@@ -177,6 +177,8 @@ @interface GCDWebServer () {
177177 dispatch_source_t _source6;
178178 CFNetServiceRef _registrationService;
179179 CFNetServiceRef _resolutionService;
180+ int ipv4ListeningSocket;
181+ int ipv6ListeningSocket;
180182 DNSServiceRef _dnsService;
181183 CFSocketRef _dnsSocket;
182184 CFRunLoopSourceRef _dnsSource;
@@ -463,6 +465,11 @@ - (int)_createListeningSocket:(BOOL)useIPv6
463465 error : (NSError **)error {
464466 int listeningSocket = socket (useIPv6 ? PF_INET6 : PF_INET , SOCK_STREAM , IPPROTO_TCP );
465467 if (listeningSocket > 0 ) {
468+ if (!useIPv6) {
469+ ipv4ListeningSocket = listeningSocket;
470+ } else {
471+ ipv6ListeningSocket = listeningSocket;
472+ }
466473 int yes = 1 ;
467474 setsockopt (listeningSocket, SOL_SOCKET , SO_REUSEADDR , &yes, sizeof (yes));
468475
@@ -570,12 +577,7 @@ - (BOOL)_start:(NSError**)error {
570577 }
571578 }
572579
573- struct sockaddr_in6 addr6;
574- bzero (&addr6, sizeof (addr6));
575- addr6.sin6_len = sizeof (addr6);
576- addr6.sin6_family = AF_INET6 ;
577- addr6.sin6_port = htons (port);
578- addr6.sin6_addr = bindToLocalhost ? in6addr_loopback : in6addr_any;
580+ struct sockaddr_in6 addr6 = [self generateAddressWithPort: port bindToLocalhost: bindToLocalhost];
579581 int listeningSocket6 = [self _createListeningSocket: YES localAddress: &addr6 length: sizeof (addr6) maxPendingConnections: maxPendingConnections error: error];
580582 if (listeningSocket6 <= 0 ) {
581583 close (listeningSocket4);
@@ -740,6 +742,81 @@ - (void)_stop {
740742
741743#if TARGET_OS_IPHONE
742744
745+ - (void )resetIpv4SocketIfError {
746+ int error = 0 ;
747+ socklen_t len = sizeof (error);
748+ int retval = getsockopt (ipv4ListeningSocket, SOL_SOCKET , SO_ERROR , &error, &len);
749+
750+ if (retval != 0 ) {
751+ /* there was a problem getting the error code */
752+ GWS_LOG_ERROR (@" error getting socket error code: %s \n " , strerror (retval));
753+ return ;
754+ }
755+
756+ if (error != 0 ) {
757+ /* socket has a non zero error status */
758+ GWS_LOG_INFO (@" Socket error: %s on socket %d \n " , strerror (error), ipv4ListeningSocket);
759+ dispatch_source_cancel (_source4);
760+ _source4 = nil ;
761+ NSUInteger port = [_GetOption (_options, GCDWebServerOption_Port, @0 ) unsignedIntegerValue ];
762+ BOOL bindToLocalhost = [_GetOption (_options, GCDWebServerOption_BindToLocalhost, @NO ) boolValue ];
763+ NSUInteger maxPendingConnections = [_GetOption (_options, GCDWebServerOption_MaxPendingConnections, @16 ) unsignedIntegerValue ];
764+
765+ struct sockaddr_in addr4 = [self generateIpv4AddressWithPort: port bindToLocalhost: bindToLocalhost];
766+ NSError * nsError = nil ;
767+ int listeningSocket4 = [self _createListeningSocket: NO
768+ localAddress: &addr4
769+ length: sizeof (addr4)
770+ maxPendingConnections: maxPendingConnections
771+ error: &nsError];
772+
773+ if (listeningSocket4 <= 0 ) {
774+ GWS_LOG_ERROR (@" Failed to create the IPv4 socket\n " );
775+ }
776+ _source4 = [self _createDispatchSourceWithListeningSocket: listeningSocket4 isIPv6: NO ];
777+ // Need to investigate
778+ dispatch_resume (_source4);
779+ }
780+ }
781+
782+ - (void )resetIpv6SocketIfError {
783+ int error = 0 ;
784+ NSError * nsError = nil ;
785+ socklen_t len = sizeof (error);
786+ int retval = getsockopt (ipv6ListeningSocket, SOL_SOCKET , SO_ERROR , &error, &len);
787+
788+ if (retval != 0 ) {
789+ /* there was a problem getting the error code */
790+ GWS_LOG_ERROR (@" error getting socket error code: %s \n " , strerror (retval));
791+ return ;
792+ }
793+
794+ if (error != 0 ) {
795+ /* socket has a non zero error status */
796+ GWS_LOG_INFO (@" Socket error: %s on socket %d \n " , strerror (error), ipv6ListeningSocket);
797+
798+ dispatch_source_cancel (_source6);
799+ _source6 = nil ;
800+ NSUInteger port = [_GetOption (_options, GCDWebServerOption_Port, @0 ) unsignedIntegerValue ];
801+ BOOL bindToLocalhost = [_GetOption (_options, GCDWebServerOption_BindToLocalhost, @NO ) boolValue ];
802+ NSUInteger maxPendingConnections = [_GetOption (_options, GCDWebServerOption_MaxPendingConnections, @16 ) unsignedIntegerValue ];
803+
804+ struct sockaddr_in6 addr6 = [self generateAddressWithPort: port bindToLocalhost: bindToLocalhost];
805+ int listeningSocket6 = [self _createListeningSocket: YES
806+ localAddress: &addr6
807+ length: sizeof (addr6)
808+ maxPendingConnections: maxPendingConnections
809+ error: &nsError];
810+ if (listeningSocket6 <= 0 ) {
811+ GWS_LOG_ERROR (@" Failed to create the IPv6 socket\n " );
812+ }
813+ _source6 = [self _createDispatchSourceWithListeningSocket: listeningSocket6 isIPv6: YES ];
814+
815+ // Need to investigate
816+ dispatch_resume (_source6);
817+ }
818+ }
819+
743820- (void )_didEnterBackground : (NSNotification *)notification {
744821 GWS_DCHECK ([NSThread isMainThread ]);
745822 GWS_LOG_DEBUG (@" Did enter background" );
@@ -751,13 +828,39 @@ - (void)_didEnterBackground:(NSNotification*)notification {
751828- (void )_willEnterForeground : (NSNotification *)notification {
752829 GWS_DCHECK ([NSThread isMainThread ]);
753830 GWS_LOG_DEBUG (@" Will enter foreground" );
754- if (!_source4) {
831+
832+ if (_suspendInBackground && !_source4) {
755833 [self _start: NULL ]; // TODO: There's probably nothing we can do on failure
756834 }
835+
836+ if ([self isRunning ]) {
837+ [self resetIpv4SocketIfError ];
838+ [self resetIpv6SocketIfError ];
839+ }
757840}
758841
759842#endif
760843
844+ - (struct sockaddr_in)generateIpv4AddressWithPort : (NSInteger )port bindToLocalhost : (BOOL )bindToLocalhost {
845+ struct sockaddr_in addr4;
846+ bzero (&addr4, sizeof (addr4));
847+ addr4.sin_len = sizeof (addr4);
848+ addr4.sin_family = AF_INET ;
849+ addr4.sin_port = htons (port);
850+ addr4.sin_addr .s_addr = bindToLocalhost ? htonl (INADDR_LOOPBACK ) : htonl (INADDR_ANY );
851+ return addr4;
852+ }
853+
854+ - (struct sockaddr_in6)generateAddressWithPort : (NSInteger )port bindToLocalhost : (BOOL )bindToLocalhost {
855+ struct sockaddr_in6 addr6;
856+ bzero (&addr6, sizeof (addr6));
857+ addr6.sin6_len = sizeof (addr6);
858+ addr6.sin6_family = AF_INET6 ;
859+ addr6.sin6_port = htons (port);
860+ addr6.sin6_addr = bindToLocalhost ? in6addr_loopback : in6addr_any;
861+ return addr6;
862+ }
863+
761864- (BOOL )startWithOptions : (NSDictionary *)options error : (NSError **)error {
762865 if (_options == nil ) {
763866 _options = options ? [options copy ] : @{};
@@ -774,8 +877,8 @@ - (BOOL)startWithOptions:(NSDictionary*)options error:(NSError**)error {
774877#if TARGET_OS_IPHONE
775878 if (_suspendInBackground) {
776879 [[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (_didEnterBackground: ) name: UIApplicationDidEnterBackgroundNotification object: nil ];
777- [[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (_willEnterForeground: ) name: UIApplicationWillEnterForegroundNotification object: nil ];
778880 }
881+ [[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (_willEnterForeground: ) name: UIApplicationWillEnterForegroundNotification object: nil ];
779882#endif
780883 return YES ;
781884 } else {
@@ -791,10 +894,7 @@ - (BOOL)isRunning {
791894- (void )stop {
792895 if (_options) {
793896#if TARGET_OS_IPHONE
794- if (_suspendInBackground) {
795- [[NSNotificationCenter defaultCenter ] removeObserver: self name: UIApplicationDidEnterBackgroundNotification object: nil ];
796- [[NSNotificationCenter defaultCenter ] removeObserver: self name: UIApplicationWillEnterForegroundNotification object: nil ];
797- }
897+ [[NSNotificationCenter defaultCenter ] removeObserver: self ];
798898#endif
799899 if (_source4) {
800900 [self _stop ];
0 commit comments