EXC_BAD_ACCESS exception at Reachability class - ios

I'm using the Reachability class provided here by Apple in my iOS project. I call its currentReachabilityStatus method always before trying to call my own REST web services:
- (NetworkStatus)currentReachabilityStatus
{
NSAssert(_reachabilityRef != NULL, #"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
NetworkStatus returnValue = NotReachable;
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
{
if (_alwaysReturnLocalWiFiStatus)
{
returnValue = [self localWiFiStatusForFlags:flags];
}
else
{
returnValue = [self networkStatusForFlags:flags];
}
}
return returnValue;
}
In turn, I call this method from a custom class I made for convenience:
+ (BOOL)checkNetStatus
{
Reachability *reach = [Reachability reachabilityForInternetConnection];
NetworkStatus status = [reach currentReachabilityStatus];
return [self boolFromStatus:status];
}
I'm performing some tests in an iPhone, enabling the flight mode in its Settings, and then when the app is back to foreground, that method is called several times (my app retries to call the web services if no reachability until they become reachable) and finally I get an EXC_BAD_ACCESS exception at line if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)), and the app crashes.
I don't understand exactly why, because currentReachabilityStatus is called several times before I get the exception and the crash, could it be because it is being called a lot of times and too fast? How could I solve this?
I need help, thanks in advance.
EDIT: whenever I'm going to call of my RESTful services, I do something like this:
- (void)callWebService
{
if ([MyReachabilityManager checkNetStatus]) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
MyServiceWrapper *requestService = [[MyServiceWrapper alloc] initWithServiceUrl];
[requestService queryService];
}
else {
[self keepRequestingMyService]; // this calls this method again until a timeout
}
}

Something similar happened to me, one of my application crashed while switching to Airplane mode and to Wifi frequently (Happened if the Wi-Fi is having low signal strength).
In my case the crash is caused by the NSAssert, the _reachabilityRef was null, so the assert condition was failing:
NSAssert(_reachabilityRef != NULL, #"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
I just removed that and re-wrote that method by adding a extra null check for _reachabilityRef

I had the same: app SOMETIMES crashes when releasing reachabilityRef. Seems like it should be NULL but it is not?
After experimenting i found if I added something in Reachability.h interface (originally it had nothing):
#interface Reachability : NSObject{
BOOL dummy;
}
it stopped crashing, could you try that and report if it helps?
I use XCode 7.1.1

Related

How do I initialize a peripheral manager in Swift?

I want to check if Bluetooth is enabled on my device and print the status to the console. My class conforms to CBPeripheralManagerDelegate and I have no errors. I read the documentation and I implemented the peripheralManagerDidUpdateState function but it never gets called. My understanding is that function is called when Bluetooth's availability changes. So if I turn Bluetooth off that function should be called and then should be called again once I turn Bluetooth back on. But that doesn't happen. I saw another question that had the same problem but the solution was written in Objective-C and didn't solve my problem.
When I run this code in viewDidLoad it returns unknown and I don't know why. I expected it to return powered on:
cbManager.delegate = self
if cbManager.state == .PoweredOn {
println("powered on")
} else if cbManager.state == .Unauthorized {
println("unauthorized")
} else if cbManager.state == .Unknown {
println("unknown")
} else if cbManager.state == .PoweredOff {
println("pow off")
} else if cbManager.state == .Unsupported {
println("unsupported")
}
I declare cbManager outside of viewDidLoad because if I don't the peripheralManagerDidUpdateState doesn't recognize the manager.
That other question's problem was "the object myPeripheralManager is deallocated as soon as viewDidLoad method returns". I think that's my problem too but I don't know how to fix it.
Here's my manager declaration:
let cbManager = CBPeripheralManager() which is outside of viewDidLoad.
Thanks!
UPDATE:
After many hours I think I have found the problem. I don't know if this is why it didn't work but it works now. I was using a CBPeripheralManager when I should've been using a CBCentralManager. This question helped show me (even though it was a completely different problem) the difference between a central and peripheral manager.
UPDATE #2:
Also, the manager that was being passed into peripheralManagerDidUpdateState was different than the manager I was using in the function itself. This in combination with using the wrong manager caused the problems. Hope this helps someone!

How to check for internet connection synchronously?

How to check for network synchronously? I want the network checking to block the calling thread and return the correct result
I tried tonymillion's Reachability and AFNetworkReachabilityManager but they all use callback block. It means the reachability status is unknown before the callback.
I want to check network at applicationDidFinishLaunchingWithOptions: but at this point, reachability is AFNetworkReachabilityStatusUnknown (AFNetworkReachabilityManager) or not reliable (tonymillion's Reachability)
I see that the only way is to perform NSURLConnection against some host (google.com for example) like this Check for internet connection - iOS SDK
Are there any better way?
To answer my own question: It is reliable
Read this Technical Q&A QA1693 Synchronous Networking On The Main Thread
reachability — The System Configuration framework reachability API
() operates synchronously
by default. Thus, seemingly innocuous routines like
SCNetworkReachabilityGetFlags can get you killed by the watchdog. If
you're using the reachability API, you should use it asynchronously.
This involves using the SCNetworkReachabilityScheduleWithRunLoop
routine to schedule your reachability queries on the run loop
So we can use it like this iOS: Check whether internet connection is available
- (BOOL) isConnectionAvailable
{
SCNetworkReachabilityFlags flags;
BOOL receivedFlags;
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(CFAllocatorGetDefault(), [#"dipinkrishna.com" UTF8String]);
receivedFlags = SCNetworkReachabilityGetFlags(reachability, &flags);
CFRelease(reachability);
if (!receivedFlags || (flags == 0) )
{
return FALSE;
} else {
return TRUE;
}
}

iOS: reachabilityWithHostname YES although it should be NO

I tested different frameworks, e.g.
https://github.com/tonymillion/Reachability
https://github.com/VerticodeLabs/VCLReachability
https://github.com/kstenerud/KSReachability
and I would like to know if a host is reachable. On my iPhone, I set my iMac as proxy (Charles) and block or don't block the connections, but the reachability is always YES. Only if I set a non-existing host, it returns NO. But if the host exists but I block the connection to it, I always get isReachable. Isn't there a way to check if the host is really reachable?
If I try with KSReachability, I'm doing the following:
self.reachability = [KSReachability reachabilityToHost:#"www.stackoverflow.com"];
self.reachability.notificationName = kDefaultNetworkReachabilityChangedNotification;
self.reachability.onReachabilityChanged = ^(KSReachability *reachability) {
NSLog(#"isReachable: %i", reachability.reachable);
};
I always get isReachable: 1 there with the following configuration:
connected to Wifi
configured my iMac as HTTP-Proxy
blocking www.stackoverflow.com in my Charles Proxy
When I try to reach www.stackoverflow.com in Safari, the page can't be opened (as expected). I would expect the reachability to be false (isReachable: 0) in this case.
EDIT
So the most important question for me is - how to achieve the behavior I'm expecting? I.e. that the app continuously checks if the given host is really reachable?
The code statement:
self.reachability = [KSReachability reachabilityToHost:#"www.stackoverflow.com"];
actually calls below method:
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL,
[hostName UTF8String]);
SCNetworkReachability reference says:
The SCNetworkReachability programming interface allows an application
to determine the status of a system's current network configuration
and the reachability of a target host. A remote host is considered
reachable when a data packet, sent by an application into the network
stack, can leave the local device. Reachability does not guarantee
that the data packet will actually be received by the host.
The explanation clears that iOS system doesn't send any request to outside world to check the reachability. It just tells that data packet can leave the device or not. If system were to send the request it automatically means that it is connected to network.
You can verify this by mentioning a valid host like "www.stackoverflow.com" and check in charles (first unblock it) that no request is sent.You can also check with other valid host names like "www.abcdefgh.com" (verify this by running it in Safari and see in charles) it also gives you the reachability but charles shows no request.Also if you put http:// before any valid host, something like "http://www.stackoverflow.com" it will also fails reachability. So it is clear that it is not an outgoing http request. If system has to send a request outside then what's the point of providing the class? A developer could have created a network connection and try to connect to a host and see if it passes or fails.
However it is interesting that if an invalid host like "www.hjjkhkhk.com" is provided iOS system gives reachability as false. Now the question is how iOS system finds a valid or invalid host without sending any query to outside world? May be it is periodically caching a list of DNS ranges??? Highly improbable to me.
In your AppDelegate add this method:
#import "Reachability.h"
-(NSString *)checkNetworkConnectivity
{
NSString *networkValue;
Reachability *rc = [Reachability reachabilityWithHostName:#"www.stackoverflow.com"];
NetworkStatus internetStatus = [rc currentReachabilityStatus];
if(internetStatus==0)
{
networkValue = #"NoAccess";
}
else if(internetStatus==1)
{
networkValue = #"ReachableViaWiFi";
} else if(internetStatus==2)
{
networkValue = #"ReachableViaWWAN";
}
else
{
networkValue = #"Reachable";
}
return networkValue;
}
Checking if the host is reachable
NSString *netStr = [appDelegate checkNetworkConnectivity];
if([netStr isEqualToString:#"NoAccess"])
{
[appDelegate callNoNetworkAlert];
}
Firstly, unless we see some code, we cannot make sure what you're doing, you're doing the right way. However I will assume you are doing it correctly.
Secondly, you should test what FreeNickname has suggested in his comment. Maybe it's not actually unreachable, and the reachability is acting correctly, when you expect a different response.
Last, but very important, from the Reachability docs :
Note: Reachability cannot tell your application if you can connect to a particular host, only that an interface is available that might allow a connection, and whether that interface is the WWAN.
What it means is that, even though your server might not be returning any responses, Reachability does NOT check that. It only checks if your server is available , such that a packet can be sent. What it does with that packet is of no concern to Reachability. If Reachability is able to transmit the entire packet, it assumes your host is reachable. It will return unreachable iff your server is down, disconnected, or does not exist.
I would like to add that To listen the Network changes at Runtime, you need to listen to the Notifications that tell you that a Network state has been changed.
This is how you can do this :
Implement a listener in AppDelegate file.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityChanged:)
name:kReachabilityChangedNotification object:nil];
Now reachabilityChanged will be called when there is a change in Network status (perhaps connectivity of internet connection or it's disconnection). You can do appropriate handling in reachabilityChanged event
like:
- (void) reachabilityChanged:(NSNotification *)note
{
Reachability* reachability = [note object];
if (reachability == self.hostReachability)
{
isHostReachable = YES; //A flag to keep track of connectivity
}
if (reachability == self.internetReachability)
{
isInternetAvailable = YES;
}
if (reachability == self.wifiReachability)
{
isWifiAvailable = YES;
}
//If all are true that means we have host and Internet available
if (isHostReachable && isInternetAvailable && isWifiAvailable)
{
isInternetAvailable = true;
}
}
Hope this will help you.
AFNetworking
A delightful iOS and OS X networking framework
http://afnetworking.com
Network Reachability Manager
AFNetworkReachabilityManager monitors the reachability of domains, and addresses for both WWAN and WiFi network interfaces.
Shared Network Reachability
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status)
{
NSLog(#"Reachability: %#", AFStringFromNetworkReachabilityStatus(status));
}];
HTTP Manager Reachability
NSURL *baseURL = [NSURL URLWithString:#"http://example.com/"];
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseURL];
NSOperationQueue *operationQueue = manager.operationQueue;
[manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status)
{
switch (status)
{
case AFNetworkReachabilityStatusReachableViaWWAN:
case AFNetworkReachabilityStatusReachableViaWiFi:
[operationQueue setSuspended:NO];
break;
case AFNetworkReachabilityStatusNotReachable:
default:
[operationQueue setSuspended:YES];
break;
}
}];

Intercepting phone call - iPhone (correct method to hook in CoreTelephony)

I am new to the jailbreak tweak development scene. I am trying to figure out the appropriate method to 'hook' so I can intercept an incoming call (and then run some code).
I have dumped the header files of CoreTelephony framework however no methods seem obvious to hook. I have tried:
- (void)broadcastCallStateChangesIfNeededWithFailureLogMessage:(id)arg1;
- (BOOL)setUpServerConnection;
but neither have worked. By worked I mean - get called when the iPhone receives a call.
Any pointers as to the appropriate method to hook? Thanks :)
Note:
This is going to be a jailbreak tweak using private APIs so it won't be submitted to the App Store.
I didn't test your code, but I think your problem might be that you need to use the Core Telephony notification center to register for that event (not what you had in the code in your comment). Something like this:
// register for all Core Telephony notifications
id ct = CTTelephonyCenterGetDefault();
CTTelephonyCenterAddObserver(ct, // center
NULL, // observer
telephonyEventCallback, // callback
NULL, // event name (or all)
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
and your callback function is
static void telephonyEventCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
NSString *notifyname = (NSString*)name;
if ([notifyname isEqualToString:#"kCTCallIdentificationChangeNotification"])
{
NSDictionary* info = (NSDictionary*)userInfo;
CTCall* call = (CTCall*)[info objectForKey:#"kCTCall"];
NSString* caller = CTCallCopyAddress(NULL, call);
if (call.callState == CTCallStateDisconnected)
{
NSLog(#"Call has been disconnected");
}
else if (call.callState == CTCallStateConnected)
{
NSLog(#"Call has just been connected");
}
else if (call.callState == CTCallStateIncoming)
{
NSLog(#"Call is incoming");
}
else if (call.callState == CTCallStateDialing)
{
NSLog(#"Call is Dialing");
}
else
{
NSLog(#"None of the conditions");
}
}
}
I offer another technique in this similar question here. Also, note my comment in that question about not getting the notifications in a UIApplication that has been put into the background.
Update: see cud_programmer's comment below about using kCTCallStatus on iOS 6 instead of kCTCall.
Is it possible?
Yes.
Would a regular average person with no background in computer engineering or knowhow of how cell towers work be capable of something like this?
No.
Technically you can buy router looking thing to do this which aren’t cheap, are illegal and cellphone companies can actually track them down since it interferes with the network. So other than government agencies or international spies i don’t think you have anything to worry about. But if the government is exactly what you’re worried about well I’m sorry to tell you they’ve been doing a lot more then intercepting just phones

How can I catch EPIPE in my NSFIleHandle handling?

I'm having a problem with EPIPE in my iOS app, and it's not being caught in the #try/#catch/#finally block. How can I catch this signal (SIGPIPE, likely)...
I've built a "web proxy" into my app that will handle certain kinds of URLs - in this error case, it seems that the remote end (also in my app, but hiding in the iOS libraries) closes its end of the socket. I don't get a notification (should I? Is there something I should register for with the NSFileHandle that might help here?).
I've based this proxy on HTTPServer that Matt Gallagher put together (available here), and the problem is in a subclass of the HTTPRequestHandler class he put together. Here's the code (this code is the equivalent of the startResponse method in the base class):
-(void)proxyTS:(SSProxyTSResource *)proxyTS didReceiveResource:(NSData *)resource
{
NSLog(#"[%# %#]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
CFHTTPMessageRef response =
CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1);
CFHTTPMessageSetHeaderFieldValue(response,
(CFStringRef)#"Content-Type",
(__bridge CFStringRef)s_MIMEtype);
CFHTTPMessageSetHeaderFieldValue(response,
(CFStringRef)#"Connection",
(CFStringRef)#"close");
CFHTTPMessageSetBody(response,
(__bridge CFDataRef)resource);
CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response);
#try
{
NSLog(#" -> writing %u bytes to filehandle...",[((__bridge NSData *)headerData) length]);
[self.fileHandle writeData:(__bridge NSData *)headerData];
}
#catch (NSException *exception)
{
// Ignore the exception, it normally just means the client
// closed the connection from the other end.
}
#finally
{
NSLog(#" *ding*");
CFRelease(headerData);
CFRelease(response);
[self.server closeHandler:self];
}
}
And here's what shows up in the console log when it crashes:
Jan 15 14:55:10 AWT-NoTouch-iPhone-1 Streamer[1788] <Warning>: [SSProxyTSResponseHandler proxyTS:didReceiveResource:]
Jan 15 14:55:10 iPhone-1 Streamer[1788] <Warning>: -> writing 261760 bytes to filehandle...
Jan 15 14:55:11 iPhone-1 com.apple.launchd[1] (UIKitApplication:com.XXX.Streamer[0xf58][1788]) <Warning>: (UIKitApplication:com.XXX.Streamer[0xf58]) Exited abnormally: Broken pipe: 13
It seems that because the other end closed the pipe the write() fails, so if someone can point me at how I can either discover that it's already closed and not try to write data to it OR whatever will make it not crash my program that would be very helpful.
The immediate problem of crashing with SIGPIPE is solved. I'm not entirely giggly about this solution, but at least the app doesn't crash. It's not clear that it's working 100% correctly, but it does seem to be behaving quite a bit better.
I've resolved this issue by examining further what's going on. In doing some research, I found that perhaps I should be using NSFileHandle's writeabilityHandler property to install a block to do the writing. I'm not fully sold on that approach (it felt convoluted to me), but it might help.
Writability-handler solution:
In doing some web searching on writeabilityHandler, I stumbled on Bert Leung's blog entry on some issues he was having in a similar area. I took his code and modified it as follows, replacing the #try/#catch/#finally block above with this code:
self.pendingData = [NSMutableData dataWithData:(__bridge NSData *)(headerData)];
CFRelease(headerData);
CFRelease(response);
self.fileHandle.writeabilityHandler = ^(NSFileHandle* thisFileHandle)
{
int amountSent = send([thisFileHandle fileDescriptor],
[self.pendingData bytes],
[self.pendingData length],
MSG_DONTWAIT);
if (amountSent < 0) {
// errno is provided by system
NSLog(#"[%# %#] Error while sending response: %d", NSStringFromClass([self class]), NSStringFromSelector(_cmd), errno);
// Setting the length to 0 will cause this handler to complete processing.
self.pendingData.length = 0;
} else {
[self.pendingData replaceBytesInRange:NSMakeRange(0, amountSent)
withBytes:NULL
length:0];
}
if ([self.pendingData length] == 0) {
thisFileHandle.writeabilityHandler = nil;
// Hack to avoid ARC cycle with self. I don't like this, but...
[[NSNotificationCenter defaultCenter] postNotification:self.myNotification];
}
};
That worked fine but it didn't solve the problem. I was still getting SIGPIPE/EPIPE.
SIGPIPE be gone!
This wasn't a surprise, exactly, as this does pretty much the same thing as the former writeData: did but does it using send() instead. The key difference though is that using send() allows errno to be set. This was quite helpful, actually - I was getting a couple of error codes (in errno), such as 54 (Connection reset by peer) and 32 (Broken pipe). The 54's were fine, but the 32's resulted in the SIGPIPE/EPIPE. Then it dawned on me - perhaps I should just ignore SIGPIPE.
Given that thought, I added a couple of hooks into my UIApplicationDelegate in application:didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[self installSignalHandlers];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
...
and applicationWillTerminate::
- (void)applicationWillTerminate:(UIApplication *)application
{
// Saves changes in the application's managed object context before the application terminates.
[self removeSignalHandlers];
[self saveContext];
}
-(void)installSignalHandlers
{
signal(SIGPIPE,SIG_IGN);
}
-(void)removeSignalHandlers
{
signal(SIGPIPE, SIG_DFL);
}
Now at least the app doesn't crash. It's not clear that it's working 100% correctly, but it does seem to be behaving.
I also switched back to the #try/#catch/#finally structure because it's more direct. Further, after ignoring SIGPIPE, the #catch block does get triggered. Right now, I'm logging the exception, but only so I can see that it's working. In the released code, that log will be disabled.

Resources