GCDAsyncSocket not releasing port - ios

I'm using the following code:
_broadcastReceiveSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:_broadcastHandler delegateQueue:_broadcastQueue];
BOOL successfulStart = [_broadcastReceiveSocket bindToPort:BROADCAST_PORT error:error]
&& [_broadcastReceiveSocket joinMulticastGroup:BROADCAST_HOST error:error]
&& [_broadcastReceiveSocket beginReceiving:error];
To start a socket listening for UDP broadcasts.
But I can only seem to run this code once in the simulator. After that I get an error back saying "Address already is use" from the bindToPort command.
The only way I have found so far to fix this is to reboot the machine. Which from a developers point of view is totally impractical.
I have had this working just fine. Any ideas what could have changed?

You have to close the socket (or destroy it completely) by sending it the close message.

Related

GRPC IOS Client Connection Lost -Objective C

For the IOS App the connection works , but after the phone is idle for a while , the connection is lost, as such the RPC calls hangs, without any response.
I had the same issue in JAVA, there I added a DeadLine and rebuilt the channel when the Deadline Exceeded, something like below.
stub.withDeadlineAfter(timeout, TimeUnit.MILLISECONDS).execute(input, new StreamObserver<AgentGuardStringResponse>() { ... }
Then on error (deadline exceeded)
mChannel.shutdown();
This works fine.
For objective-c/ios
I set a time out for the RPC calls as so
[call setTimeout:timeout];
call.requestHeaders[#"sessionId"] = sessionId;
[call start];
And Try to rebuild ,
_serviceClient = [[AgentGuardService alloc] initWithHost:GRPCMetadata.shared.uri];
This does not seem to work as the app stays idle for a while after starting and eventually the Requests start flowing through.
Any pointers/guides will be highly helpful.
Thanks

Peer2Peer CouchbaseListener

I am working on peer to peer replication in CouchbaseLite using CouchbaseListener. I am unable to find the peers.
Here is the code which i follow,
Note: Assue that all self. properties are available
Here is my listener code
CBLManager *cblManager = [CBLManager sharedInstance];
self.dbListener = [[CBLListener alloc] initWithManager:cblManager port:0];
[self.dbListener setBonjourName:[[UIDevice currentDevice] name]
type:#"_ashok._tcp."];
[self.dbListener setTXTRecordDictionary:[NSDictionary dictionaryWithObject:DBNAME
forKey:#"dataBasePath"]];
NSError *error;
BOOL status = [self.dbListener start:&error];
if (status) {
dblPort = dbListener.port;
} else {
NSLog(#"CBLListener is not started: %#", error.localizedDescription);
}
started browsing the peers
self.serviceBrowser = [[NSNetServiceBrowser alloc] init];
self.serviceBrowser.includesPeerToPeer = YES;
self.serviceBrowser.delegate = self;
[self.serviceBrowser searchForServicesOfType:_ashok._tcp. inDomain:#"local."];
[self.serviceBrowser scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
But i am unable to find the peers.
I had turn on both wifi & bluetooth on both the devices. Both are not connected to any network.
Scenarios i have tested:
Bluetooth & Wifi is turned on both the devices, but both are not connected to any network.
Bluetooth & Wifi is turned on both the devices, and both are connected to same network.
In both scenarios I am unable to find the nearby peer.
After crawling many forums, i've just managed to get peer 2 peer work on iOS. So i'll just post all the things that helped me (note : i call the host that has the listener running the "server" and the other one the "client" for simplicity purpose).
First, turn on logging. You can do that by adding "-Log YES" and "-LogSyncVerbose YES" on Arguments passed on Launch (in the Edit Scheme => Run MyApp => Arguments)
Then, you need to get the Listener service to successfully advertise itself using Bonjour. You can download iphone Apps on the app store that displays all the services available in your local network and check that the name you chose for the service can be seen.
Then, on the "client" side you have to use NSNetServiceBrowser to browse for the service, then once the service is found use [NSNetService resolveWithTimeout] method to resolve the host. Then and only then can you build the replication using nsnsetservice hostname and port. Otherwise, those will be nil.
Finally once you managed to connect your "client" to the "server", i suggest trying to make the replication work without any credential (no "login / password" at all) because it doesn't seem to be properly working and cause various network error, such as connexion terminating in the middle of the synchronization (even on version 1.0.2).
Hope this helped. A very useful thread to help you :
https://groups.google.com/forum/#!searchin/mobile-couchbase/p2p/mobile-couchbase/oFGn1zybDcE/7BE3vFXh9xoJ

Blackberry's WLANInfo.getWLANState() Doesn't Return Correct Information

I'm working with the NetworkUtils.java class created by Sameer Nafdey in his blog post regarding accuiring a network connection within a Blackberry Application. However I recently noticed that my application was using the cell network even when a WiFi connection was available. I realized this was the case when we tested the application on a Torch with no SIM card and the app failed. After some debugging I found that:
if (WLANInfo.getWLANState() == WLANInfo.WLAN_STATE_CONNECTED){...}
was returning false despite the fact that the WiFi network was setup correctly (I was able to use web browser to visit Google). We had to return the Torch but while debugging the app in the simulator I noticed that if WiFi was on but the Data Network was turned off then this call would work correctly. However I would then get an exception (java.io.ioexception: Radio is off) when executing this block:
httpConnector = (HttpConnection)Connector.open(URL);
httpConnector.setRequestMethod(HttpConnection.GET);
httpConnector.setRequestProperty("Content-Type", "text/plain; charset=UTF-8");
in = httpConnector.openInputStream();
I've seen a lot of issues related to the Torch's WiFi connectivity problems but I'm currently concerned that this behavior may also be affecting other models. Anyone seen anything like this or have an idea of how to fix it?
You could try:
if( RadioInfo.areWAFsSupported( RadioInfo.WAF_WLAN )
&&
( RadioInfo.getActiveWAFs() & RadioInfo.WAF_WLAN ) != 0
&&
CoverageInfo.isCoverageSufficient( 1 , RadioInfo.WAF_WLAN, false) )
{ ... }
It's been working so far, on Blackberry OS 6.0 (Torch 9800). Tested on device and sim.

Ruby, SSLSockets, and Apple's Enhanced APN message format

I'm trying to implement support for Apple's enhanced Push Notification message format in my Rails app, and am having some frustrating problems. I clearly don't understand sockets as much as I thought I did.
My main problem is that if I send all messages correctly, my code hangs, because socket.read will block until I receive a message. Apple doesn't return anything if your messages looked OK, so my program locks up.
Here is some pseudocode for how I have this working:
cert = File.read(options[:cert])
ctx = OpenSSL::SSL::SSLContext.new
ctx.key = OpenSSL::PKey::RSA.new(cert, options[:passphrase])
ctx.cert = OpenSSL::X509::Certificate.new(cert)
sock = TCPSocket.new(options[:host], options[:port])
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
ssl.sync = true
ssl.connect
messages.each do |message|
ssl.write(message.to_apn)
end
if read_buffer = ssl.read(6)
process_error_response(read_buffer)
end
Obviously, there are a number of problems with this:
If I'm sending messages to a large number of devices, and the failure message is sent half way through processing, then I'm not going to actually see the error until I've already tried to send to all devices.
As mentioned earlier, if all messages were acceptable to Apple, my app will hang on the socket read call.
One way I've tried to solve this is by to reading from the socket in a separate thread:
Thread.new() {
while data = ssl.read(6)
process_error_response(data)
end
}
messages.each do |message|
ssl.write(message.to_apn)
end
ssl.close
sock.close
This doesn't seem to work. Data never seems to be read from the socket. This is probably a misunderstanding I have about how sockets are supposed to work.
The other solution I have thought of is having a non-blocking read call... but it doesn't seem like Ruby has a non blocking read call on SSLSocket until 1.9... which I unfortunately cannot use right now.
Could someone with a better understanding of socket programming please point me in the right direction?
cam is correct: the traditional way to handle this situation is with IO.select
if IO.select([ssl], nil, nil, 5)
read_buffer = ssl.read(6)
process_error_response(read_buffer)
end
This will check ssl for "readability" for 5 seconds and return ssl if it's readable or nil otherwise.
Can you use IO.select? It lets you specify a timeout, so you could at limit the amount of time you block. See the spec for details: http://github.com/rubyspec/rubyspec/blob/master/core/io/select_spec.rb
I'm interested in this too, this is another approach, unfortunately with it's own flaws.
messages.each do |message|
begin
// Write message to APNS
ssl.write(message.to_apn)
rescue
// Write failed (disconnected), read response
response = ssl.read(6)
// Unpack the binary response and print it out
command, errorCode, identifier = response.unpack('CCN');
puts "Command: #{command} Code: #{errorCode} Identifier: #{identifier}"
// Before reconnecting, the problem (assuming incorrect token) must be solved
break
end
end
This seems to work, and since I'm keeping a persistent connection, I can without problems reconnect in the rescue code and start over again.
There are some issues though. The main problem I'm looking to solve is disconnects caused by sending in incorrect device tokens (for example from development builds). If I have 100 device tokens that I send a message to, and somewhere in the middle there is an incorrect token, my code lets me know which one it was (assuming I supplied good identifiers). I can then remove the faulty token, and send the message to all devices that appeared after the faulty one (since the message didn't get sent to them). But if the incorrect token is somewhere in the end of the 100, the rescue doesn't happen until the next time I send messages.
The problem seams to be that the code isn't really in real time. If I were to send in, say, 10 messages to 10 incorrect tokens with this code, everything would be just fine, the loop will go through and no problems will be reported. It seems that write() doesn't wait for everything to clear up, and the loops runs through before the connection is terminated. The next time the loop will be run, the write() command fails (since we've actually been disconnected since the last time) and we would get the error.
If there is an alternative way to respond to the failed connection, this could solve the problem.
There is a simple way. After you write your messages, try reading in nonblocking mode:
ssl.connect
ssl.sync = true # then ssl.write() flushes immediately
ssl.write(your_packed_frame)
sleep(0.5) # so APN have time to answer
begin
error_packet = ssl.read_nonblock(6) # Read one packet: 6 bytes
# If we are here, there IS an error_packet which we need to process
rescue IO::WaitReadable
# There is no (yet) 6 bytes from APN, probably everything is fine
end
I use it with MRI 2.1 but it should work with earlier versions too.

MQ Connection - 2009 error

am connectting the MQ with below code. I am able connected to MQ successfully. My case is i place the messages to MQ every 1 min once. After disconnecting the cable i get a ResonCode error but IsConnected property still show true. Is this is the right way to check if the connection is still connected ? Or there any best pratcices around that.
I would like to open the connection when applicaiton is started keep it open for ever.
public static MQQueueManager ConnectMQ()
{
if ((queueManager == null) || (!queueManager.IsConnected)||(queueManager.ReasonCode == 2009))
{
queueManager = new MQQueueManager();
}
return queueManager;
}
The behavior of the WMQ client connection is that when idle it will appear to be connected until an API call fails or the connection times out. So isConnected() will likely report true until a get, put or inquire call is attempted and fails, at which point QMgr will then report disconnected.
The other thing to consider here is that 2009 is not the only code you might get. It happens to be the one you get when the connection is severed but there are connection codes for QMgr shutting down, channel shutting down, and a variety of resource and other errors.
Typically for a requirement to maintain a constant connection you would want to wrap the connect and message processing loop inside a try/catch block nested inside a while statement. When you catch an exception other than an intentional exit, close the objects and QMgr, sleep at least 5 seconds, then loop around to the top of the while. The sleep is crucial because if you get caught in a tight reconnect loop and throw hundreds of connection attempts at the QMgr, you can bring even a mainframe QMgr to its knees.
An alternative is to use a v7 WMQ client and QMgr. With this combination, automatic reconnection is configurable as a channel configuration.

Resources