cmake: supernova - missing include_directories() for Jack
[supercollider.git] / external_libraries / oscpack / ip / win32 / UdpSocket.cpp
blob5e8e94f8e65f085f66e369de68a2497546e2fcb2
1 /*
2 oscpack -- Open Sound Control packet manipulation library
3 http://www.audiomulch.com/~rossb/oscpack
5 Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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:
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
18 Any person wishing to distribute modifications to the Software is
19 requested to send the modifications to the original developer so that
20 they can be incorporated into the canonical version.
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include "ip/UdpSocket.h"
32 #include <winsock2.h> // this must come first to prevent errors with MSVC7
33 #include <windows.h>
34 #include <mmsystem.h> // for timeGetTime()
36 #include <vector>
37 #include <algorithm>
38 #include <stdexcept>
39 #include <assert.h>
41 #ifndef WINCE
42 #include <signal.h>
43 #endif
45 #include "ip/NetworkingUtils.h"
46 #include "ip/PacketListener.h"
47 #include "ip/TimerListener.h"
50 typedef int socklen_t;
53 static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint )
55 memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
56 sockAddr.sin_family = AF_INET;
58 sockAddr.sin_addr.s_addr =
59 (endpoint.address == IpEndpointName::ANY_ADDRESS)
60 ? INADDR_ANY
61 : htonl( endpoint.address );
63 sockAddr.sin_port =
64 (endpoint.port == IpEndpointName::ANY_PORT)
65 ? (short)0
66 : htons( (short)endpoint.port );
70 static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr )
72 return IpEndpointName(
73 (sockAddr.sin_addr.s_addr == INADDR_ANY)
74 ? IpEndpointName::ANY_ADDRESS
75 : ntohl( sockAddr.sin_addr.s_addr ),
76 (sockAddr.sin_port == 0)
77 ? IpEndpointName::ANY_PORT
78 : ntohs( sockAddr.sin_port )
83 class UdpSocket::Implementation{
84 NetworkInitializer networkInitializer_;
86 bool isBound_;
87 bool isConnected_;
89 SOCKET socket_;
90 struct sockaddr_in connectedAddr_;
91 struct sockaddr_in sendToAddr_;
93 public:
95 Implementation()
96 : isBound_( false )
97 , isConnected_( false )
98 , socket_( INVALID_SOCKET )
100 if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == INVALID_SOCKET ){
101 throw std::runtime_error("unable to create udp socket\n");
104 memset( &sendToAddr_, 0, sizeof(sendToAddr_) );
105 sendToAddr_.sin_family = AF_INET;
108 ~Implementation()
110 if (socket_ != INVALID_SOCKET) closesocket(socket_);
113 IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
115 assert( isBound_ );
117 // first connect the socket to the remote server
119 struct sockaddr_in connectSockAddr;
120 SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint );
122 if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) {
123 throw std::runtime_error("unable to connect udp socket\n");
126 // get the address
128 struct sockaddr_in sockAddr;
129 memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
130 socklen_t length = sizeof(sockAddr);
131 if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) {
132 throw std::runtime_error("unable to getsockname\n");
135 if( isConnected_ ){
136 // reconnect to the connected address
138 if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
139 throw std::runtime_error("unable to connect udp socket\n");
142 }else{
143 // unconnect from the remote address
145 struct sockaddr_in unconnectSockAddr;
146 SockaddrFromIpEndpointName( unconnectSockAddr, IpEndpointName() );
148 if( connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr)) < 0
149 && WSAGetLastError() != WSAEADDRNOTAVAIL ){
150 throw std::runtime_error("unable to un-connect udp socket\n");
154 return IpEndpointNameFromSockaddr( sockAddr );
157 void Connect( const IpEndpointName& remoteEndpoint )
159 SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint );
161 if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
162 throw std::runtime_error("unable to connect udp socket\n");
165 isConnected_ = true;
168 void Send( const char *data, int size )
170 assert( isConnected_ );
172 send( socket_, data, size, 0 );
175 void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size )
177 sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address );
178 sendToAddr_.sin_port = htons( (short)remoteEndpoint.port );
180 sendto( socket_, data, size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) );
183 void Bind( const IpEndpointName& localEndpoint )
185 struct sockaddr_in bindSockAddr;
186 SockaddrFromIpEndpointName( bindSockAddr, localEndpoint );
188 if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) {
189 throw std::runtime_error("unable to bind udp socket\n");
192 isBound_ = true;
195 bool IsBound() const { return isBound_; }
197 int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size )
199 assert( isBound_ );
201 struct sockaddr_in fromAddr;
202 socklen_t fromAddrLen = sizeof(fromAddr);
204 int result = recvfrom(socket_, data, size, 0,
205 (struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen);
206 if( result < 0 )
207 return 0;
209 remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr);
210 remoteEndpoint.port = ntohs(fromAddr.sin_port);
212 return result;
215 SOCKET& Socket() { return socket_; }
218 UdpSocket::UdpSocket()
220 impl_ = new Implementation();
223 UdpSocket::~UdpSocket()
225 delete impl_;
228 IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
230 return impl_->LocalEndpointFor( remoteEndpoint );
233 void UdpSocket::Connect( const IpEndpointName& remoteEndpoint )
235 impl_->Connect( remoteEndpoint );
238 void UdpSocket::Send( const char *data, int size )
240 impl_->Send( data, size );
243 void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size )
245 impl_->SendTo( remoteEndpoint, data, size );
248 void UdpSocket::Bind( const IpEndpointName& localEndpoint )
250 impl_->Bind( localEndpoint );
253 bool UdpSocket::IsBound() const
255 return impl_->IsBound();
258 int UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size )
260 return impl_->ReceiveFrom( remoteEndpoint, data, size );
264 struct AttachedTimerListener{
265 AttachedTimerListener( int id, int p, TimerListener *tl )
266 : initialDelayMs( id )
267 , periodMs( p )
268 , listener( tl ) {}
269 int initialDelayMs;
270 int periodMs;
271 TimerListener *listener;
275 static bool CompareScheduledTimerCalls(
276 const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs )
278 return lhs.first < rhs.first;
282 SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0;
284 extern "C" /*static*/ void InterruptSignalHandler( int );
285 /*static*/ void InterruptSignalHandler( int )
287 multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak();
288 #ifndef WINCE
289 signal( SIGINT, SIG_DFL );
290 #endif
294 class SocketReceiveMultiplexer::Implementation{
295 NetworkInitializer networkInitializer_;
297 std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_;
298 std::vector< AttachedTimerListener > timerListeners_;
300 volatile bool break_;
301 HANDLE breakEvent_;
303 double GetCurrentTimeMs() const
305 #ifndef WINCE
306 return timeGetTime(); // FIXME: bad choice if you want to run for more than 40 days
307 #else
308 return 0;
309 #endif
312 public:
313 Implementation()
315 breakEvent_ = CreateEvent( NULL, FALSE, FALSE, NULL );
318 ~Implementation()
320 CloseHandle( breakEvent_ );
323 void AttachSocketListener( UdpSocket *socket, PacketListener *listener )
325 assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() );
326 // we don't check that the same socket has been added multiple times, even though this is an error
327 socketListeners_.push_back( std::make_pair( listener, socket ) );
330 void DetachSocketListener( UdpSocket *socket, PacketListener *listener )
332 std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i =
333 std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) );
334 assert( i != socketListeners_.end() );
336 socketListeners_.erase( i );
339 void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
341 timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) );
344 void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
346 timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) );
349 void DetachPeriodicTimerListener( TimerListener *listener )
351 std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
352 while( i != timerListeners_.end() ){
353 if( i->listener == listener )
354 break;
355 ++i;
358 assert( i != timerListeners_.end() );
360 timerListeners_.erase( i );
363 void Run()
365 break_ = false;
367 // prepare the window events which we use to wake up on incoming data
368 // we use this instead of select() primarily to support the AsyncBreak()
369 // mechanism.
371 std::vector<HANDLE> events( socketListeners_.size() + 1, 0 );
372 int j=0;
373 for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
374 i != socketListeners_.end(); ++i, ++j ){
376 HANDLE event = CreateEvent( NULL, FALSE, FALSE, NULL );
377 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
378 events[j] = event;
382 events[ socketListeners_.size() ] = breakEvent_; // last event in the collection is the break event
385 // configure the timer queue
386 double currentTimeMs = GetCurrentTimeMs();
388 // expiry time ms, listener
389 std::vector< std::pair< double, AttachedTimerListener > > timerQueue_;
390 for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
391 i != timerListeners_.end(); ++i )
392 timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) );
393 std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
395 const int MAX_BUFFER_SIZE = 4098;
396 char *data = new char[ MAX_BUFFER_SIZE ];
397 IpEndpointName remoteEndpoint;
399 while( !break_ ){
401 double currentTimeMs = GetCurrentTimeMs();
403 DWORD waitTime = INFINITE;
404 if( !timerQueue_.empty() ){
406 waitTime = (DWORD)( timerQueue_.front().first >= currentTimeMs
407 ? timerQueue_.front().first - currentTimeMs
408 : 0 );
411 DWORD waitResult = WaitForMultipleObjects( (DWORD)socketListeners_.size() + 1, &events[0], FALSE, waitTime );
412 if( break_ )
413 break;
415 if( waitResult != WAIT_TIMEOUT ){
416 for( int i = waitResult - WAIT_OBJECT_0; i < (int)socketListeners_.size(); ++i ){
417 int size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE );
418 if( size > 0 ){
419 socketListeners_[i].first->ProcessPacket( data, size, remoteEndpoint );
420 if( break_ )
421 break;
426 // execute any expired timers
427 currentTimeMs = GetCurrentTimeMs();
428 bool resort = false;
429 for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin();
430 i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){
432 i->second.listener->TimerExpired();
433 if( break_ )
434 break;
436 i->first += i->second.periodMs;
437 resort = true;
439 if( resort )
440 std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
443 delete [] data;
445 // free events
446 j = 0;
447 for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
448 i != socketListeners_.end(); ++i, ++j ){
450 WSAEventSelect( i->second->impl_->Socket(), events[j], 0 ); // remove association between socket and event
451 CloseHandle( events[j] );
452 unsigned long enableNonblocking = 0;
453 ioctlsocket( i->second->impl_->Socket(), FIONBIO, &enableNonblocking ); // make the socket blocking again
457 void Break()
459 break_ = true;
462 void AsynchronousBreak()
464 break_ = true;
465 SetEvent( breakEvent_ );
471 SocketReceiveMultiplexer::SocketReceiveMultiplexer()
473 impl_ = new Implementation();
476 SocketReceiveMultiplexer::~SocketReceiveMultiplexer()
478 delete impl_;
481 void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener )
483 impl_->AttachSocketListener( socket, listener );
486 void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener )
488 impl_->DetachSocketListener( socket, listener );
491 void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
493 impl_->AttachPeriodicTimerListener( periodMilliseconds, listener );
496 void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
498 impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener );
501 void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener )
503 impl_->DetachPeriodicTimerListener( listener );
506 void SocketReceiveMultiplexer::Run()
508 impl_->Run();
511 void SocketReceiveMultiplexer::RunUntilSigInt()
513 assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */
514 multiplexerInstanceToAbortWithSigInt_ = this;
515 #ifndef WINCE
516 signal( SIGINT, InterruptSignalHandler );
517 #endif
518 impl_->Run();
519 #ifndef WINCE
520 signal( SIGINT, SIG_DFL );
521 #endif
522 multiplexerInstanceToAbortWithSigInt_ = 0;
525 void SocketReceiveMultiplexer::Break()
527 impl_->Break();
530 void SocketReceiveMultiplexer::AsynchronousBreak()
532 impl_->AsynchronousBreak();