Jamoma API  0.6.0.a19
win32/UdpSocket.cpp
1 /*
2  oscpack -- Open Sound Control (OSC) packet manipulation library
3  http://www.rossbencina.com/code/oscpack
4 
5  Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
6 
7  Permission is hereby granted, free of charge, to any person obtaining
8  a copy of this software and associated documentation files
9  (the "Software"), to deal in the Software without restriction,
10  including without limitation the rights to use, copy, modify, merge,
11  publish, distribute, sublicense, and/or sell copies of the Software,
12  and to permit persons to whom the Software is furnished to do so,
13  subject to the following conditions:
14 
15  The above copyright notice and this permission notice shall be
16  included in all copies or substantial portions of the Software.
17 
18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
22  ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23  CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26 
27 /*
28  The text above constitutes the entire oscpack license; however,
29  the oscpack developer(s) also make the following non-binding requests:
30 
31  Any person wishing to distribute modifications to the Software is
32  requested to send the modifications to the original developer so that
33  they can be incorporated into the canonical version. It is also
34  requested that these non-binding requests be included whenever the
35  above license is reproduced.
36 */
37 
38 #include <winsock2.h> // this must come first to prevent errors with MSVC7
39 #include <windows.h>
40 #include <mmsystem.h> // for timeGetTime()
41 
42 #ifndef WINCE
43 #include <signal.h>
44 #endif
45 
46 #include <algorithm>
47 #include <cassert>
48 #include <cstring> // for memset
49 #include <stdexcept>
50 #include <vector>
51 
52 #include "UdpSocket.h" // usually I'd include the module header first
53  // but this is causing conflicts with BCB4 due to
54  // std::size_t usage.
55 
56 #include "NetworkingUtils.h"
57 #include "PacketListener.h"
58 #include "TimerListener.h"
59 
60 
61 typedef int socklen_t;
62 
63 
64 static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint )
65 {
66  std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
67  sockAddr.sin_family = AF_INET;
68 
69  sockAddr.sin_addr.s_addr =
70  (endpoint.address == IpEndpointName::ANY_ADDRESS)
71  ? INADDR_ANY
72  : htonl( endpoint.address );
73 
74  sockAddr.sin_port =
75  (endpoint.port == IpEndpointName::ANY_PORT)
76  ? (short)0
77  : htons( (short)endpoint.port );
78 }
79 
80 
81 static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr )
82 {
83  return IpEndpointName(
84  (sockAddr.sin_addr.s_addr == INADDR_ANY)
85  ? IpEndpointName::ANY_ADDRESS
86  : ntohl( sockAddr.sin_addr.s_addr ),
87  (sockAddr.sin_port == 0)
88  ? IpEndpointName::ANY_PORT
89  : ntohs( sockAddr.sin_port )
90  );
91 }
92 
93 
94 class UdpSocket::Implementation{
95  NetworkInitializer networkInitializer_;
96 
97  bool isBound_;
98  bool isConnected_;
99 
100  SOCKET socket_;
101  struct sockaddr_in connectedAddr_;
102  struct sockaddr_in sendToAddr_;
103 
104 public:
105 
106  Implementation()
107  : isBound_( false )
108  , isConnected_( false )
109  , socket_( INVALID_SOCKET )
110  {
111  if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == INVALID_SOCKET ){
112  throw std::runtime_error("unable to create udp socket\n");
113  }
114 
115  std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) );
116  sendToAddr_.sin_family = AF_INET;
117  }
118 
119  ~Implementation()
120  {
121  if (socket_ != INVALID_SOCKET) closesocket(socket_);
122  }
123 
124  void SetEnableBroadcast( bool enableBroadcast )
125  {
126  char broadcast = (char)((enableBroadcast) ? 1 : 0); // char on win32
127  setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
128  }
129 
130  void SetAllowReuse( bool allowReuse )
131  {
132  // Note: SO_REUSEADDR is non-deterministic for listening sockets on Win32. See MSDN article:
133  // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
134  // http://msdn.microsoft.com/en-us/library/ms740621%28VS.85%29.aspx
135 
136  char reuseAddr = (char)((allowReuse) ? 1 : 0); // char on win32
137  setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr));
138  }
139 
140  IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
141  {
142  assert( isBound_ );
143 
144  // first connect the socket to the remote server
145 
146  struct sockaddr_in connectSockAddr;
147  SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint );
148 
149  if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) {
150  throw std::runtime_error("unable to connect udp socket\n");
151  }
152 
153  // get the address
154 
155  struct sockaddr_in sockAddr;
156  std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
157  socklen_t length = sizeof(sockAddr);
158  if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) {
159  throw std::runtime_error("unable to getsockname\n");
160  }
161 
162  if( isConnected_ ){
163  // reconnect to the connected address
164 
165  if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
166  throw std::runtime_error("unable to connect udp socket\n");
167  }
168 
169  }else{
170  // unconnect from the remote address
171 
172  struct sockaddr_in unconnectSockAddr;
173  SockaddrFromIpEndpointName( unconnectSockAddr, IpEndpointName() );
174 
175  if( connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr)) < 0
176  && WSAGetLastError() != WSAEADDRNOTAVAIL ){
177  throw std::runtime_error("unable to un-connect udp socket\n");
178  }
179  }
180 
181  return IpEndpointNameFromSockaddr( sockAddr );
182  }
183 
184  void Connect( const IpEndpointName& remoteEndpoint )
185  {
186  SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint );
187 
188  if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
189  throw std::runtime_error("unable to connect udp socket\n");
190  }
191 
192  isConnected_ = true;
193  }
194 
195  void Send( const char *data, std::size_t size )
196  {
197  assert( isConnected_ );
198 
199  send( socket_, data, (int)size, 0 );
200  }
201 
202  void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size )
203  {
204  sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address );
205  sendToAddr_.sin_port = htons( (short)remoteEndpoint.port );
206 
207  sendto( socket_, data, (int)size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) );
208  }
209 
210  void Bind( const IpEndpointName& localEndpoint )
211  {
212  struct sockaddr_in bindSockAddr;
213  SockaddrFromIpEndpointName( bindSockAddr, localEndpoint );
214 
215  if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) {
216  throw std::runtime_error("unable to bind udp socket\n");
217  }
218 
219  isBound_ = true;
220  }
221 
222  bool IsBound() const { return isBound_; }
223 
224  std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size )
225  {
226  assert( isBound_ );
227 
228  struct sockaddr_in fromAddr;
229  socklen_t fromAddrLen = sizeof(fromAddr);
230 
231  int result = recvfrom(socket_, data, (int)size, 0,
232  (struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen);
233  if( result < 0 )
234  return 0;
235 
236  remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr);
237  remoteEndpoint.port = ntohs(fromAddr.sin_port);
238 
239  return result;
240  }
241 
242  SOCKET& Socket() { return socket_; }
243 };
244 
245 UdpSocket::UdpSocket()
246 {
247  impl_ = new Implementation();
248 }
249 
250 UdpSocket::~UdpSocket()
251 {
252  delete impl_;
253 }
254 
255 void UdpSocket::SetEnableBroadcast( bool enableBroadcast )
256 {
257  impl_->SetEnableBroadcast( enableBroadcast );
258 }
259 
260 void UdpSocket::SetAllowReuse( bool allowReuse )
261 {
262  impl_->SetAllowReuse( allowReuse );
263 }
264 
265 IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
266 {
267  return impl_->LocalEndpointFor( remoteEndpoint );
268 }
269 
270 void UdpSocket::Connect( const IpEndpointName& remoteEndpoint )
271 {
272  impl_->Connect( remoteEndpoint );
273 }
274 
275 void UdpSocket::Send( const char *data, std::size_t size )
276 {
277  impl_->Send( data, size );
278 }
279 
280 void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size )
281 {
282  impl_->SendTo( remoteEndpoint, data, size );
283 }
284 
285 void UdpSocket::Bind( const IpEndpointName& localEndpoint )
286 {
287  impl_->Bind( localEndpoint );
288 }
289 
290 bool UdpSocket::IsBound() const
291 {
292  return impl_->IsBound();
293 }
294 
295 std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size )
296 {
297  return impl_->ReceiveFrom( remoteEndpoint, data, size );
298 }
299 
300 
301 struct AttachedTimerListener{
302  AttachedTimerListener( int id, int p, TimerListener *tl )
303  : initialDelayMs( id )
304  , periodMs( p )
305  , listener( tl ) {}
306  int initialDelayMs;
307  int periodMs;
308  TimerListener *listener;
309 };
310 
311 
312 static bool CompareScheduledTimerCalls(
313  const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs )
314 {
315  return lhs.first < rhs.first;
316 }
317 
318 
319 SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0;
320 
321 extern "C" /*static*/ void InterruptSignalHandler( int );
322 /*static*/ void InterruptSignalHandler( int )
323 {
324  multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak();
325 #ifndef WINCE
326  signal( SIGINT, SIG_DFL );
327 #endif
328 }
329 
330 
331 class SocketReceiveMultiplexer::Implementation{
332  NetworkInitializer networkInitializer_;
333 
334  std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_;
335  std::vector< AttachedTimerListener > timerListeners_;
336 
337  volatile bool break_;
338  HANDLE breakEvent_;
339 
340  double GetCurrentTimeMs() const
341  {
342 #ifndef WINCE
343  return timeGetTime(); // FIXME: bad choice if you want to run for more than 40 days
344 #else
345  return 0;
346 #endif
347  }
348 
349 public:
350  Implementation()
351  {
352  breakEvent_ = CreateEvent( NULL, FALSE, FALSE, NULL );
353  }
354 
355  ~Implementation()
356  {
357  CloseHandle( breakEvent_ );
358  }
359 
360  void AttachSocketListener( UdpSocket *socket, PacketListener *listener )
361  {
362  assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() );
363  // we don't check that the same socket has been added multiple times, even though this is an error
364  socketListeners_.push_back( std::make_pair( listener, socket ) );
365  }
366 
367  void DetachSocketListener( UdpSocket *socket, PacketListener *listener )
368  {
369  std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i =
370  std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) );
371  assert( i != socketListeners_.end() );
372 
373  socketListeners_.erase( i );
374  }
375 
376  void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
377  {
378  timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) );
379  }
380 
381  void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
382  {
383  timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) );
384  }
385 
386  void DetachPeriodicTimerListener( TimerListener *listener )
387  {
388  std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
389  while( i != timerListeners_.end() ){
390  if( i->listener == listener )
391  break;
392  ++i;
393  }
394 
395  assert( i != timerListeners_.end() );
396 
397  timerListeners_.erase( i );
398  }
399 
400  void Run()
401  {
402  break_ = false;
403 
404  // prepare the window events which we use to wake up on incoming data
405  // we use this instead of select() primarily to support the AsyncBreak()
406  // mechanism.
407 
408  std::vector<HANDLE> events( socketListeners_.size() + 1, 0 );
409  int j=0;
410  for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
411  i != socketListeners_.end(); ++i, ++j ){
412 
413  HANDLE event = CreateEvent( NULL, FALSE, FALSE, NULL );
414  WSAEventSelect( i->second->impl_->Socket(), event, FD_READ ); // note that this makes the socket non-blocking which is why we can safely call RecieveFrom() on all sockets below
415  events[j] = event;
416  }
417 
418 
419  events[ socketListeners_.size() ] = breakEvent_; // last event in the collection is the break event
420 
421 
422  // configure the timer queue
423  double currentTimeMs = GetCurrentTimeMs();
424 
425  // expiry time ms, listener
426  std::vector< std::pair< double, AttachedTimerListener > > timerQueue_;
427  for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
428  i != timerListeners_.end(); ++i )
429  timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) );
430  std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
431 
432  const int MAX_BUFFER_SIZE = 4098;
433  char *data = new char[ MAX_BUFFER_SIZE ];
434  IpEndpointName remoteEndpoint;
435 
436  while( !break_ ){
437 
438  double currentTimeMs = GetCurrentTimeMs();
439 
440  DWORD waitTime = INFINITE;
441  if( !timerQueue_.empty() ){
442 
443  waitTime = (DWORD)( timerQueue_.front().first >= currentTimeMs
444  ? timerQueue_.front().first - currentTimeMs
445  : 0 );
446  }
447 
448  DWORD waitResult = WaitForMultipleObjects( (DWORD)socketListeners_.size() + 1, &events[0], FALSE, waitTime );
449  if( break_ )
450  break;
451 
452  if( waitResult != WAIT_TIMEOUT ){
453  for( int i = waitResult - WAIT_OBJECT_0; i < (int)socketListeners_.size(); ++i ){
454  std::size_t size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE );
455  if( size > 0 ){
456  socketListeners_[i].first->ProcessPacket( data, (int)size, remoteEndpoint );
457  if( break_ )
458  break;
459  }
460  }
461  }
462 
463  // execute any expired timers
464  currentTimeMs = GetCurrentTimeMs();
465  bool resort = false;
466  for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin();
467  i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){
468 
469  i->second.listener->TimerExpired();
470  if( break_ )
471  break;
472 
473  i->first += i->second.periodMs;
474  resort = true;
475  }
476  if( resort )
477  std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
478  }
479 
480  delete [] data;
481 
482  // free events
483  j = 0;
484  for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
485  i != socketListeners_.end(); ++i, ++j ){
486 
487  WSAEventSelect( i->second->impl_->Socket(), events[j], 0 ); // remove association between socket and event
488  CloseHandle( events[j] );
489  unsigned long enableNonblocking = 0;
490  ioctlsocket( i->second->impl_->Socket(), FIONBIO, &enableNonblocking ); // make the socket blocking again
491  }
492  }
493 
494  void Break()
495  {
496  break_ = true;
497  }
498 
499  void AsynchronousBreak()
500  {
501  break_ = true;
502  SetEvent( breakEvent_ );
503  }
504 };
505 
506 
507 
508 SocketReceiveMultiplexer::SocketReceiveMultiplexer()
509 {
510  impl_ = new Implementation();
511 }
512 
513 SocketReceiveMultiplexer::~SocketReceiveMultiplexer()
514 {
515  delete impl_;
516 }
517 
518 void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener )
519 {
520  impl_->AttachSocketListener( socket, listener );
521 }
522 
523 void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener )
524 {
525  impl_->DetachSocketListener( socket, listener );
526 }
527 
528 void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
529 {
530  impl_->AttachPeriodicTimerListener( periodMilliseconds, listener );
531 }
532 
533 void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
534 {
535  impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener );
536 }
537 
538 void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener )
539 {
540  impl_->DetachPeriodicTimerListener( listener );
541 }
542 
543 void SocketReceiveMultiplexer::Run()
544 {
545  impl_->Run();
546 }
547 
548 void SocketReceiveMultiplexer::RunUntilSigInt()
549 {
550  assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */
551  multiplexerInstanceToAbortWithSigInt_ = this;
552 #ifndef WINCE
553  signal( SIGINT, InterruptSignalHandler );
554 #endif
555  impl_->Run();
556 #ifndef WINCE
557  signal( SIGINT, SIG_DFL );
558 #endif
559  multiplexerInstanceToAbortWithSigInt_ = 0;
560 }
561 
562 void SocketReceiveMultiplexer::Break()
563 {
564  impl_->Break();
565 }
566 
567 void SocketReceiveMultiplexer::AsynchronousBreak()
568 {
569  impl_->AsynchronousBreak();
570 }
571