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 "ip/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 "ip/NetworkingUtils.h"
57 #include "ip/PacketListener.h"
58 #include "ip/TimerListener.h"
59
60
61 typedef int socklen_t;
62
63
SockaddrFromIpEndpointName(struct sockaddr_in & sockAddr,const IpEndpointName & endpoint)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
IpEndpointNameFromSockaddr(const struct sockaddr_in & sockAddr)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
Implementation()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
~Implementation()119 ~Implementation()
120 {
121 if (socket_ != INVALID_SOCKET) closesocket(socket_);
122 }
123
SetEnableBroadcast(bool enableBroadcast)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
SetAllowReuse(bool allowReuse)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
LocalEndpointFor(const IpEndpointName & remoteEndpoint) const140 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
Connect(const IpEndpointName & remoteEndpoint)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
Send(const char * data,std::size_t size)195 void Send( const char *data, std::size_t size )
196 {
197 assert( isConnected_ );
198
199 send( socket_, data, (int)size, 0 );
200 }
201
SendTo(const IpEndpointName & remoteEndpoint,const char * data,std::size_t size)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
Bind(const IpEndpointName & localEndpoint)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
IsBound() const222 bool IsBound() const { return isBound_; }
223
ReceiveFrom(IpEndpointName & remoteEndpoint,char * data,std::size_t size)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
Socket()242 SOCKET& Socket() { return socket_; }
243 };
244
UdpSocket()245 UdpSocket::UdpSocket()
246 {
247 impl_ = new Implementation();
248 }
249
~UdpSocket()250 UdpSocket::~UdpSocket()
251 {
252 delete impl_;
253 }
254
SetEnableBroadcast(bool enableBroadcast)255 void UdpSocket::SetEnableBroadcast( bool enableBroadcast )
256 {
257 impl_->SetEnableBroadcast( enableBroadcast );
258 }
259
SetAllowReuse(bool allowReuse)260 void UdpSocket::SetAllowReuse( bool allowReuse )
261 {
262 impl_->SetAllowReuse( allowReuse );
263 }
264
LocalEndpointFor(const IpEndpointName & remoteEndpoint) const265 IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
266 {
267 return impl_->LocalEndpointFor( remoteEndpoint );
268 }
269
Connect(const IpEndpointName & remoteEndpoint)270 void UdpSocket::Connect( const IpEndpointName& remoteEndpoint )
271 {
272 impl_->Connect( remoteEndpoint );
273 }
274
Send(const char * data,std::size_t size)275 void UdpSocket::Send( const char *data, std::size_t size )
276 {
277 impl_->Send( data, size );
278 }
279
SendTo(const IpEndpointName & remoteEndpoint,const char * data,std::size_t size)280 void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size )
281 {
282 impl_->SendTo( remoteEndpoint, data, size );
283 }
284
Bind(const IpEndpointName & localEndpoint)285 void UdpSocket::Bind( const IpEndpointName& localEndpoint )
286 {
287 impl_->Bind( localEndpoint );
288 }
289
IsBound() const290 bool UdpSocket::IsBound() const
291 {
292 return impl_->IsBound();
293 }
294
ReceiveFrom(IpEndpointName & remoteEndpoint,char * data,std::size_t size)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{
AttachedTimerListenerAttachedTimerListener302 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
CompareScheduledTimerCalls(const std::pair<double,AttachedTimerListener> & lhs,const std::pair<double,AttachedTimerListener> & rhs)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 );
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
GetCurrentTimeMs() const340 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:
Implementation()350 Implementation()
351 {
352 breakEvent_ = CreateEvent( NULL, FALSE, FALSE, NULL );
353 }
354
~Implementation()355 ~Implementation()
356 {
357 CloseHandle( breakEvent_ );
358 }
359
AttachSocketListener(UdpSocket * socket,PacketListener * listener)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
DetachSocketListener(UdpSocket * socket,PacketListener * listener)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
AttachPeriodicTimerListener(int periodMilliseconds,TimerListener * listener)376 void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
377 {
378 timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) );
379 }
380
AttachPeriodicTimerListener(int initialDelayMilliseconds,int periodMilliseconds,TimerListener * listener)381 void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
382 {
383 timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) );
384 }
385
DetachPeriodicTimerListener(TimerListener * listener)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
Run()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
Break()494 void Break()
495 {
496 break_ = true;
497 }
498
AsynchronousBreak()499 void AsynchronousBreak()
500 {
501 break_ = true;
502 SetEvent( breakEvent_ );
503 }
504 };
505
506
507
SocketReceiveMultiplexer()508 SocketReceiveMultiplexer::SocketReceiveMultiplexer()
509 {
510 impl_ = new Implementation();
511 }
512
~SocketReceiveMultiplexer()513 SocketReceiveMultiplexer::~SocketReceiveMultiplexer()
514 {
515 delete impl_;
516 }
517
AttachSocketListener(UdpSocket * socket,PacketListener * listener)518 void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener )
519 {
520 impl_->AttachSocketListener( socket, listener );
521 }
522
DetachSocketListener(UdpSocket * socket,PacketListener * listener)523 void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener )
524 {
525 impl_->DetachSocketListener( socket, listener );
526 }
527
AttachPeriodicTimerListener(int periodMilliseconds,TimerListener * listener)528 void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
529 {
530 impl_->AttachPeriodicTimerListener( periodMilliseconds, listener );
531 }
532
AttachPeriodicTimerListener(int initialDelayMilliseconds,int periodMilliseconds,TimerListener * listener)533 void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
534 {
535 impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener );
536 }
537
DetachPeriodicTimerListener(TimerListener * listener)538 void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener )
539 {
540 impl_->DetachPeriodicTimerListener( listener );
541 }
542
Run()543 void SocketReceiveMultiplexer::Run()
544 {
545 impl_->Run();
546 }
547
RunUntilSigInt()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
Break()562 void SocketReceiveMultiplexer::Break()
563 {
564 impl_->Break();
565 }
566
AsynchronousBreak()567 void SocketReceiveMultiplexer::AsynchronousBreak()
568 {
569 impl_->AsynchronousBreak();
570 }
571
572