annotate external/oscpack/ip/win32/UdpSocket.cpp @ 509:0284d2152e17

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