Client not discovering bonjour service - iphone

I have just started learning to design iphone apps and I am trying to set up a client server environment. As a starter I would like to first make sure that the service I publish is visible to the client. I have written server and client codes wit help from Apple's Docs. However I find that though my service is getting published (netServiceWillPublish(NSNetService *)sender is called), my client is not identifying this service. At the client's side the delegate function netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser is called making me believe that the client is searching for the service. However the didFindService delegate function is never called. i am stumped as to why this is not working. I have followed the sample codes for the client side from various places and my code matches theirs. Some help on this would be greatly appreciated
Also I have the following questions
Can the service name (that comes along with the transport level protocol) be any string? Or does it have to be specified in http://www.dns-sd.org/ServiceTypes.html. Also what purpose does this solve apart from service discovery.
When I print out the details of the NSNetService object at the server's side (After setting up the socket and starting the service) the hostname is printed as (null) and there are no addresses being displayed. technically when a service is opened shouldn't these be set to values? If yes could someone please tell me where I am going wrong in my code?
I have attached the client and server code blocks of my project where the publishing and browsing of servicing is done. Help is extremely appreciated as I am stuck in my work with this issue.
This is the code snippet at the client side that browses for the services
NSNetServiceBrowser *serviceBrowser;
serviceBrowser = [[NSNetServiceBrowser alloc] init];
[serviceBrowser setDelegate:self];
[serviceBrowser searchForServicesOfType:#"_http._tcp." inDomain:#"local."];
This is the code snippet at the server side that publishes the service
BOOL success;
int fd;
int err;
int junk;
struct sockaddr_in addr;
NSInteger port;
port = 0;
fd = socket(AF_INET, SOCK_STREAM, 0);
success = (fd != -1);
if(success) {
memset(&addr, 0, sizeof(addr));
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr.s_addr = INADDR_ANY;
err = bind(fd, (const struct sockaddr*) &addr, sizeof(addr));
success = (err == 0);
}
if (success) {
err = listen(fd, 5);
success = (err == 0);
}
if (success) {
socklen_t addrLen;
addrLen = sizeof(addr);
err = getsockname(fd, (struct sockaddr *) &addr, &addrLen);
success = (err == 0);
if (success) {
assert( addrLen = sizeof(addr));
port = ntohs(addr.sin_port);
}
}
if (success) {
CFSocketContext context = { 0, (__bridge void *) self, NULL, NULL, NULL };
assert(self->_listeningSocket == NULL);
self->_listeningSocket = CFSocketCreateWithNative(NULL, fd, kCFSocketAcceptCallBack, AcceptCallBack, &context);
success = (self->_listeningSocket != NULL);
if (success) {
CFRunLoopSourceRef rls;
fd = -1; //listeningSocket is now responsible for closing the socket
rls = CFSocketCreateRunLoopSource(NULL, self.listeningSocket, 0);
assert(rls != NULL);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
}
}
if (success) {
self.netService = [[NSNetService alloc] initWithDomain:#"local." type:#"_http._tcp." name:#"test" port:port];
success = (self.netService != nil);
}
if (success) {
self.netService.delegate = self;
[self.netService publishWithOptions:NSNetServiceNoAutoRename];
}
if (success) {
assert(port != 0);
[self serverDidStartOnPort:port];
}
else {
[self stopServer:#"Start Failed"];
if (fd != -1) {
junk = close(fd);
assert(junk == 0);
}
}
This is the code snippet that tells that the service is published and prints out the details of my NSSocket object
- (void)netServiceWillPublish:(NSNetService *)sender {
NSLog(#"This function is getting called");
NSLog(#"sender.name %#",sender.name);
NSLog(#"sender.addresses %#",sender.addresses);
NSLog(#"sender.domain %#",sender.domain);
NSLog(#"sender.hostname %#",sender.hostName);
NSLog(#"sender.type %#",sender.type);
NSLog(#"sender.port %d",sender.port);
}
Thanks
Vivek

Related

iphone socket disconnecting after 1 min

We have following code for connecting to our server. This is part of iPhone App.
Problem is that recv(CFSocketGetNative(inSocketRef), &length, sizeof(length), 0);
call returns 0 after exactly 60 sec. We are not sending anything from server. I want it to wait for data or disconnection (either server or client initiated). However, it always returns after 60 sec.
What am I doing wrong here?
void CallbackHandlerConnectionHandler(CFSocketRef inSocketRef, CFSocketCallBackType inType,
CFDataRef inAddress, const void *inData, void *inInfo)
{
ChatServerConnectionHandler *conHandler = (ChatServerConnectionHandler *)inInfo;
if([conHandler respondsToSelector:#selector(dataRecievedFromServer:)])
{
int res = 0;
SInt32 length;
res = recv(CFSocketGetNative(inSocketRef), &length, sizeof(length), MSG_PEEK);
if(0 >= res || (length < 0))
{
//Disconnect the connection, as some has occcured in the sockets..
[conHandler performSelector:#selector(errorEncountered)];
NSLog(#"Error occured in server!!");
return;
}
printf ("good data")
}
}
-(BOOL) connectToServer:(NSString *)ipAddress Port:(int)portNumber
{
connectionState = eConnectionEstablishInProgress;
self.threadStopped = NO;
CFRunLoopSourceRef source;
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *host;
host = gethostbyname([ipAddress cStringUsingEncoding:NSUTF8StringEncoding]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct timeval timeout;
if (sockfd < 0)
{
error("ERROR opening socket");
connectionState = eNoConnection;
return NO;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portNumber);
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8);
/* Creates a CFSocket object for a pre-existing native socket */
CFSocketContext socketContext={0,self,NULL,NULL,NULL};
socketRef = CFSocketCreateWithNative(kCFAllocatorDefault,
sockfd,
kCFSocketReadCallBack,
CallbackHandlerConnectionHandler,
&socketContext);
source = CFSocketCreateRunLoopSource(NULL, socketRef, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
CFRelease(source);
source = nil;
InstallSignalHandlers();
CFDataRef socketAddress;
socketAddress = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8 *)&serv_addr, sizeof(serv_addr), kCFAllocatorNull);
CFSocketError result=CFSocketConnectToAddress(socketRef, socketAddress, 0);
CFRelease(socketAddress);
if(kCFSocketSuccess == result)
{
//printf("Socket connection established");
self.serverRunning = YES;
connectionState = eConnectionEstablised;
NSLog(#"\nCall Connection accepted callback.");
if([delegate respondsToSelector:#selector(conectionEstablishedWithTheServer)])
{
[delegate performSelector:#selector(conectionEstablishedWithTheServer)];
}
}
else
{
//printf("Unable to create socket why???***");
connectionState = eNoConnection;
if(socketRef)
CFRelease(socketRef);
socketRef = nil;
return NO;
}
while(FALSE == self.threadStopped)
{
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, FALSE);
}
NSLog(#"\nOut of Server socket connection thread.");
self.serverRunning = NO;
if([delegate respondsToSelector:#selector(conectionFinishedWithServer)])
{
[delegate performSelector:#selector(conectionFinishedWithServer)];
}
if(socketRef)
{
if(CFSocketIsValid(socketRef))
CFSocketInvalidate(socketRef);
}
return YES;
}
This looks like a server problem - or rather functionality: closing inactive connections to keep enough free resources.
If you didn't write the server code try to contact the author.
The packet you mention [FIN, ACK] is a packet that closes your socket: you should check the IP adresses but the server is most probably the initiator of this packet.

CFStream IOS Socket communication

how can i clear an CFStream buffer?
Everytime i read from socket there is still data from an old request, i mean complete response to an old request not just a fragment of it.
Am i missing something ?
This is a function i use to initialize the connection:
-(void)openSocketConnection:(UInt32)port: (NSString *)host
{
NSString *hoststring = [[NSString alloc] initWithString:host];
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,(__bridge CFStringRef)hoststring ,
port,&_nnet_readStream,&_nnet_writeStream);
CFWriteStreamCanAcceptBytes(_nnet_writeStream);
CFWriteStreamSetProperty(_nnet_writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFReadStreamSetProperty(_nnet_readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
if(!CFWriteStreamOpen(_nnet_writeStream)) {
NSLog(#"Error Opening Write Socket");
}
if(!CFReadStreamOpen(_nnet_readStream)) {
NSLog(#"Error Opening Write Socket");
}
}
This is a function i use to read data from socket:
BOOL done = NO;
NSMutableString* result = [NSMutableString string];
while (!done)
{
if (CFReadStreamHasBytesAvailable(_nnet_readStream))
{
UInt8 buf[1024];
CFIndex bytesRead = CFReadStreamRead(_nnet_readStream, buf, 1024);
if (bytesRead < 0)
{
CFStreamError error = CFReadStreamGetError(_nnet_readStream);
NSLog(#"%#",error);
} else if (bytesRead == 0)
{
if (CFReadStreamGetStatus(_nnet_readStream) == kCFStreamStatusAtEnd)
{
done = YES;
}
} else
{
[result appendString:[[NSString alloc] initWithBytes:buf length:bytesRead encoding:NSUTF8StringEncoding]];
}
} else
{
done = YES;
}
}
You seem to assume that when you get data from the host on the other end it will always be available all in one go.
I don't know what the underlying protocol is, but in general it's entirely possible that the remote end will try and send 1600 bytes and that you'll get 1500 bytes but then have to wait a few milliseconds (or even seconds) for the next 100 bytes. Meanwhile CFReadStreamHasBytesAvailable would return false and so your code would set your done flag even though you haven't read all the data the server sent.

Async CFStream networking with runloop

I am trying to implement async tcp networking with runloop.
currently I manage to connect, but when I try to send something I get that -1 bytes have been written - but CFWriteStreamCopyError returns null.
code sample below, first function connects, second send a simple message.
any help will be appreciated, including random bug spotting (I am new to objective-c and to iphone development in general).
struct header
{
uint32_t length;
uint32_t type;
} header;
- (void) connect
{
NSLog(#"Attempting to (re)connect to %#:%d", m_host, m_port);
while(TRUE)
{
CFHostRef host = CFHostCreateWithName(kCFAllocatorDefault, (CFStringRef)m_host);
if (!host)
{
NSLog(#"Error resolving host %#", m_host);
[NSThread sleepForTimeInterval:5.0];
continue;
}
CFStreamCreatePairWithSocketToCFHost(kCFAllocatorDefault, host , m_port, &m_in, &m_out);
CFRelease(host);
if (!m_in)
{
NSLog(#"Error");
}
CFStreamClientContext context = {0, self,nil,nil,nil};
if (CFReadStreamSetClient(m_in, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, networkReadEvent, &context))
{
CFReadStreamScheduleWithRunLoop(m_in, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
}
if (CFWriteStreamSetClient(m_out, kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, networkWriteEvent, &context))
{
CFWriteStreamScheduleWithRunLoop(m_out, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
}
BOOL success = CFReadStreamOpen(m_in);
CFErrorRef error = CFReadStreamCopyError(m_in);
if (!success || (error && CFErrorGetCode(error) != 0))
{
NSLog(#"Connect error %s : %d", CFErrorGetDomain(error), CFErrorGetCode(error));
[NSThread sleepForTimeInterval:5.0];
}
else
{
NSLog(#"Connected");
break;
}
}
[self startSession];
}
- (void) startSession
{
struct header hh;
hh.type = RTR_CREATE_SESSION;
hh.length = 0;
CFIndex res = CFWriteStreamWrite(self.m_out, (const UInt8*)&hh, sizeof(hh));
NSLog(#"Written %d", res);
CFErrorRef error = CFWriteStreamCopyError(self.m_out);
if (error)
{
NSLog(#"Read error %s : %d", CFErrorGetDomain(error), CFErrorGetCode(error));
CFRelease(error);
}
}
figured it out, I forgot to open the write stream as well:
CFWriteStreamOpen(m_out);

Problem with close socket

I have a problem with my socket program.
I create the client program (my code is below)
I have a problem when i close the socket with the disconnect method.
CFSocketRef s;
-(void)CreaConnessione
{
CFSocketError errore;
struct sockaddr_in sin;
CFDataRef address;
CFRunLoopSourceRef source;
CFSocketContext context = { 0, self, NULL, NULL, NULL };
s = CFSocketCreate(
NULL,
PF_INET,
SOCK_STREAM,
IPPROTO_TCP,
kCFSocketDataCallBack,
AcceptDataCallback,
&context);
memset(&sin, 0, sizeof(sin));
int port = [fieldPorta.text intValue];
NSString *tempIp = fieldIndirizzo.text;
const char *ip = [tempIp UTF8String];
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = (long)inet_addr(ip);
address = CFDataCreate(NULL, (UInt8 *)&sin, sizeof(sin));
errore = CFSocketConnectToAddress(s, address, 0);
if(errore == 0){
buttonInvioMess.enabled = TRUE;
fieldMessaggioInvio.enabled = TRUE;
labelTemp.text = [NSString stringWithFormat:#"Connesso al Server"];
CFRelease(address);
source = CFSocketCreateRunLoopSource(NULL, s, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(),
source,
kCFRunLoopDefaultMode);
CFRelease(source);
CFRunLoopRun();
}
else{
labelTemp.text = [NSString stringWithFormat:#"Errore di connessione. Verificare Ip e Porta"];
switchConnection.on = FALSE;
}
}
//the socket doesn't disconnect
-(void)Disconnetti{
CFSocketInvalidate(s);
CFRelease(s);
}
-(IBAction)Connetti
{
if(switchConnection.on)
[self CreaConnessione];
else
[self Disconnetti];
}
If you're trying to reuse the socket which you have invalidated. I guess you cant use the same socket object again.
because once i remove invalidating socket from my code. the code works pretty good on every single time i try to make connection after disconnecting..

Very odd iPhone - Server problem

Essentially I'm sending data to a Java Socket Server from an iPhone app however something rather strange happens, it doesn't receive the data until the iPhone application is closed! I'm sure there is something I'm missing but I just can't seem to find it, it's all quite odd.
Here is how my connection is created:
-(CFSocketRef)initSocket {
CFSocketContext context = {
.version = 0,
.info = self,
.retain = NULL,
.release = NULL,
.copyDescription = NULL
};
sockety = CFSocketCreate(
kCFAllocatorDefault,
PF_INET,
SOCK_STREAM,
IPPROTO_TCP,
kCFSocketDataCallBack^kCFSocketConnectCallBack,
socketCallBack,
&context
);
uint16_t port = 4444;
struct sockaddr_in addr4;
memset(&addr4, 0, sizeof(addr4));
addr4.sin_family = AF_INET;
addr4.sin_len = sizeof(addr4);
addr4.sin_port = htons(port);
const char *ipaddress = "192.168.1.5";
inet_aton(ipaddress, &addr4.sin_addr);
NSData *address = [NSData dataWithBytes:&addr4 length:sizeof(addr4)];
CFSocketError error = CFSocketConnectToAddress(sockety, (CFDataRef)address, 1);
if(error != kCFSocketSuccess )
{
Faliure = YES;
}
else{
ViewNo = 2;
}
CFRunLoopSourceRef source;
source = CFSocketCreateRunLoopSource(NULL, sockety, 1);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
CFRelease(source);
return sockety;
}
Heres how the message is sent:
const char *sendStrUTF = [sentmessage UTF8String];
NSData *dataOut = [NSData dataWithBytes: sendStrUTF length: strlen(sendStrUTF)];
CFSocketSendData(sockety, NULL, (CFDataRef) dataOut, 0);
Any help would be greatly appreciated!
Thanks in advance,
Ozzie
Is your call to CFSocketSendData being done on a (blocked) GUI thread?
I would experiment with wrapping those 3 lines in a performSelectorInBackground / or after delay combinations.
NSData *dat=[stringToSend dataUsingEncoding:NSASCIIStringEncoding];
CFSocketError w =CFSocketSendData(_socket, NULL,(CFDataRef)dat, 0);
if (w==kCFSocketSuccess) {
NSLog(#"success");
}