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