?
Solved

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

Posted on 2009-04-06
21
Medium Priority
?
268 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 10
  • 6
  • 3
  • +1
21 Comments
 
LVL 40

Accepted Solution

by:
mrjoltcola earned 2000 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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Originally, this post was published on Monitis Blog, you can check it here . It goes without saying that technology has transformed society and the very nature of how we live, work, and communicate in ways that would’ve been incomprehensible 5 ye…
Make the most of your online learning experience.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
Monitoring a network: why having a policy is the best policy? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the enormous benefits of having a policy-based approach when monitoring medium and large networks. Software utilized in this v…
Suggested Courses

765 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