Solved

C++: How to stop socket() from failing

Posted on 2009-04-06
21
264 Views
Last Modified: 2012-05-06
Hello,

I have an iPhone app that runs a c++ class I wrote that HTTP posts to a server I wrote. I let the user have control over what IP address to post to. If the IP address is correct, the app runs fine and gets the information back from the server. Here's where it gets tricky:

If the IP address is not on the network, an error is flagged and a user error message comes up. If the user then changes the IP address to the correct one, the app keeps working fine, no hitches.

On the error screen, the app is constantly (6 times/second) retrying the IP to see if it can connect. If the user sits on the error screen for too long, then when he changes it to the correct IP, the socket() command will still fail.

I'm thinking that maybe because it's running socket() six times/second, maybe it's running it too many times and it's running out of file descriptors? http://www.opengroup.org/onlinepubs/000095399/functions/socket.html says that this is one possible way for it to fail.

Anyone have any ideas for how to stop it from failing? Of course, please let me know if I can clear this up in any way. Thank you for your help!
struct hostent *hostentPointer
struct sockaddr_in serverAddress;
char **pPointer;
char networkAddress[MAX_SIZE];
 
hostentPointer = gethostbyname(host);
pPointer = hostentPointer -> h_addr_list;
int sockFD = socket(AF_INET, SOCK_STREAM, 0);
if (sockFD == -1)
     return 1;
 
etc.

Open in new window

0
Comment
Question by:ehensens
  • 10
  • 6
  • 3
  • +1
21 Comments
 
LVL 40

Accepted Solution

by:
mrjoltcola earned 500 total points
ID: 24079223
Your code sample isn't complete enough to tell, but surely, if you are calling the socket() function, it allocates a descriptor.

Regardless of whether your connect() later succeeds or not, you still need to close that descriptor on your side.

So, yes, you could be running out of descriptors.

You don't need to repeatedly call socket(), once you get one, then you can try repeatedly to connect() with that socket.
0
 

Author Comment

by:ehensens
ID: 24079237
Hi mrjoltcola,

Thank you for your response. How exactly do I "close that descriptor"?
0
 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24079289
with close()
0
Portable, direct connect server access

The ATEN CV211 connects a laptop directly to any server allowing you instant access to perform data maintenance and local operations, for quick troubleshooting, updating, service and repair.

 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24079292
I would not keep opening and closing, though, you can reuse the descriptor to connect() with until it succeeds.
0
 

Author Comment

by:ehensens
ID: 24079304
The weird thing is, i AM close() ing. I am going to try to reuse the descriptor and then if that doesn't work I will post a more complete code sample.
0
 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24079326
Then that may not be your root problem at all.
0
 

Author Comment

by:ehensens
ID: 24079429
I see... well, here's a more complete code sample, this function is called 6 times a second



struct hostent *hostentPointer
struct sockaddr_in serverAddress;
char **pPointer;
char networkAddress[MAX_SIZE];
 
hostentPointer = gethostbyname(host);
pPointer = hostentPointer -> h_addr_list;
int sockFD = socket(AF_INET, SOCK_STREAM, 0);
if (sockFD == -1)
     return 1;
 
bzero(&serverAddress, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(port);
inet_pton(AF_INET, network address, &serverAddress.sin_addr);
 
fcntl(sockFD, F_SETL, O_NONBLOCK);
 
fd_set sockSet;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 300;
FD_SET(sockFD, &sockSet);
 
int connectReturn;
int badReturns = 0;
 
while (connectReturn != 0)
{
   connectReturn = connect(sockFD, (SOCKA *) & serverAddress, sizeof(serverAddress));
   badReturns++;
   if (badReturns > 1000)
      return 1;
}
 
select(5, &sockSet, &sockSet, NULL, &timeout);
 
const void *optVal;
socklen_t *optLen;
getsockopt(sockFD, SOL_SOCKET, SO_ERROR, &optVal, optLen);
 
fcntl(sockFD, F_SETL, 0);
 
ssize_t responseReturn;
char sendRequest[MAX_SIZE];
 
snprintf(sendRequest, BUFFSIZE, "POST %s HTTP/1.0\r\nHost: %s\r\nContent-type: text/plain\r\nContent-length: %d\r\n\r\n%s", directory, host, strlen(payload), payload);
 
write(sockFD, sendRequest, strlen(sendRequest));
 
while ((responseReturn = read(sockFD, receiveResponse, SENDSIZE)) > 0)
   receiveResponse[responseReturn] = '\0';
 
close(sockFD);
 
return 0;

Open in new window

0
 
LVL 86

Expert Comment

by:jkr
ID: 24079460
>>On the error screen, the app is constantly (6 times/second) retrying the IP to
>>see if it can connect

I am sorry, but that is not a really good design. If you already know that the connection to that address does not work (that's why you are displaying an error screen, isn't it?), it is futile to try to reconnect. I suspect that the new address information isn't communicated correctly to that code in question. Also, what does 'errno' report when the connection fails?
0
 

Author Comment

by:ehensens
ID: 24079513
Hi jkr,

I have it like that in case the sever doesn't come on until after the client app does. That way it's constantly polling that IP address. Can you get any clues as to my problem from the code I just posted?

>> I suspect that the new address information isn't communicated correctly to that code in question

Well it has to be communicated correctly, because if you change the IP to a correct address within a minute or so of being on the error screen, it works great. But if you wait too long on the error screen then socket() fails.
0
 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24079560
jkr indirectly brings up another good point. Too many failed connects like that generates a lot of network SYN packets, and could cause a firewall or intrusion control to block your IP, because to a dump sniffer, it might look like a scanner.
0
 
LVL 86

Expert Comment

by:jkr
ID: 24079563
>>Well it has to be communicated correctly

OK, then the value of 'errno' would be interesting in the case that it still fails.

But, again, as a side note: 6 times a second is a bit too much. How fast can you type in a  new address?
0
 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24079583
I meant "dumb" sniffer. Some firewalls and intrusion software is not too smart about what it thinks is a scanner, and I'm mostly talking, in this case, to a corporate firewall where the user is on the inside.
0
 

Author Comment

by:ehensens
ID: 24079617
The information needs to be updated 6 times a second because the info being served up can change quite often.
0
 

Author Comment

by:ehensens
ID: 24079670
The errno is "too many open files"
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24079706
>>>> while (connectReturn != 0)
>>>> {
>>>>    connectReturn = connect(sockFD, (SOCKA *) & serverAddress, sizeof(serverAddress));
>>>>    badReturns++;
>>>>    if (badReturns > 1000)
>>>>       return 1;
>>>> }

You should add at least a sleep into that while loop.  

As the socket is non-blocking the while loop would return SOCKET_ERROR (== -1) for a lot of these connect calls and your while loop would catch all CPU of at least one of your cores ...

Didn't I show you a much less brute force method for checking one single connect call on being successful by using select with timeout on a set of writeable sockets?
0
 

Author Comment

by:ehensens
ID: 24080045
I thought I did that on line 36
0
 

Author Closing Comment

by:ehensens
ID: 31567121
I thought I was closing the socket because there was a close() at the bottom of the code, but the return statements didn't close the socket before they "return()"d. So, the close() was never getting called. I just added a close() before each return and it works great.
0
 

Author Comment

by:ehensens
ID: 24080178
It's fixed - please see the accepted solution comments.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24080213
>>>> select(5, &sockSet, &sockSet, NULL, &timeout);

Indeed. Though you may not use the same socket set for both reading and writing. I also would use sockFD as first argument and not 5.

But what purpose has the while loop with the connect call? You need one single call and it necessarily fails with socket error and errno = E_WOULDBLOCK  cause the socket is non-blocking. Then call select and it either wil timeout (than the IP is wrong or the user plugged of the cable or there is no wireless connection) or succeed.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24080222
>>>> select(5, &sockSet, &sockSet, NULL, &timeout);

 select(sockFD, NULL, &sockSet, NULL, &timeout);
0
 

Author Comment

by:ehensens
ID: 24080314
This seems to work nicely, itsmeandnobodyelse, thank you.
0

Featured Post

Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Short answer to this question: there is no effective WiFi manager in iOS devices as seen in Windows WiFi or Macbook OSx WiFi management, but this article will try and provide some amicable solutions to better suite your needs.
For many of us, the  holiday season kindles the natural urge to give back to our friends, family members and communities. While it's easy for friends to notice the impact of such deeds, understanding the contributions of businesses and enterprises i…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

832 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question