NSStream not giving any data - ios

I'm trying to write telnet client on iOS and I can't set up streams correctly. I think that they work, but I am getting empty buffer each time I get delegate method triggered.
Here is how I set up streams:
self.manager = [[TelnetManager alloc] init];
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)[[NSURL URLWithString:#"arda.pp.ru"] host], 7000, &readStream, &writeStream);
NSInputStream *inputStream = (__bridge_transfer NSInputStream *)readStream;
NSOutputStream *outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[inputStream setDelegate:self.manager];
[outputStream setDelegate:self.manager];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
Here is the delegate method that is on manager that handles events:
-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
if (eventCode == NSStreamEventHasBytesAvailable) {
NSLog(#"We got some data over here");
if(!_data) {
_data = [NSMutableData data];
}
uint8_t buf[1024];
unsigned int len = 0;
len = [(NSInputStream *)aStream read:buf maxLength:1024];
NSLog(#"length - %d", len);
NSLog(#"buf:%s", buf);
if(len) {
[_data appendBytes:(const void *)buf length:len];
_bytesRead = #([_bytesRead intValue]+len);
} else {
NSLog(#"no buffer!");
}
}
}
It is getting fired, but buffer is always empty and "no buffer" is logged.
What's wrong with my code?

There actually is nothing wrong with your code. I have used it to connect to a telnet server and it worked fine.
In your code, "no buffer" is logged when len is 0, which means the buffer's end has been reached. In the case of a telnet server, this usually means that either the server disconnected your connection or the server quit.

Related

Handling errors in CFReadStream - Obj-C

How do I handle errors in a stream? If the user is connected to the wrong network I want to handle that. Thanks!
Code:
- (void)initNetworkCommunication {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"IP HERE", 7777, &readStream, &writeStream);
_inputStream = (NSInputStream *)CFBridgingRelease(readStream);
_outputStream = (NSOutputStream *)CFBridgingRelease(writeStream);
[_inputStream setDelegate:self];
[_outputStream setDelegate:self];
[_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_inputStream open];
[_outputStream open];
}
I figured out a solution that worked in my case. This code will print out the current network's BSSID in the console, and I simply check if the BSSID matches the one for my preferred network with an if-statement:
#import <SystemConfiguration/CaptiveNetwork.h>
//Checks which network the user is connected to.
CFArrayRef myArray = CNCopySupportedInterfaces();
CFDictionaryRef myDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray, 0));
NSLog(#"Connected at: %#", myDict);
NSDictionary *myDictionary = (__bridge_transfer NSDictionary*)myDict;
NSString * BSSID = [myDictionary objectForKey:#"BSSID"];
NSLog(#"BSSID is: %#", BSSID);
//Handling wrong/correct BSSID.
if (![BSSID isEqualToString:#"PREFERRED BSSID HERE"]) {
//Handle error however you want.
}
else {
//If correct BSSID, handle that here however you want.
}
}

How to send push notification using NSStream and APN certificate

I know there are tools available to send push notification that are implemented with php or C++ or something else. I am trying develop my own using NSStream. I have tried the following code.
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 80, &readStream, &writeStream);
NSInputStream *inputStream = (__bridge_transfer NSInputStream *)readStream;
NSOutputStream *outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
Delegate method:
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
NSLog(#"stream:handleEvent: is invoked...");
switch(eventCode) {
case NSStreamEventOpenCompleted:
// it is getting here
break;
case NSStreamEventHasSpaceAvailable:
{
if (stream == oStream) {
NSString * str = [NSString stringWithFormat:
#"{"aps":{"alert":"Hello from APN server.","badge":"1"}}"];
// how do i add device token
const uint8_t * payload =
(const uint8_t *)[str UTF8String];
[oStream write:payload maxLength:strlen(payload)];
[oStream close];
}
break;
}
}
}
Now the problems are:
How do I open the stream with a push certificate
How do I generate the payload with a device token

iOS app crashes after sending the first UIImage

I'm developing an application for iOS which is sharing its screen with another device through constant flow of screenshot images sent through TCP sockets connection.
Here's the code I'm written so far:
#implementation newClient {
NSData *data;
NSInputStream *iStream;
NSOutputStream *oStream;
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
BOOL boolean;
}
-(void) connectToServerUsingCFStream:(UIImage *) bitmap {
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
(CFStringRef) #"192.168.1.9",
8080,
&readStream,
&writeStream);
if (readStream && writeStream) {
CFReadStreamSetProperty(readStream,
kCFStreamPropertyShouldCloseNativeSocket,
kCFBooleanTrue);
CFWriteStreamSetProperty(writeStream,
kCFStreamPropertyShouldCloseNativeSocket,
kCFBooleanTrue);
iStream = (NSInputStream *)CFBridgingRelease(readStream);
[iStream setDelegate:self];
//[iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
// forMode:NSDefaultRunLoopMode];
[iStream open];
oStream = (NSOutputStream *)CFBridgingRelease(writeStream);
[oStream setDelegate:self];
[oStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[oStream open];
// data = UIImageJPEGRepresentation(bitmap, 50);
boolean = YES;
[self writeToServer:bitmap];
}
}
- (void) writeToServer:(UIImage *)bitmap {
dispatch_async(dispatch_get_main_queue(), ^{
#autoreleasepool {
NSData *data = UIImageJPEGRepresentation(bitmap, 50);
int len;
uint32_t length = (uint32_t)htonl([data length]);
// Sending out the length of the screenshot image and then the image
len=[oStream write:(const uint8_t *)&length maxLength:4];
NSLog(#"len=%d",len);
len=[oStream write:(const uint8_t *)[data bytes] maxLength:[data length]];
NSLog(#"len=%d",len);
//[oStream write:(const uint8_t *)"/n" maxLength:0];
}
});
}
#end
When I click the button which is activating this object in sends the first screenshot and then crashes giving me "Thread 1: EXC_BAD_ACCESS(code=1, address=0xd000000c) in the main.m file of my project.
The server application is running on Android and it's a thread which is constantly running in a loop.
I don't know what is causing the problem.

iOS: How to send image data periodically via socket?

I am able to connect my iOS program to a java based socket listener and get it connected well. iOS app is also able to send screen shot image data to the socket very well. This is done under NSStreamEventHasSpaceAvailable
My problem is, i do not know, how to send this screenshot image periodically to the socket. I am sending it just once now, its working. But, i want to keep sending this image data to socket one after another screenshot taken programmatically in every certain interval. How to do that? Please advise.
Please refer my complete code below.
-(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
NSString *io;
if (theStream == inputStream) io = #">>";
else io = #"<<";
NSString *event;
switch (streamEvent)
{
case NSStreamEventNone:
event = #"NSStreamEventNone";
//statusText.text = #"Can not connect to the host!";
NSLog(#"NSStreamEventNone - Can not connect to the host");
break;
case NSStreamEventOpenCompleted:
event = #"NSStreamEventOpenCompleted";
//pingButton.hidden = NO;
//statusText.text = #"Connected";
NSLog(#"Connected");
break;
case NSStreamEventHasBytesAvailable:
event = #"NSStreamEventHasBytesAvailable";
NSLog(#"NSStreamEventHasBytesAvailable called");
if (theStream == inputStream)
{
//read data
uint8_t buffer[1024];
int len;
while ([inputStream hasBytesAvailable])
{
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0)
{
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
NSData *theData = [[NSData alloc] initWithBytes:buffer length:len];
if (nil != output)
{
//do something with data
NSLog(#"NSStreamEventHasBytesAvailable theData: %#", theData);
}
}
}
}
break;
case NSStreamEventHasSpaceAvailable:
event = #"NSStreamEventHasSpaceAvailable";
NSLog(#"NSStreamEventHasSpaceAvailable called");
NSLog(#"space : %d",[outputStream hasSpaceAvailable]);
if (theStream == outputStream)
{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
UIGraphicsBeginImageContext(appDelegate.window.bounds.size);
[appDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
[data writeToFile:#"screenshot.png" atomically:YES];
int num = [outputStream write:[data bytes] maxLength:[data length]];
if (-1 == num) {
NSLog(#"Error writing to stream %#: %#", outputStream, [outputStream streamError]);
}else{
NSLog(#"Wrote %i bytes to stream %#.", num, outputStream);
//[outputStream close];
}
}
break;
case NSStreamEventErrorOccurred:
event = #"NSStreamEventErrorOccurred";
//statusText.text = #"Can not connect to the host!";
//pingButton.hidden = YES;
NSLog(#"NSStreamEventErrorOccurred - Can not connect to the host");
break;
case NSStreamEventEndEncountered:
event = #"NSStreamEventEndEncountered";
//statusText.text = #"Connection closed by the server.";
//pingButton.hidden = YES;
NSLog(#"NSStreamEventEndEncountered - Connection closed by the server");
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
//[theStream release];
theStream = nil;
break;
default:
event = #"** Unknown";
}
NSLog(#"%# : %#", io, event);
}
Under a Button click, the below code is for connecting the host initially.
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"localhost", 8080, &readStream, &writeStream);
inputStream = (__bridge_transfer NSInputStream *)readStream;
outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);

iOS socket programming - receiving nsstream event 4

I am using a device called a WiFly that has ip address:169.254.1.1 and port 2000. I am trying to connect to this device via an iOS application. I use the following code to connect:
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
UInt32 port = 2000;
CFStringRef host = CFSTR("169.254.1.1");
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, &readStream, &writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
// set the delegates to this view controller
[inputStream setDelegate:self];
[outputStream setDelegate:self];
// Set run loops to continuous receive information
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
// Finally, open the connection
[inputStream open];
[outputStream open];
Then I use the following to handle stream events:
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
NSLog(#"stream event %i", streamEvent);
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream) {
uint8_t buffer[1024];
int len;
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
if (nil != output) {
NSLog(#"server said: %#", output);
[self messageReceived:output];
}
}
}
}
break;
case NSStreamEventErrorOccurred:
NSLog(#"Can't connect to server");
break;
case NSStreamEventEndEncountered:
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
break;
default:
NSLog(#"Unknown event");
}
So, I can see that the first two streams are opened correctly. Then it follows immediately with a stream event 4, which from my understanding is to be expected. However, I then try to call a function:
- (IBAction)moveForward
{
NSLog(#"move forward called");
NSString *response = [NSString stringWithFormat:#"2"];
NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
[outputStream write:[data bytes] maxLength:[data length]];
}
Which should return "forward" from an arduino uno via the wifly. However, when I click, I get another NSStreamEvent 4 for some reason. I also telnetted in to the device via the terminal with:
telnet 169.254.1.1 2000
and subsequently type a "2"... This returned the desired "forward" immediately. What am I doing wrong from the perspective of the iPad?
Help is much appreciated!
EDIT For some reason, everytime the handler is accessed, the stream that is passed is the output stream, which is completely wrong... Why wouldn't the input stream ever be passed through?
And here is the arduino code:
void loop()
{ while (Serial.available() > 0) {
int next = Serial.parseInt();if(Serial.available() > 0)
{
if(next == 20) {
Serial.println("leftMove");
}}}}

Resources