Dispatch source is only called when I do a NSLog() first - iphone

I am trying to use grand central dispatch in conjunction with bsd sockets to send an icmp ping. I add DISPATCH_SOURCE_TYPE_WRITE and DISPATCH_SOURCE_TYPE_READ as dispatch sources to read and write async.
So this is the method were I create the bsd socket and install the dispatch sources:
- (void)start
{
int err;
const struct sockaddr * addrPtr;
assert(self.hostAddress != nil);
// Open the socket.
addrPtr = (const struct sockaddr *) [self.hostAddress bytes];
fd = -1;
err = 0;
switch (addrPtr->sa_family) {
case AF_INET: {
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (fd < 0) {
err = errno;
}
} break;
case AF_INET6:
assert(NO);
// fall through
default: {
err = EPROTONOSUPPORT;
} break;
}
if (err != 0) {
[self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]];
} else {
dispatch_source_t writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_event_handler(writeSource, ^{
abort(); // testing
// call call method here to send a ping
});
dispatch_resume(writeSource);
//NSLog(#"testout");
dispatch_source_t readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_event_handler(readSource, ^{
unsigned long bytesAvail = dispatch_source_get_data(readSource);
NSLog(#"bytes available: %lu", bytesAvail);
});
dispatch_resume(readSource);
}
}
You see the //NSLog(#"testout");? The funny thing is that the write block is only called when the //NSLog(#"testout"); is NOT commented out. This is very odd. I didn't test the read callback. The sending needs to be working first.
So what is going on here?

There are kind of a bunch of things missing here. I'm not sure exactly which one is causing the weird behavior, but when I do all of the missing things, it seems to work "as expected" and my write event handler is called reliably and repeatedly. In general, there are a bunch of things you need to do when setting up a socket like this before passing it off to GCD. They are:
Create the socket
Bind it to a local address (missing in your code)
Set it to non-blocking (missing in your code)
Here is a little example I was able to put together in which the write handler gets called repeatedly, as expected:
int DoStuff()
{
int fd = -1;
// Create
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("cannot create socket");
return 0;
}
// Bind
struct sockaddr_in *localAddressPtr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
memset((char *)localAddressPtr, 0, sizeof(*localAddressPtr));
localAddressPtr->sin_family = AF_INET;
localAddressPtr->sin_addr.s_addr = htonl(INADDR_ANY);
localAddressPtr->sin_port = htons(0);
if (bind(fd, (struct sockaddr *)localAddressPtr, sizeof(*localAddressPtr)) < 0) {
perror("bind failed");
return 0;
}
// Set non-blocking
int flags;
if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
flags = 0;
if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
{
perror("Couldnt set non-blocking");
return 0;
}
// Do a DNS lookup...
struct hostent *hp;
struct sockaddr_in *remoteAddressPtr = malloc(sizeof(struct sockaddr_in));
// Fill in the server's address and data
memset((char*)remoteAddressPtr, 0, sizeof(*remoteAddressPtr));
remoteAddressPtr->sin_family = AF_INET;
remoteAddressPtr->sin_port = htons(12345);
// Look up the address of the server by name
const char* host = "www.google.com";
hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "could not obtain address of %s\n", host);
return 0;
}
// Copy the host's address into the remote address structure
memcpy((void *)&remoteAddressPtr->sin_addr, hp->h_addr_list[0], hp->h_length);
dispatch_source_t writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_event_handler(writeSource, ^{
// Send message
const char* my_message = "the only thing we have to fear is fear itself.";
unsigned long len = strlen(my_message);
if (sendto(fd, my_message, len, 0, (struct sockaddr *)remoteAddressPtr, sizeof(*remoteAddressPtr)) != len) {
perror("sendto failed");
dispatch_source_cancel(writeSource);
}
});
dispatch_source_set_cancel_handler(writeSource, ^{
close(fd);
free(localAddressPtr);
free(remoteAddressPtr);
});
dispatch_resume(writeSource);
return 1;
}
NB: There's no way to dispose of the writeSource in my example without there being an error in a send operation. It's a trivial example...
My general theory on why NSLog triggers the handler to fire in your case, is that it keeps execution at or below that stack frame long enough for the background thread to come around and call the handler, but without that NSLog, your function returns, and something has a chance to die before the handler can get called. In fact, if you're using ARC it's probably the writeSource itself that is getting deallocated, since I don't see you making a strong reference to it anywhere outside the scope of this function. (My example captures a strong reference to it in the block, thus keeping it alive.) You could test this in your code by stashing a strong reference to writeSource.

I found the error:
In newer SDKs dispatch sources are subject to automatic reference counting despite the fact that they are no Objective-C objects.
So when the start method is over ARC disposes the dispatch source and they never get called.
NSLog delays the end of the start method in a way that the dispatch source triggers before the source gets disposed.

Related

recvfrom returning errno 14 in debug mode with GDB

I have a code something like this.
where recvfrom works fine if i run the code normally. but when i run the code with GDB, recvfrom doesn't wait for 2 seconds and instantly throwing errno 14.
==
char buf[sizeof(FSME_START)] = { 0 };
/* open socket */
fsm_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fsm_fd < 0)
{
perror("socket");
exit(1);
}
const struct sockaddr_in remote_addr = { .sin_family = AF_INET };
//socklen_t addrlen = sizeof(struct sockaddr);
socklen_t addrlen = sizeof(client_addr);
struct timeval tv = { .tv_sec = 2,
.tv_usec = 0};
/* set initial 1s recv timeout */
int ret = setsockopt(fsm_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
if (ret < 0)
{
perror("setsockopt");
exit(1);
}
while (1)
{
const struct iovec iov = { .iov_base = (void*)FSME_START,
.iov_len = sizeof(FSME_START) };
// Send the START packet (once/sec) to the FSM-E until we get
// receive a START message back based on 1sec timeout set above.
fsm_dp_send(&iov,1,0);
ret = recvfrom(fsm_fd, (char *)buf, MAX_BUFSIZE,
MSG_WAITALL, (struct sockaddr *)&client_addr, &addrlen);
====
I tried passing client_addr and addrlen both parameters as NULL but no success. But strangely this code works if run without GDB.
Any suggestions
looks like there is an error with the size of msg i was passing with recvfrom but it was weird that one version of gdb and and even compiler was hiding this error. This error was visible only with older gdb version. Later on when i passed the correct size of the buffer, it was passing.

is there a working vmci example?

I need a working VMCI socket example that does what UDP does, but without networking. There are many good code fragments in the vmci_sockets.h code, but not a full working template to expand on.
I believe that the server should look as follows:
#include "vmci_sockets.h"
#define BUFSIZE 2048
int main() {
int afVMCI = VMCISock_GetAFValue();
if ((sockfd_dgram = socket(afVMCI, SOCK_DGRAM, 0)) == -1) {
perror("socket");
goto exit;
}
struct sockaddr_vm my_addr = {0};
my_addr.svm_family = afVMCI;
my_addr.svm_cid = VMADDR_CID_ANY;
my_addr.svm_port = VMADDR_PORT_ANY;
if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof my_addr) == -1) {
perror("bind");
goto close;
}
if (getsockname(sockfd, (struct sockaddr *) &my_addr, &svm_size) == -1) {
perror("getsockname");
goto close;
}
if ((numbytes = recvfrom(sockfd, buf, sizeof buf, 0,
(struct sockaddr *) &their_addr, &svm_size)) == -1) {
perror("recvfrom");
goto close;
}
close:
return close(sockfd);
}
and for the client
#include <stdio.h>
#include <string.h>
#include "vmci_sockets.h"
#define BUFSIZE 128
int main() {
int afVMCI = VMCISock_GetAFValue();
int fd;
struct sockaddr_vm addr;
if ((fd = socket(afVMCI, SOCK_DGRAM, 0)) == -1) {
perror("socket");
return 1;
}
addr.svm_family = afVMCI;
addr.svm_cid = VMADDR_CID_ANY;
addr.svm_port = VMADDR_PORT_ANY;
bind(fd, (struct sockaddr *) &addr, sizeof addr);
struct sockaddr_vm serveraddr;
socklen_t svm_size = sizeof serveraddr;
{
int numbytes; char buf[BUFSIZE]; bzero(buf, BUFSIZE);
strcpy(buf, "hello there\n");
if ((numbytes = sendto(fd, buf, BUFSIZE, 0,
(const struct sockaddr *) &serveraddr, svm_size)) == -1) {
perror("sendto error");
goto close;
}
}
close:
close(fd);
VMCISock_ReleaseAFValueFd(fd);
return 0;
}
however, it's not working. there is not much documentation, e.g., how to troubleshoot. there is not information whether one can try both server and client within the same virtual machine for debugging purposes.
I tried to post to the vmware board, sent an email to their support, but no one seems to have a working example. because this is not standard socketry, though it is similar socketry, it is and is not followable.
anyone have a working example?
vmci is apparently not supported for vmplayer or vmware fusion. this is what the vmware support people told me:
I have been checking internally with our development team regarding
your request and incidentally could only generate interest if this was
a situation that is failing with vSphere. The final comment I have is
that we never meant to officially support this for VMware Fusion and
certain dependencies are on internal references only.
Unfortunately, we do not have any such vmci example which can be
shared publicly when it comes to VMware Fusion.

why does my connect fail?

I am trying to do basic socket calls, and trying to connect to google.com but the connect call always fails and returns -1. Any reason why it must be failing
int main()
{
int sockfd;
struct addrinfo *ai;
char port[4];
if(sockfd = socket(AF_INET, SOCK_STREAM, 0) < 0) {
printf("socket return -1");
}
sprintf(port, "%d", 80);
if(getaddrinfo("www.google.com", port, NULL, &ai) < 0)
printf("-2\n");
if(connect(sockfd, ai->ai_addr, sizeof(*ai->ai_addr)) < 0)
printf("connect failed -1");
}
I believe the problem is with the parameter sizeof(*ai->ai_addr). ai->ai_addr returns a pointer to a sockaddr struct, and dereferencing brings you to the struct itself.
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
sizeof is returning the size of the entire struct, not the length of the address.
Try making the argument ai->ai_addrlen instead.

Struct and Thread DWORD WINAPI

What's up guys, hope you are ok !
well, the problem is that I'm doing a chat client/server aplication but doing some tests with the server, I found out that I have a problem sending messages. I'm using a struct, sockets and DWORD WINAPI threads...
So the code in the struct is:
DWORD WINAPI threadSendMessages(LPVOID vpParam); //THREAD
typedef struct messagesServerChat{ //STRUCT
const char *messageServEnv;
}MESSAGE, *SMESSAGES;
then in the main method I call the struct to use the const char messageServEnv, a HeapAlloc to give some memory to the thread that is going to send the message and a char variable that I use to store the message
char mServer[1024] = ""; //variable to pre-store the message
SMESSAGES messages; //call the struct
messages = (SMESSAGES) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MESSAGE));
in the main method, I ask the user to insert the message that he wants to send and I use the struct to store the message and send it to the thread as a parameter:
cout<<"Dear user, please insert your message: ";
setbuf(stdin, NULL);
fgets(mServer, 1024, stdin);
messages->messageServEnv = mServer;
DWORD hSend; //send the parameters to the thread function
HANDLE sendThread = CreateThread(0, 0, threadSendMessages, mServer, 0, &hSend);
and finally the thread code function
DWORD WINAPI threadSendMessages(LPVOID lpParam){
SMESSAGES messages;
messages = (SMESSAGES)lpParam;
int mesa;
mesa = send(sConnect, (char *)messages->messageServEnv, sizeof messages->messageServEnv, 0);
//sConnect is the socket
//messages = to use the struct, and messageServEnv is the struct data that should contain the message
return 0;
}
--Edit-- I fix a lot of problems using Remy's solution but maybe I'm missing something... in the Thread threadSendMessages(SMESSAGES lpMessage)
char *ptr = messages->messageServEnv;
int len = strlen(messages->messageServEnv);
I get and error that says messages is undifined, then, I changed to:
SMESSAGES messages;
char *ptr = messages->messageServEnv;
int len = strlen(messages->messageServEnv);
now I can use messages and struct value messageServEnv but if I start debugging visual studio and I try to send a message, I get an error that says messages is used without being initialized, then I change that part to
SMESSAGES messages = new MESSAGE;
and now I can send messages to client but only characters and garbage code
You need to dynamically allocate the memory for each message's string data and then have the thread free the memory when finished sending it.
You are also passing the wrong pointer to the lpParameter parameter of CreateThread(), you are passing your char[] buffer instead of your allocated MESSAGE struct.
You are also using sizeof() when calling send(). Since your messageServEnv is a char* pointer, sizeof() will return 4 (32-bit) or 8 (64-bit) instead of the actual size of the string that is being pointed at.
I would suggest moving the char[] buffer directly into the struct instead of using a pointer to an external buffer, eg:
typedef struct messagesServerChat
{
char messageServEnv[1024];
}
MESSAGE, *SMESSAGES;
DWORD WINAPI threadSendMessages(SMESSAGES lpMessage);
.
cout << "Dear user, please insert your message: ";
setbuf(stdin, NULL);
SMESSAGES message = new MESSAGE;
fgets(message->messageServEnv, sizeof(message->messageServEnv), stdin);
DWORD hSend;
HANDLE sendThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&threadSendMessages, message, 0, &hSend);
if (!sendThread)
delete message;
.
DWORD WINAPI threadSendMessages(SMESSAGES lpMessage)
{
// send() is not guaranteed to send the entire message
// in one go, so call it in a loop...
char *ptr = lpMessage->messageServEnv;
int len = strlen(lpMessage->messageServEnv); // or sizeof() if you really want to send all 1024 bytes instead
while (len > 0)
{
int mesa = send(sConnect, ptr, len, 0);
if (mesa > 0)
{
ptr += mesa;
len -= mesa;
continue;
}
// this is only needed if you are using a non-blocking socket...
if ((mesa == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
{
fd_set fd;
FD_ZERO(&fd);
FD_SET(sConnect, &fd);
timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
if (select(0, NULL, &fd, NULL, &tv) > 0)
continue;
}
... error handling ...
break;
}
delete message;
return 0;
}
If you want to pass a dynamically-lengthed string instead, you are better off using a std::string instead of a char[]:
typedef struct messagesServerChat
{
std::string messageServEnv;
}
MESSAGE, *SMESSAGES;
DWORD WINAPI threadSendMessages(SMESSAGES lpMessage);
.
cout << "Dear user, please insert your message: ";
setbuf(stdin, NULL);
SMESSAGES message = new MESSAGE;
getline(stdin, message->messageServEnv);
DWORD hSend;
HANDLE sendThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&threadSendMessages, message, 0, &hSend);
if (!sendThread)
delete message;
.
DWORD WINAPI threadSendMessages(SMESSAGES lpMessage)
{
// send() is not guaranteed to send the entire message
// in one go, so call it in a loop...
char *ptr = lpMessage->messageServEnv.c_str();
int len = lpMessage->messageServEnv.length(); // or sizeof() if you really want to send all 1024 bytes instead
while (len > 0)
{
int mesa = send(sConnect, ptr, len, 0);
if (mesa > 0)
{
ptr += mesa;
len -= mesa;
continue;
}
// this is only needed if you are using a non-blocking socket...
if ((mesa == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
{
fd_set fd;
FD_ZERO(&fd);
FD_SET(sConnect, &fd);
timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
if (select(0, NULL, &fd, NULL, &tv) > 0)
continue;
}
... error handling ...
break;
}
delete message;
return 0;
}

Unable to Write On CFWriteStreamWrite

i am having trouble in writing data to CFStream.
// i am getting the CFSocketRef and then from it getting native Handle.
CFSocketNativeHandle sock = CFSocketGetNative( [appDelegate getSocketRef]);
Does above Code return me the same handler of the created socket?what ever i write onto stream will be written on the created socket?
// and then wrote
CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock,
&readStream, &writeStream);
if (!readStream || !writeStream) {
// close([appDelegate TCPClient]);
// close(sock);
fprintf(stderr, "CFStreamCreatePairWithSocket() failed\n");
return;
}
above works fine,it does not give me failed message
// does not give error ,else portion is executed
if (!CFWriteStreamOpen(writeStream)) {
CFStreamError myErr = CFWriteStreamGetError(writeStream);
// An error has occurred.
if (myErr.domain == kCFStreamErrorDomainPOSIX) {
// Interpret myErr.error as a UNIX errno.
NSLog(#"kCFStreamErrorDomainPOSIX");
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) {
// Interpret myErr.error as a MacOS error code.
OSStatus macError = (OSStatus)myErr.error;
// Check other error domains.
NSLog(#"kCFStreamErrorDomainMacOSStatus");
}
}else
/* Send the connect call to stream */
// while (send_len < (originalLength + 1))
{
// if (CFWriteStreamCanAcceptBytes(writeStream))
{
//UInt8 buf[] = "Hello, world";//(unsigned char *) "connectStream"
//CFIndex bufLen = (CFIndex)strlen(buf);
bytes = CFWriteStreamWrite(writeStream,
(unsigned char *) connectStream,
originalLength );
NSLog(#"%#",[[NSString alloc] initWithData:connectStream encoding:NSASCIIStringEncoding] );
if (bytes < 0) {
fprintf(stderr, "CFWriteStreamWrite() failed\n");
// close(sock);
return;
}
send_len += bytes;
}
// close(sock);
CFReadStreamClose(readStream);
CFWriteStreamClose(writeStream);
return;
}
CFWriteStreamCanAcceptBytes always return false so i have commented it and directly wrote bytes,and it blocks the call and does not return any thing neither any byte is written on to the stream,
Can any one please guide me in this rergard?
is there any other way of doing this?
Regards,
Aamir