<rdar://problem/7179778> Remove tcp connect thread by integrating tcp connect event...
authorsherscher@apple.com <sherscher@apple.com@214c2c4a-bf3b-4dcf-9390-e4dd3010487d>
Wed, 9 Sep 2009 22:52:03 +0000 (22:52 +0000)
committersherscher@apple.com <sherscher@apple.com@214c2c4a-bf3b-4dcf-9390-e4dd3010487d>
Wed, 9 Sep 2009 22:52:03 +0000 (22:52 +0000)
git-svn-id: http://svn.macosforge.org/repository/mDNSResponder/trunk@6657 214c2c4a-bf3b-4dcf-9390-e4dd3010487d

mDNSWindows/SystemService/Service.c
mDNSWindows/mDNSWin32.c
mDNSWindows/mDNSWin32.h

index 63326ea..70d2980 100644 (file)
@@ -62,7 +62,7 @@
 //     Constants
 //===========================================================================================================================
 
-#define        DEBUG_NAME                                                      "[Server] "
+#define        DEBUG_NAME                                                      "[mDNSWin32] "
 #define kServiceFirewallName                           L"Bonjour"
 #define        kServiceDependencies                            TEXT("Tcpip\0\0")
 #define        kDNSServiceCacheEntryCountDefault       512
@@ -83,19 +83,15 @@ static CacheEntity gRRCache[RR_CACHE_SIZE];
 
 typedef struct EventSource
 {
-       SOCKET                                  sock;
-       DWORD                                   lastError;
-       BOOL                                    closed;
-       void                            *       context;
-       udsEventCallback                callback;\r
-       OVERLAPPED                              overlapped;
-       WSABUF                                  wbuf;
-       uint8_t                                 buf[ 4192 ];
-       uint8_t                         *       bptr;
-       uint8_t                         *       eptr;
-       struct EventSource      *   next;
+       HANDLE                                                  event;
+       void                                            *       context;
+       RegisterWaitableEventHandler    handler;
+       struct EventSource                      *       next;
 } EventSource;
 
+static BOOL                                                                                    gEventSourceListChanged = FALSE;
+static EventSource                                                             *       gEventSourceList = NULL;
+static int                                                                                     gEventSources = 0;
 
 #define        kWaitListStopEvent                                                      ( WAIT_OBJECT_0 + 0 )
 #define        kWaitListInterfaceListChangedEvent                      ( WAIT_OBJECT_0 + 1 )
@@ -106,8 +102,7 @@ typedef struct EventSource
 #define kWaitListFirewallEvent                                         ( WAIT_OBJECT_0 + 6 )
 #define kWaitListSPSWakeupEvent                                                ( WAIT_OBJECT_0 + 7 )
 #define kWaitListSPSSleepEvent                                         ( WAIT_OBJECT_0 + 8 )
-#define kWaitListUDSEvent                                                      ( WAIT_OBJECT_0 + 9 )
-#define        kWaitListItemCount                                                      10
+#define        kWaitListFixedItemCount                                         9
 
 
 #if 0
@@ -138,12 +133,13 @@ static OSStatus           ServiceSpecificInitialize( int argc, LPTSTR  argv[] );
 static OSStatus                ServiceSpecificRun( int argc, LPTSTR argv[] );
 static OSStatus                ServiceSpecificStop( void );
 static void                    ServiceSpecificFinalize( int argc, LPTSTR argv[] );
-mDNSlocal mStatus      SetupNotifications();
-mDNSlocal mStatus      TearDownNotifications();
-mDNSlocal mStatus      BeginUDSRecv( EventSource * source );
-mDNSlocal void         EndUDSRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
-static mStatus         EventSourceFinalize( EventSource * source );
-static void                    EventSourceFree( EventSource * source );
+static mStatus         SetupNotifications();
+static mStatus         TearDownNotifications();
+static mStatus         RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler );
+static void                    UnregisterWaitableEvent( mDNS * const inMDNS, HANDLE event );
+static mStatus         SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
+static void                    UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context );
+static void                    UDSCanRead( TCPSocket * sock );
 static void                    HandlePowerSuspend( void * v );
 static void                    HandlePowerResumeSuspend( void * v );
 static void                    CoreCallback(mDNS * const inMDNS, mStatus result);
@@ -213,7 +209,6 @@ DEBUG_LOCAL HANDLE                                          gSPSSleepEvent                  = NULL;
 DEBUG_LOCAL HANDLE                                             gUDSEvent                               = NULL;
 DEBUG_LOCAL SocketRef                                  gUDSSocket                              = 0;
 DEBUG_LOCAL udsEventCallback                   gUDSCallback                    = NULL;
-DEBUG_LOCAL GenLinkedList                              gEventSources;
 DEBUG_LOCAL BOOL                                               gRetryFirewall                  = FALSE;
 DEBUG_LOCAL DWORD                                              gOSMajorVersion;
 DEBUG_LOCAL DWORD                                              gOSMinorVersion;
@@ -1180,6 +1175,9 @@ static OSStatus   ServiceSpecificInitialize( int argc, LPTSTR argv[] )
        mDNSPlatformMemZero( &gMDNSRecord, sizeof gMDNSRecord);
        mDNSPlatformMemZero( &gPlatformStorage, sizeof gPlatformStorage);
 
+       gPlatformStorage.registerWaitableEventFunc = RegisterWaitableEvent;
+       gPlatformStorage.unregisterWaitableEventFunc = UnregisterWaitableEvent;
+
        err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext); 
        require_noerr( err, exit);
 
@@ -1215,9 +1213,10 @@ exit:
 
 static OSStatus        ServiceSpecificRun( int argc, LPTSTR argv[] )
 {
+       HANDLE  *       waitList;
+       int                     waitListCount;
        DWORD           timeout;
        DWORD           result;
-       HANDLE          waitList[ kWaitListItemCount ];
        BOOL            done;
        mStatus         err;
        
@@ -1231,17 +1230,6 @@ static OSStatus  ServiceSpecificRun( int argc, LPTSTR argv[] )
 
        err = uDNS_SetupDNSConfig( &gMDNSRecord );
        check( !err );
-       
-       waitList[ 0 ] = gStopEvent;
-       waitList[ 1 ] = gInterfaceListChangedEvent;
-       waitList[ 2 ] = gDescChangedEvent;
-       waitList[ 3 ] = gTcpipChangedEvent;
-       waitList[ 4 ] = gDdnsChangedEvent;
-       waitList[ 5 ] = gFileSharingChangedEvent;
-       waitList[ 6 ] = gFirewallChangedEvent;
-       waitList[ 7 ] = gSPSWakeupEvent;
-       waitList[ 8 ] = gSPSSleepEvent;
-       waitList[ 9 ] = gUDSEvent;
 
        done = FALSE;
 
@@ -1249,170 +1237,229 @@ static OSStatus       ServiceSpecificRun( int argc, LPTSTR argv[] )
 
        while( !done )
        {
-               mDNSs32 interval;
+               waitList                = NULL;
+               waitListCount   = 0;
 
-               // Give the mDNS core a chance to do its work and determine next event time.
-               
-               interval = mDNS_Execute( &gMDNSRecord ) - mDNS_TimeNow( &gMDNSRecord );
-               interval = udsserver_idle( interval );
+               err = SetupWaitList( &gMDNSRecord, &waitList, &waitListCount );
+               require_noerr( err, exit );
 
-               if      (interval < 0)                                          interval = 0;
-               else if (interval > (0x7FFFFFFF / 1000))        interval = 0x7FFFFFFF / mDNSPlatformOneSecond;
-               else                                                                            interval = (interval * 1000) / mDNSPlatformOneSecond;
-               
-               // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
-                                       
-               result = WaitForMultipleObjectsEx( kWaitListItemCount, waitList, FALSE, (DWORD) interval, TRUE );
-               check( result != WAIT_FAILED );
+               gEventSourceListChanged = FALSE;
 
-               if ( result != WAIT_FAILED )
+               for ( ;; )
                {
-                       if( result == WAIT_TIMEOUT )
-                       {
-                               // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
-                               
-                               dlog( kDebugLevelChatty - 1, DEBUG_NAME "timeout\n" );
-                               continue;
-                       }
-                       else if ( result == kWaitListStopEvent )
+                       mDNSs32 interval;
+
+                       if ( gEventSourceListChanged )
                        {
-                               // Stop event. Set the done flag and break to exit.
-                               
-                               dlog( kDebugLevelVerbose, DEBUG_NAME "stopping...\n" );
-                               done = TRUE;
                                break;
                        }
-                       else if( result == kWaitListInterfaceListChangedEvent )
-                       {
-                               int             inBuffer;
-                               int             outBuffer;
-                               DWORD   outSize;
-
-                               // It would be nice to come up with a more elegant solution to this, but it seems that
-                               // GetAdaptersAddresses doesn't always stay in sync after network changed events.  So as
-                               // as a simple workaround, we'll pause for a couple of seconds before processing the change.
-
-                               // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
-                               // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec.  We added another
-                               // second on top of that to account for machine load or some other exigency.
 
-                               Sleep( 2000 );
+                       // Give the mDNS core a chance to do its work and determine next event time.
+                       
+                       interval = mDNS_Execute( &gMDNSRecord ) - mDNS_TimeNow( &gMDNSRecord );
+                       interval = udsserver_idle( interval );
 
-                               // Interface list changed event. Break out of the inner loop to re-setup the wait list.
-                               
-                               InterfaceListDidChange( &gMDNSRecord );
+                       if      (interval < 0)                                          interval = 0;
+                       else if (interval > (0x7FFFFFFF / 1000))        interval = 0x7FFFFFFF / mDNSPlatformOneSecond;
+                       else                                                                            interval = (interval * 1000) / mDNSPlatformOneSecond;
+                       
+                       // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
+                                               
+                       result = WaitForMultipleObjectsEx( ( DWORD ) waitListCount, waitList, FALSE, (DWORD) interval, TRUE );
+                       check( result != WAIT_FAILED );
 
-                               // reset the event handler
-                               inBuffer        = 0;
-                               outBuffer       = 0;
-                               err = WSAIoctl( gInterfaceListChangedSocket, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
-                               if( err < 0 )
+                       if ( result != WAIT_FAILED )
+                       {
+                               if ( result == WAIT_TIMEOUT )
                                {
-                                       check( errno_compat() == WSAEWOULDBLOCK );
+                                       // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
+                                       
+                                       dlog( kDebugLevelChatty - 1, DEBUG_NAME "timeout\n" );
+                                       continue;
                                }
-                       }
-                       else if ( result == kWaitListComputerDescriptionEvent )
-                       {
-                               // The computer description might have changed
-                               
-                               ComputerDescriptionDidChange( &gMDNSRecord );
-
-                               udsserver_handle_configchange( &gMDNSRecord );
-
-                               // and reset the event handler
-                               if ( ( gDescKey != NULL ) && ( gDescChangedEvent != NULL ) )
+                               else if ( result == WAIT_IO_COMPLETION )
                                {
-                                       err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
-                                       check_noerr( err );
+                                       dlog( kDebugLevelChatty - 1, DEBUG_NAME "i/o completion\n" );
+                                       continue;
                                }
-                       }
-                       else if ( result == kWaitListTCPIPEvent )
-                       {       
-                               // The TCP/IP might have changed
+                               else if ( result == kWaitListStopEvent )
+                               {
+                                       // Stop event. Set the done flag and break to exit.
+                                       
+                                       dlog( kDebugLevelVerbose, DEBUG_NAME "stopping...\n" );
+                                       done = TRUE;
+                                       break;
+                               }
+                               else if( result == kWaitListInterfaceListChangedEvent )
+                               {
+                                       int             inBuffer;
+                                       int             outBuffer;
+                                       DWORD   outSize;
 
-                               TCPIPConfigDidChange( &gMDNSRecord );
+                                       // It would be nice to come up with a more elegant solution to this, but it seems that
+                                       // GetAdaptersAddresses doesn't always stay in sync after network changed events.  So as
+                                       // as a simple workaround, we'll pause for a couple of seconds before processing the change.
 
-                               // and reset the event handler
+                                       // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
+                                       // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec.  We added another
+                                       // second on top of that to account for machine load or some other exigency.
 
-                               if ( ( gTcpipKey != NULL ) && ( gTcpipChangedEvent ) )
+                                       Sleep( 2000 );
+
+                                       // Interface list changed event. Break out of the inner loop to re-setup the wait list.
+                                       
+                                       InterfaceListDidChange( &gMDNSRecord );
+
+                                       // reset the event handler
+                                       inBuffer        = 0;
+                                       outBuffer       = 0;
+                                       err = WSAIoctl( gInterfaceListChangedSocket, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
+                                       if( err < 0 )
+                                       {
+                                               check( errno_compat() == WSAEWOULDBLOCK );
+                                       }
+                               }
+                               else if ( result == kWaitListComputerDescriptionEvent )
                                {
-                                       err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE );
-                                       check_noerr( err );
+                                       // The computer description might have changed
+                                       
+                                       ComputerDescriptionDidChange( &gMDNSRecord );
+
+                                       udsserver_handle_configchange( &gMDNSRecord );
+
+                                       // and reset the event handler
+                                       if ( ( gDescKey != NULL ) && ( gDescChangedEvent != NULL ) )
+                                       {
+                                               err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
+                                               check_noerr( err );
+                                       }
                                }
-                       }
-                       else if ( result == kWaitListDynDNSEvent )
-                       {
-                               // The DynDNS config might have changed
+                               else if ( result == kWaitListTCPIPEvent )
+                               {       
+                                       // The TCP/IP might have changed
 
-                               DynDNSConfigDidChange( &gMDNSRecord );
+                                       TCPIPConfigDidChange( &gMDNSRecord );
 
-                               // and reset the event handler
+                                       // and reset the event handler
 
-                               if ((gDdnsKey != NULL) && (gDdnsChangedEvent))
-                               {
-                                       err = RegNotifyChangeKeyValue(gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
-                                       check_noerr( err );
+                                       if ( ( gTcpipKey != NULL ) && ( gTcpipChangedEvent ) )
+                                       {
+                                               err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE );
+                                               check_noerr( err );
+                                       }
                                }
-                       }
-                       else if ( result == kWaitListFileShareEvent )
-                       {
-                               // File sharing changed
+                               else if ( result == kWaitListDynDNSEvent )
+                               {
+                                       // The DynDNS config might have changed
 
-                               FileSharingDidChange( &gMDNSRecord );
+                                       DynDNSConfigDidChange( &gMDNSRecord );
 
-                               // and reset the event handler
+                                       // and reset the event handler
 
-                               if ((gFileSharingKey != NULL) && (gFileSharingChangedEvent))
+                                       if ((gDdnsKey != NULL) && (gDdnsChangedEvent))
+                                       {
+                                               err = RegNotifyChangeKeyValue(gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
+                                               check_noerr( err );
+                                       }
+                               }
+                               else if ( result == kWaitListFileShareEvent )
                                {
-                                       err = RegNotifyChangeKeyValue(gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
-                                       check_noerr( err );
+                                       // File sharing changed
+
+                                       FileSharingDidChange( &gMDNSRecord );
+
+                                       // and reset the event handler
+
+                                       if ((gFileSharingKey != NULL) && (gFileSharingChangedEvent))
+                                       {
+                                               err = RegNotifyChangeKeyValue(gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
+                                               check_noerr( err );
+                                       }
                                }
-                       }
-                       else if ( result == kWaitListFirewallEvent )
-                       {
-                               // Firewall configuration changed
+                               else if ( result == kWaitListFirewallEvent )
+                               {
+                                       // Firewall configuration changed
 
-                               FirewallDidChange( &gMDNSRecord );
+                                       FirewallDidChange( &gMDNSRecord );
 
-                               // and reset the event handler
+                                       // and reset the event handler
 
-                               if ((gFirewallKey != NULL) && (gFirewallChangedEvent))
+                                       if ((gFirewallKey != NULL) && (gFirewallChangedEvent))
+                                       {
+                                               err = RegNotifyChangeKeyValue(gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
+                                               check_noerr( err );
+                                       }
+                               }
+                               else if ( result == kWaitListSPSWakeupEvent )
                                {
-                                       err = RegNotifyChangeKeyValue(gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
-                                       check_noerr( err );
+                               }
+                               else if ( result == kWaitListSPSSleepEvent )
+                               {
+                               }
+                               /*
+                               else if ( result == kWaitListUDSEvent )
+                               {
+                                       gUDSCallback( ( int ) gUDSSocket, 0, NULL );
+                               }
+                               */
+                               else
+                               {
+                                       int waitItemIndex;
+
+                                       waitItemIndex = (int)( ( (int) result ) - WAIT_OBJECT_0 );
+                                       dlog( kDebugLevelChatty, DEBUG_NAME "waitable event on %d\n", waitItemIndex );
+                                       check( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) );
+
+                                       if ( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
+                                       {
+                                               HANDLE                  signaledEvent;
+                                               EventSource     *       source;
+                                               int                             n = 0;
+                                               
+                                               signaledEvent = waitList[ waitItemIndex ];
+
+                                               for ( source = gEventSourceList; source; source = source->next )
+                                               {
+                                                       if ( source->event == signaledEvent )
+                                                       {
+                                                               source->handler( &gMDNSRecord, source->event, source->context );
+                                                               ++n;
+                                                               break;
+                                                       }
+                                               }
+
+                                               check( n > 0 );
+                                       }
+                                       else
+                                       {
+                                               dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
+                                       }
                                }
                        }
-                       else if ( result == kWaitListSPSWakeupEvent )
-                       {
-                       }
-                       else if ( result == kWaitListSPSSleepEvent )
-                       {
-                       }
-                       else if ( result == kWaitListUDSEvent )
-                       {
-                               gUDSCallback( ( int ) gUDSSocket, 0, NULL );
-                       }
-                       else if ( result != WAIT_IO_COMPLETION )
+                       else
                        {
-                               // Unexpected wait result.
+                               Sleep( 3 * 1000 );
+                               
+                               err = SetupInterfaceList( &gMDNSRecord );
+                               check( !err );
+
+                               err = uDNS_SetupDNSConfig( &gMDNSRecord );
+                               check( !err );
                                
-                               dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
+                               break;
                        }
                }
-               else
-               {
-                       Sleep( 3 * 1000 );
-                       
-                       err = SetupInterfaceList( &gMDNSRecord );
-                       check( !err );
 
-                       err = uDNS_SetupDNSConfig( &gMDNSRecord );
-                       check( !err );
-                       
-                       break;
+               if ( waitList )
+               {
+                       free( waitList );
+                       waitList = NULL;
+                       waitListCount = 0;
                }
        }
 
+exit:
+
        return( 0 );
 }
 
@@ -1444,10 +1491,11 @@ static void     ServiceSpecificFinalize( int argc, LPTSTR argv[] )
        //
        // clean up any open sessions
        //
-       while (gEventSources.Head)
+       while ( gEventSourceList )
        {
-               EventSourceFinalize((EventSource*) gEventSources.Head);
+               UnregisterWaitableEvent( &gMDNSRecord, gEventSourceList->event );
        }
+
        //
        // give a chance for the udsserver code to clean up
        //
@@ -1703,45 +1751,34 @@ mDNSlocal mStatus       TearDownNotifications()
                gSPSSleepEvent = NULL;
        }
 
-       if ( gUDSEvent )
-       {
-               CloseHandle( gUDSEvent );
-               gUDSEvent = NULL;
-       }
-
        return( mStatus_NoError );
 }
 
 
-static void
-CoreCallback(mDNS * const inMDNS, mStatus status)
-{
-       if (status == mStatus_ConfigChanged)
-       {
-               SetLLRoute( inMDNS );
-       }
-}
-
-
 //===========================================================================================================================
-//     BeginUDSRecv
+//     RegisterWaitableEvent
 //===========================================================================================================================
 
-mDNSlocal mStatus BeginUDSRecv( EventSource * source )
+static mStatus RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler )
 {
-       DWORD   bytesReceived   = 0;
-       DWORD   flags                   = 0;
-       mStatus err;
+       EventSource * source;
+       mStatus err = mStatus_NoError;
 
-       ZeroMemory( &source->overlapped, sizeof( source->overlapped ) );
-       source->overlapped.hEvent = source;
+       ( void ) inMDNS;
+       check( event );
+       check( handler );
 
-       source->wbuf.buf = ( char* ) source->buf;
-       source->wbuf.len = sizeof( source->buf );
+       source = ( EventSource* ) malloc( sizeof( EventSource ) );
+       require_action( source, exit, err = mStatus_NoMemoryErr );
+       mDNSPlatformMemZero( source, sizeof( EventSource ) );
+       source->event = event;
+       source->context = context;
+       source->handler = handler;
 
-       err = WSARecv( source->sock, &source->wbuf, 1, &bytesReceived, &flags, &source->overlapped, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) EndUDSRecv );
-       err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), WSAGetLastError(), kUnknownErr );
-       require_noerr( err, exit );
+       source->next                    = gEventSourceList;
+       gEventSourceList                = source;
+       gEventSourceListChanged = TRUE;
+       gEventSources++;
 
 exit:
 
@@ -1750,35 +1787,146 @@ exit:
 
 
 //===========================================================================================================================
-//     EndUDSRecv
+//     UnregisterWaitableEvent
 //===========================================================================================================================
 
-mDNSlocal void EndUDSRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags )
+static void UnregisterWaitableEvent( mDNS * const inMDNS, HANDLE event )
 {
-       EventSource     * source;\r
-\r
-       ( void ) flags;\r
-\r
-       source = ( overlapped != NULL ) ? overlapped->hEvent : NULL;
+       EventSource     *       current = gEventSourceList;
+       EventSource     *       last    = NULL;
 
-       if ( source && ( source->sock != INVALID_SOCKET ) )
-       {
-               source->lastError = error;
+       ( void ) inMDNS;
+       check( event );
 
-               if ( !error )
+       while ( current )
+       {
+               if ( current->event == event )
                {
-                       if ( bytesTransferred )
+                       if ( last == NULL )
                        {
-                               source->bptr = source->buf;
-                               source->eptr = source->buf + bytesTransferred;
+                               gEventSourceList = current->next;
                        }
                        else
                        {
-                               source->closed = TRUE;
+                               last->next = current->next;
                        }
+
+                       gEventSourceListChanged = TRUE;
+                       gEventSources--;
+                       free( current );
+
+                       break;
                }
 
-               source->callback( (int) source->sock, 0, source->context );
+               last    = current;
+               current = current->next;
+       }
+}
+
+
+//===========================================================================================================================
+//     SetupWaitList
+//===========================================================================================================================
+
+mDNSlocal mStatus SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
+{
+       int                             waitListCount;
+       HANDLE          *       waitList;
+       HANDLE          *       waitItemPtr;
+       EventSource     *       source;
+       mStatus                 err;
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list\n" );
+       
+       ( void ) inMDNS;
+       check( inMDNS->p );
+       check( outWaitList );
+       check( outWaitListCount );
+       
+       // Allocate an array to hold all the objects to wait on.
+       
+       waitListCount = kWaitListFixedItemCount + gEventSources;
+       waitList = ( HANDLE* ) malloc( waitListCount * sizeof( *waitList ) );
+       require_action( waitList, exit, err = mStatus_NoMemoryErr );
+       waitItemPtr = waitList;
+       
+       // Add the fixed wait items to the beginning of the list.
+       
+       *waitItemPtr++  =       gStopEvent;
+       *waitItemPtr++  =       gInterfaceListChangedEvent;
+       *waitItemPtr++  =       gDescChangedEvent;
+       *waitItemPtr++  =       gTcpipChangedEvent;
+       *waitItemPtr++  =       gDdnsChangedEvent;
+       *waitItemPtr++  =       gFileSharingChangedEvent;
+       *waitItemPtr++  =       gFirewallChangedEvent;
+       *waitItemPtr++  =       gSPSWakeupEvent;
+       *waitItemPtr++  =       gSPSSleepEvent;
+
+       for ( source = gEventSourceList; source; source = source->next )
+       {
+               *waitItemPtr++ = source->event;
+       }
+
+       check( ( int )( waitItemPtr - waitList ) == waitListCount );
+       
+       *outWaitList            = waitList;
+       *outWaitListCount       = waitListCount;
+       waitList                        = NULL;
+       err                                     = mStatus_NoError;
+       
+exit:
+
+       if( waitList )
+       {
+               free( waitList );
+       }
+
+       dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list done (err=%d %m)\n", err, err );
+       return( err );
+}
+
+
+//===========================================================================================================================
+//     CoreCallback
+//===========================================================================================================================
+
+static void
+CoreCallback(mDNS * const inMDNS, mStatus status)
+{
+       if (status == mStatus_ConfigChanged)
+       {
+               SetLLRoute( inMDNS );
+       }
+}
+
+
+//===========================================================================================================================
+//     UDSCanAccept
+//===========================================================================================================================
+
+mDNSlocal void UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context )
+{
+       ( void ) inMDNS;
+       ( void ) event;
+       
+       if ( gUDSCallback )
+       {
+               gUDSCallback( ( int ) gUDSSocket, 0, context );
+       }
+}
+
+
+//===========================================================================================================================
+//     UDSCanRead
+//===========================================================================================================================
+
+mDNSlocal void UDSCanRead( TCPSocket * sock )
+{
+       udsEventCallback callback = ( udsEventCallback ) sock->userCallback;
+
+       if ( callback )
+       {
+               callback( (int) sock->fd, 0, sock->userContext );
        }
 }
 
@@ -1799,40 +1947,35 @@ udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *conte
 
        if ( context )
        {
-               EventSource * source;
-
-               source = malloc( sizeof( EventSource ) );
-               require_action( source, exit, err = mStatus_NoMemoryErr );
-               mDNSPlatformMemZero( source, sizeof( EventSource ) );
+               TCPSocket * sock;
 
-               source->sock            = (SOCKET) fd;
-               source->callback        = callback;
-               source->context         = context;
+               sock = malloc( sizeof( TCPSocket ) );
+               require_action( sock, exit, err = mStatus_NoMemoryErr );
+               mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
 
-               // Setup socket with alertable i/o
+               sock->fd                                = (SOCKET) fd;
+               sock->readEventHandler  = UDSCanRead;
+               sock->userCallback              = callback;
+               sock->userContext               = context;
+               sock->m                                 = &gMDNSRecord;
 
-               err = BeginUDSRecv( source );
+               err = TCPAddSocket( sock->m, sock );
                require_noerr( err, exit );
-               
-               // add the event source to the end of the list, while checking
-               // to see if the list needs to be initialized
-               //
-               if ( gEventSources.LinkOffset == 0)
-               {
-                       InitLinkedList( &gEventSources, offsetof( EventSource, next ) );
-               }
-
-               AddToTail( &gEventSources, source );
 
-               *platform_data = source;
+               *platform_data = sock;
        }
        else
        {
-               err = WSAEventSelect( fd, gUDSEvent, FD_ACCEPT | FD_CLOSE);\r
-               err = translate_errno( err == 0, WSAGetLastError(), kNoResourcesErr );\r
-               require_noerr( err, exit );
                gUDSSocket              = fd;
                gUDSCallback    = callback;
+               gUDSEvent               = CreateEvent( NULL, FALSE, FALSE, NULL );
+               err = translate_errno( gUDSEvent, (mStatus) GetLastError(), kUnknownErr );
+               require_noerr( err, exit ); 
+               err = WSAEventSelect( fd, gUDSEvent, FD_ACCEPT | FD_CLOSE );\r
+               err = translate_errno( err == 0, WSAGetLastError(), kNoResourcesErr );\r
+               require_noerr( err, exit );
+               err = RegisterWaitableEvent( &gMDNSRecord, gUDSEvent, context, UDSCanAccept );
+               require_noerr( err, exit );
        }
 
 exit:
@@ -1844,56 +1987,21 @@ exit:
 int
 udsSupportReadFD( SocketRef fd, char *buf, int len, int flags, void *platform_data )
 {
-       EventSource     *       source;
-       int                             bytesLeft;
+       TCPSocket       *       sock;
+       mDNSBool                closed;
        int                             ret;
 
        ( void ) flags;
 
-       source = ( EventSource* ) platform_data;
-       require_action( source, exit, ret = -1 );
-       require_action( source->sock == fd, exit, ret = -1 );
-
-       if ( source->closed )
-       {
-               ret = 0;
-       }
-       else if ( source->lastError == 0 )
-       {
-               // First check to see if we have any data left in our buffer
-
-               bytesLeft = ( DWORD ) ( source->eptr - source->bptr );
-
-               if ( bytesLeft )
-               {
-                       int bytesToCopy = ( bytesLeft < len ) ? bytesLeft : len;
-
-                       memcpy( buf, source->bptr, bytesToCopy );
-                       source->bptr += bytesToCopy;
+       sock = ( TCPSocket* ) platform_data;
+       require_action( sock, exit, ret = -1 );
+       require_action( sock->fd == fd, exit, ret = -1 );
 
-                       ret = bytesToCopy;
+       ret = mDNSPlatformReadTCP( sock, buf, len, &closed );
 
-                       if ( bytesLeft == bytesToCopy )
-                       {
-                               source->lastError = BeginUDSRecv( source );
-
-                               if ( source->lastError )
-                               {
-                                       WSASetLastError( source->lastError );
-                                       ret = -1;
-                               }
-                       }
-               }
-               else
-               {
-                       WSASetLastError( WSAEWOULDBLOCK );
-                       ret = -1;
-               }
-       }
-       else
+       if ( closed )
        {
-               WSASetLastError( source->lastError );
-               ret = -1;
+               ret = 0;
        }
 
 exit:
@@ -1905,29 +2013,25 @@ exit:
 mStatus
 udsSupportRemoveFDFromEventLoop( SocketRef fd, void *platform_data)            // Note: This also CLOSES the socket
 {
-       mStatus err = mStatus_NoError;
+       mStatus err = kNoErr;
 
-       if ( platform_data )
+       if ( platform_data != NULL )
        {
-               EventSource * source;
+               TCPSocket * sock;
 
-               source = ( EventSource* ) platform_data;
-               check( fd == source->sock );
-
-               if ( source )
-               {
-                       EventSourceFinalize( source );  
-               }
+               dlog( kDebugLevelInfo, DEBUG_NAME "session closed\n" );
+               sock = ( TCPSocket* ) platform_data;
+               check( sock->fd == fd );
+               mDNSPlatformTCPCloseConnection( sock );
        }
-       else
+       else if ( gUDSEvent != NULL )
        {
-               err = WSAEventSelect( fd, gUDSEvent, 0 );
-               err = translate_errno( err == 0, WSAGetLastError(), kUnknownErr );
-               require_noerr( err, exit );
+               UnregisterWaitableEvent( &gMDNSRecord, gUDSEvent );
+               WSAEventSelect( fd, gUDSEvent, 0 );
+               CloseHandle( gUDSEvent );
+               gUDSEvent = NULL;
        }
 
-exit:
-
        return err;
 }
 
@@ -1940,36 +2044,6 @@ mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
        }
 
 
-static mStatus
-EventSourceFinalize(EventSource * source)
-{      
-       check( source );
-
-       if ( source->sock != INVALID_SOCKET )
-       {
-               closesocket( source->sock );
-               source->sock = INVALID_SOCKET;
-       }
-       
-       // Remove the session from the list.
-       RemoveFromList(&gEventSources, source);
-       
-       // Queue the free
-       QueueUserAPC( ( PAPCFUNC ) EventSourceFree, gMDNSRecord.p->mainThread, ( ULONG_PTR ) source );
-       
-       dlog( kDebugLevelInfo, DEBUG_NAME "session closed\n" );
-
-       return( mStatus_NoError );
-}
-
-
-static void
-EventSourceFree( EventSource * source )
-{
-       free( source );
-}
-
-
 //===========================================================================================================================
 //     SystemWakeForNetworkAccess
 //===========================================================================================================================
index 7103994..f95b6ed 100755 (executable)
@@ -97,13 +97,6 @@ mDNSlocal void                               FreeInterface( mDNSInterfaceData *inIFD );
 mDNSlocal mStatus                      SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef  );
 mDNSlocal mStatus                      SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
 mDNSlocal OSStatus                     GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
-
-mDNSlocal unsigned WINAPI      TCPConnectThread( LPVOID inParam );
-mDNSlocal void CALLBACK                TCPConnectSuccess( ULONG_PTR dwParam );
-mDNSlocal void CALLBACK                TCPConnectFailure( ULONG_PTR dwParam );
-mDNSlocal mStatus                      TCPBeginRecv( TCPSocket * sock );
-mDNSlocal void                         TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
-
 mDNSlocal int                          getifaddrs( struct ifaddrs **outAddrs );
 mDNSlocal void                         freeifaddrs( struct ifaddrs *inAddrs );
 
@@ -122,30 +115,6 @@ struct     mDNSPlatformInterfaceInfo
        mDNSAddr                        ip;
 };
 
-struct TCPSocket_struct
-{
-       TCPSocketFlags                  flags;          // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
-       mDNS                            *       m;
-       SocketRef                               fd;
-       HANDLE                                  connectThread;
-       CRITICAL_SECTION                lock;
-       BOOL                                    lockInitialized;
-       BOOL                                    connectReplyQueued;
-       HANDLE                                  connectEvent;
-       HANDLE                                  stopEvent;
-       BOOL                                    connected;
-       TCPConnectionCallback   callback;
-       void                            *       context;
-       DWORD                                   lastError;
-       BOOL                                    closed;\r
-       OVERLAPPED                              overlapped;
-       WSABUF                                  wbuf;
-       uint8_t                                 buf[ 4192 ];
-       uint8_t                         *       bptr;
-       uint8_t                         *       eptr;
-       TCPSocket                       *       next;
-};
-
 
 mDNSexport mStatus     mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
 mDNSexport mStatus     mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
@@ -169,7 +138,11 @@ mDNSlocal mStatus                  RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWOR
 mDNSlocal struct ifaddrs*      myGetIfAddrs(int refresh);
 mDNSlocal OSStatus                     TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize );
 mDNSlocal OSStatus                     WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
-mDNSlocal void                         FreeTCPSocket( TCPSocket *sock );
+mDNSlocal void                         TCPDidConnect( mDNS * const inMDNS, HANDLE event, void * context );
+mDNSlocal void                         TCPCanRead( TCPSocket * sock );
+mDNSlocal mStatus                      TCPBeginRecv( TCPSocket * sock );
+mDNSlocal void                         TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
+mDNSlocal void                         TCPFreeSocket( TCPSocket *sock );
 mDNSlocal OSStatus                     UDPBeginRecv( UDPSocket * socket );
 mDNSlocal void                         UDPEndRecv( DWORD err, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
 mDNSlocal void                         UDPFreeSocket( UDPSocket * sock );
@@ -199,8 +172,6 @@ mDNSlocal mDNSu8                    IsWOMPEnabledForAdapter( const char * adapterName );
 
 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
 mDNSs32                                                        mDNSPlatformOneSecond = 0;
-mDNSlocal TCPSocket            *               gTCPConnectionList              = NULL;
-mDNSlocal int                                  gTCPConnections                 = 0;
 mDNSlocal UDPSocket            *               gUDPSocketList                  = NULL;
 mDNSlocal int                                  gUDPSockets                             = 0;
 
@@ -919,14 +890,11 @@ mDNSPlatformTCPSocket
 
        port->NotAnInteger = saddr.sin_port;
 
-       InitializeCriticalSection( &sock->lock );
-       sock->lockInitialized = TRUE;
-
 exit:
 
        if ( err && sock )
        {
-               FreeTCPSocket( sock );
+               TCPFreeSocket( sock );
                sock = mDNSNULL;
        }
 
@@ -940,7 +908,7 @@ exit:
 mStatus
 mDNSPlatformTCPConnect
        (
-       TCPSocket *                     sock,
+       TCPSocket                       *       sock,
        const mDNSAddr          *       inDstIP, 
        mDNSOpaque16                    inDstPort, 
        mDNSInterfaceID                 inInterfaceID,
@@ -961,8 +929,9 @@ mDNSPlatformTCPConnect
 
        // Setup connection data object
 
-       sock->callback = inCallback;
-       sock->context = inContext;
+       sock->readEventHandler  = TCPCanRead;
+       sock->userCallback              = inCallback;
+       sock->userContext               = inContext;
 
        mDNSPlatformMemZero(&saddr, sizeof(saddr));
        saddr.sin_family        = AF_INET;
@@ -973,37 +942,28 @@ mDNSPlatformTCPConnect
 
        err = connect( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
        require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
-       sock->connected         = !err ? TRUE : FALSE;
+       sock->connected = !err ? TRUE : FALSE;
 
-       if ( !sock->connected )
+       if ( sock->connected )
+       {
+               err = TCPAddSocket( sock->m, sock );
+               require_noerr( err, exit );
+       }
+       else
        {
-               unsigned threadID;
+               require_action( sock->m->p->registerWaitableEventFunc != NULL, exit, err = mStatus_ConnFailed );
 
                sock->connectEvent      = CreateEvent( NULL, FALSE, FALSE, NULL );
                err = translate_errno( sock->connectEvent, GetLastError(), mStatus_UnknownErr );
                require_noerr( err, exit );
 
-               sock->stopEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-               err = translate_errno( sock->stopEvent, GetLastError(), mStatus_UnknownErr );
-               require_noerr( err, exit );
-
                err = WSAEventSelect( sock->fd, sock->connectEvent, FD_CONNECT );
                require_noerr( err, exit );
 
-               // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time \r
-               // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.\r
-       \r
-               sock->connectThread = ( HANDLE ) _beginthreadex_compat( NULL, 0, TCPConnectThread, sock, 0, &threadID );\r
-               err = translate_errno( sock->connectThread, (mStatus) GetLastError(), kUnknownErr );\r
+               err = sock->m->p->registerWaitableEventFunc( sock->m, sock->connectEvent, sock, TCPDidConnect );
                require_noerr( err, exit );
        }
 
-       // Bookkeeping
-
-       sock->next                      = gTCPConnectionList;
-       gTCPConnectionList      = sock;
-       gTCPConnections++;
-
 exit:
 
        if ( !err )
@@ -1052,42 +1012,20 @@ exit:
 
 mDNSexport void        mDNSPlatformTCPCloseConnection( TCPSocket *sock )
 {
-       TCPSocket *     inserted  = gTCPConnectionList;
-       TCPSocket *     last = NULL;
+       check( sock );
 
-       while ( inserted )
+       if ( sock->connectEvent && sock->m->p->unregisterWaitableEventFunc )
        {
-               if ( inserted == sock )
-               {
-                       if ( last == NULL )
-                       {
-                               gTCPConnectionList = inserted->next;
-                       }
-                       else
-                       {
-                               last->next = inserted->next;
-                       }
-
-                       EnterCriticalSection( &sock->lock );
-
-                       closesocket( sock->fd );
-                       sock->fd = INVALID_SOCKET;
-
-                       if ( !sock->connectReplyQueued )
-                       {
-                               QueueUserAPC( ( PAPCFUNC ) FreeTCPSocket, sock->m->p->mainThread, ( ULONG_PTR ) sock );
-                       }
-
-                       LeaveCriticalSection( &sock->lock );
-
-                       gTCPConnections--;
+               sock->m->p->unregisterWaitableEventFunc( sock->m, sock->connectEvent );
+       }
 
-                       break;
-               }
+       if ( sock->fd != INVALID_SOCKET )
+       {
+               closesocket( sock->fd );
+               sock->fd = INVALID_SOCKET;
 
-               last            = inserted;
-               inserted        = inserted->next;
-       }       
+               QueueUserAPC( ( PAPCFUNC ) TCPFreeSocket, sock->m->p->mainThread, ( ULONG_PTR ) sock );
+       }
 }
 
 //===========================================================================================================================
@@ -1100,10 +1038,10 @@ mDNSexport long mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned l
        long                    ret;
 
        ret = -1;
+       *closed = sock->closed;
 
-       if ( sock->closed )
+       if ( *closed )
        {
-               *closed = mDNStrue;
                ret = 0;
        }
        else if ( sock->lastError == 0 )
@@ -1127,10 +1065,21 @@ mDNSexport long mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned l
                                
                                if ( sock->lastError )
                                {
+                                       WSASetLastError( sock->lastError );
                                        ret = -1;
                                }
                        }
                }
+               else
+               {
+                       WSASetLastError( WSAEWOULDBLOCK );\r
+                       ret = -1;
+               }
+       }
+       else
+       {
+               WSASetLastError( sock->lastError );
+               ret = -1;
        }
 
        return ret;
@@ -1166,98 +1115,94 @@ exit:
 //===========================================================================================================================
 
 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
-    {
-    return ( int ) sock->fd;
-    }
+{
+       return ( int ) sock->fd;
+}
 
 
 //===========================================================================================================================
-//     TCPConnectThread
+//     TCPAddConnection
 //===========================================================================================================================
 
-mDNSlocal unsigned WINAPI TCPConnectThread( LPVOID inParam )\r
-{\r
-       TCPSocket * sock = ( TCPSocket* ) inParam;\r
-       HANDLE          waitList[ 2 ];\r
-       DWORD           result;\r
-\r
-       waitList[ 0 ] = sock->connectEvent;\r
-       waitList[ 1 ] = sock->stopEvent;\r
-       result = WaitForMultipleObjects( 2, waitList, FALSE, 60 * 1000 );\r
-\r
-       EnterCriticalSection( &sock->lock );\r
-\r
-       if ( sock->fd != INVALID_SOCKET )\r
-       {\r
-               BOOL ok = FALSE;\r
-\r
-               if ( result == WAIT_OBJECT_0 )\r
-               {\r
-                       ok = QueueUserAPC( ( PAPCFUNC ) TCPConnectSuccess, sock->m->p->mainThread, ( ULONG_PTR ) sock );\r
-                       check( ok );\r
-\r
-               }\r
-               else if ( result != WAIT_OBJECT_0 + 1 )\r
-               {\r
-                       ok = QueueUserAPC( ( PAPCFUNC ) TCPConnectFailure, sock->m->p->mainThread, ( ULONG_PTR ) sock );\r
-                       check( ok );\r
-               }\r
-\r
-               sock->connectReplyQueued = ok;\r
-       }\r
-\r
-       LeaveCriticalSection( &sock->lock );\r
-\r
-       _endthreadex_compat( 0 );\r
-       return 0;\r
+mStatus TCPAddSocket( mDNS * const inMDNS, TCPSocket *sock )
+{
+       mStatus err;
+
+       ( void ) inMDNS;
+
+       dlog( kDebugLevelChatty, DEBUG_NAME "adding TCPSocket 0x%x:%d\n", sock, sock->fd );
+       err = TCPBeginRecv( sock );
+       require_noerr( err, exit );
+
+exit:
+
+       return err;
 }
 
 
 //===========================================================================================================================
-//     TCPConnectSuccess
+//     TCPDidConnect
 //===========================================================================================================================
 
-mDNSlocal void CALLBACK TCPConnectSuccess( ULONG_PTR dwParam )\r
+mDNSlocal void TCPDidConnect( mDNS * const inMDNS, HANDLE event, void * context )\r
 {\r
-       TCPSocket * sock = ( TCPSocket* ) dwParam;\r
+       TCPSocket * sock = ( TCPSocket* ) context;\r
+       TCPConnectionCallback callback = NULL;\r
+       WSANETWORKEVENTS sockEvent;\r
+       int err = kNoErr;\r
+\r
+       if ( inMDNS->p->unregisterWaitableEventFunc )\r
+       {\r
+               inMDNS->p->unregisterWaitableEventFunc( inMDNS, event );\r
+       }\r
+\r
+       if ( sock )\r
+       {\r
+               callback = ( TCPConnectionCallback ) sock->userCallback;\r
+               err = WSAEnumNetworkEvents( sock->fd, sock->connectEvent, &sockEvent );\r
+               require_noerr( err, exit );\r
+               require_action( sockEvent.lNetworkEvents & FD_CONNECT, exit, err = mStatus_UnknownErr );\r
+               require_action( sockEvent.iErrorCode[ FD_CONNECT_BIT ] == 0, exit, err = sockEvent.iErrorCode[ FD_CONNECT_BIT ] );\r
 \r
-       if ( sock->fd != INVALID_SOCKET )\r
-       {       \r
                sock->connected = mDNStrue;\r
-               sock->callback( sock, sock->context, TRUE, 0 );\r
 \r
                if ( sock->fd != INVALID_SOCKET )\r
                {\r
-                       TCPBeginRecv( sock );\r
+                       err = TCPAddSocket( sock->m, sock );\r
+                       require_noerr( err, exit );\r
                }\r
-       }\r
-       else\r
-       {\r
-               FreeTCPSocket( sock );\r
-       }\r
-}\r
-\r
 \r
-//===========================================================================================================================
-//     TCPConnectFailure
-//===========================================================================================================================
+               if ( callback )\r
+               {\r
+                       callback( sock, sock->userContext, TRUE, 0 );\r
+               }\r
+       }\r
 \r
-mDNSlocal void CALLBACK TCPConnectFailure( ULONG_PTR dwParam )\r
-{\r
-       TCPSocket * sock = ( TCPSocket* ) dwParam;\r
+exit:\r
 \r
-       if ( sock->fd != INVALID_SOCKET )\r
-       {\r
-               sock->connected = mDNSfalse;\r
-               sock->callback( sock, sock->context, TRUE, mStatus_ConnFailed );\r
-       }\r
-       else\r
+       if ( err && callback )\r
        {\r
-               FreeTCPSocket( sock );\r
+               callback( sock, sock->userContext, TRUE, err );\r
        }\r
 }
 
 
+
+//===========================================================================================================================
+//     TCPCanRead
+//===========================================================================================================================
+
+mDNSlocal void TCPCanRead( TCPSocket * sock )
+{
+       TCPConnectionCallback callback = ( TCPConnectionCallback ) sock->userCallback;
+
+       if ( callback )
+       {
+               callback( sock, sock->userContext, mDNSfalse, sock->lastError );
+       }
+}
+
+
 //===========================================================================================================================
 //     TCPBeginRecv
 //===========================================================================================================================
@@ -1313,7 +1258,10 @@ mDNSlocal void TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED
                        }
                }
 
-               sock->callback( sock, sock->context, FALSE, sock->lastError );
+               if ( sock->readEventHandler != NULL )
+               {
+                       sock->readEventHandler( sock );
+               }
        }
 }
 
@@ -4280,45 +4228,28 @@ exit:
 
 
 //===========================================================================================================================
-//     FreeTCPConnectionData
+//     TCPFreeSocket
 //===========================================================================================================================
 
 mDNSlocal void
-FreeTCPSocket( TCPSocket *sock )
+TCPFreeSocket( TCPSocket *sock )
 {
        check( sock );
 
-       if ( sock->connectThread )
-       {
-               SetEvent( sock->stopEvent );
-               WaitForSingleObject( sock->connectThread, 5 * 1000 );
-               sock->connectThread = NULL;
-       }
-
+       dlog( kDebugLevelChatty, DEBUG_NAME "freeing TCPSocket 0x%x:%d\n", sock, sock->fd );
+       
        if ( sock->connectEvent )
        {
                CloseHandle( sock->connectEvent );
                sock->connectEvent = NULL;
        }
 
-       if ( sock->stopEvent )
-       {
-               CloseHandle( sock->stopEvent );
-               sock->stopEvent = NULL;
-       }
-
        if ( sock->fd != INVALID_SOCKET )
        {
                closesocket( sock->fd );
                sock->fd = INVALID_SOCKET;
        }
 
-       if ( sock->lockInitialized )
-       {
-               DeleteCriticalSection( &sock->lock );
-               sock->lockInitialized = FALSE;
-       }
-
        free( sock );
 }
 
@@ -4332,9 +4263,10 @@ UDPFreeSocket( UDPSocket * sock )
 {
     check( sock );
 
+       dlog( kDebugLevelChatty, DEBUG_NAME "freeing UDPSocket %d (%##a)\n", sock->fd, &sock->addr );
+
     if ( sock->fd != INVALID_SOCKET )
-    {
-               dlog( kDebugLevelTrace, DEBUG_NAME "freeing socket %d (%##a)\n", sock->fd, &sock->addr );
+    {          
         closesocket( sock->fd );
                sock->fd = INVALID_SOCKET;
     }
index 5e13fce..ac9529e 100755 (executable)
        extern "C" {
 #endif
 
+typedef void ( *TCPReadEventHandler )( TCPSocket * sock );
+typedef void ( *TCPUserCallback )();
+
+struct TCPSocket_struct
+{
+       TCPSocketFlags                          flags;          // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
+       SOCKET                                          fd;
+       TCPReadEventHandler                     readEventHandler;
+       HANDLE                                          connectEvent;
+       BOOL                                            connected;
+       TCPUserCallback                         userCallback;
+       void                                    *       userContext;
+       DWORD                                           lastError;
+       BOOL                                            closed;\r
+       OVERLAPPED                                      overlapped;
+       WSABUF                                          wbuf;
+       uint8_t                                         buf[ 4192 ];
+       uint8_t                                 *       bptr;
+       uint8_t                                 *       eptr;
+       mDNS                                    *       m;
+};
+
+
 struct UDPSocket_struct
 {
        mDNSIPPort                                              port;                   // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
@@ -71,13 +94,19 @@ struct      mDNSInterfaceData
 
 
 //---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        HostDescriptionChangedCallback
+/*!    @typedef        RegisterWaitableEventHandler
+*/
+typedef void           (*RegisterWaitableEventHandler)(mDNS * const inMDNS, HANDLE event, void * context );
 
-       @abstract       mDNSWin32 core will call out through this function pointer
-                               after detecting that the computer description has changed
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        RegisterWaitableEventFunc
 */
-typedef void (*HostDescriptionChangedCallback)(mDNS * const inMDNS);
+typedef mStatus                (*RegisterWaitableEventFunc)(mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler );
+
 //---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        UnregisterWaitableEventHandler
+*/
+typedef void           (*UnregisterWaitableEventFunc)(mDNS * const inMDNS, HANDLE event );
 
 
 //---------------------------------------------------------------------------------------------------------------------------
@@ -89,6 +118,8 @@ typedef void (*HostDescriptionChangedCallback)(mDNS * const inMDNS);
 struct mDNS_PlatformSupport_struct
 {
        HANDLE                                          mainThread;
+       RegisterWaitableEventFunc       registerWaitableEventFunc;
+       UnregisterWaitableEventFunc     unregisterWaitableEventFunc;
        time_t                                          nextDHCPLeaseExpires;
        mDNSBool                                        smbRegistered;
        ServiceRecordSet                        smbSRS;
@@ -134,6 +165,7 @@ extern void         TCPIPConfigDidChange( mDNS * const inMDNS );
 extern void            DynDNSConfigDidChange( mDNS * const inMDNS );
 extern void            FileSharingDidChange( mDNS * const inMDNS );
 extern void            FirewallDidChange( mDNS * const inMDNS );
+extern mStatus  TCPAddSocket( mDNS * const inMDNS, TCPSocket *sock );
 extern mStatus SetupInterfaceList( mDNS * const inMDNS );
 extern mStatus TearDownInterfaceList( mDNS * const inMDNS );
 extern BOOL            IsWOMPEnabled();