0

I am trying to listen to internet status change using the following code. This works fine with cocoa application but in daemon application, networkChangeHappend method never gets called. Do I need to do anything different for daemon app? Or is there any other alternative to listen to internet state change in daemon application?

main.m

#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>
#import "ViewController.h"

int main(int argc, const char * argv[])
{
    
    [NSThread detachNewThreadWithBlock:^{
        [[ViewController sharedInstance] startOperation];
    }];

    [[NSRunLoop currentRunLoop] run];
    
    return 0;
}

ViewController.h

#import <Foundation/Foundation.h>

@interface ViewController : NSObject

+ (instancetype _Nonnull )sharedInstance;
- (BOOL)startOperation;

@end

ViewController.m

#import "ViewController.h"
#import <SystemConfiguration/SystemConfiguration.h>
#include <arpa/inet.h>

@implementation ViewController

+ (instancetype)sharedInstance
{
    static ViewController *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[ViewController alloc] init];
    });
    return sharedInstance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self registerNetworkChangeCallback];
    }
    return self;
}

//MARK: -
- (BOOL)startOperation {
   //some stuff..
}

-(void)registerNetworkChangeCallback
{
    
    struct sockaddr_in zeroAddress;
    
    zeroAddress.sin_addr.s_addr = inet_addr("64.14.192.121");
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;
    
    
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
    
    void *info = (__bridge void *)(self);
    SCNetworkReachabilitySetCallback ((SCNetworkReachabilityRef)defaultRouteReachability,(SCNetworkReachabilityCallBack)networkChangeHappend,info);

    SCNetworkReachabilityScheduleWithRunLoop (
                                              defaultRouteReachability,
                                              CFRunLoopGetCurrent(),
                                              kCFRunLoopDefaultMode
                                              );
    
    [Logger logString:@"registerNetworkChangeCallback"];
    
}


static void networkChangeHappend(
                                 SCNetworkReachabilityRef target,
                                 SCNetworkReachabilityFlags flags,
                                 void *info
                                 )
{
    BOOL isReachable = flags & kSCNetworkFlagsReachable;
    BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;

    ViewController *viewController = (__bridge ViewController *)info;
    (isReachable && !needsConnection) ? [viewController connected] : [viewController disconnected];
}

-(void)connected {
    [Logger logString:@"Network connected"];
}

-(void)disconnected {
    [Logger logString:@"Network disconnected"];
}

@end
prabhu
  • 1,158
  • 1
  • 12
  • 27
  • then you will have fun reading this.. https://gist.github.com/nacho4d/2338521 Your NSThread will end when the app ends, Daemons is not same as a NSThread, but know that allready. ^^ So the gist may give you a clue what went wrong. – Ol Sen Jul 18 '20 at 06:04
  • Sorry I'm new to Mac development so I couldn't understand the problem correctly. Could you please help me get there. Also my Daemon app will be running in the background all the time. – prabhu Jul 18 '20 at 06:18
  • in the gist example you see that in main() there is a while loop that watches for a signal to break its loop to end. That way its running unless the app is forced to do so.. this is what you want. You can still create a thread for where you place your callback, but actually not needed. Mainthread of your app would be anouth. Your singleton init is correct because you want to avoid double start. – Ol Sen Jul 18 '20 at 06:24
  • Hint: daemons are plist files in the Daemon folder structure of your mac. Where in those folders placed plists files contain information what to start on startup, see example comment at the end. – Ol Sen Jul 18 '20 at 06:27

1 Answers1

0

You can use your *info pointer to give your callback a way to access the object you placed the Callback in.

void *info = (__bridge void *)(self);
SCNetworkReachabilitySetCallback ((SCNetworkReachabilityRef)defaultRouteReachability,(SCNetworkReachabilityCallBack)networkChangeHappend,info);

and in your Callback accessing "self" again with.

....
YourClass *yourclass = (__bridge YourClass *)info;
(isReachable && !needsConnection) ? [yourclass connected] : [yourclass disconnected];

where -(void)connected{} and -(void)disconnected{} could be methods of YourControllerClass

Ol Sen
  • 3,163
  • 2
  • 21
  • 30
  • My problem is the callback itself is not getting called. Tried your suggestion as well and it didn't work. – prabhu Jul 18 '20 at 05:25
  • can you show the interface & implementation holding the methods you defined above? – Ol Sen Jul 18 '20 at 05:32