Solved

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

Posted on 2009-04-06
21
261 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
 
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
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

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Suggested Solutions

Even if you have implemented a Mobile Device Management solution company wide, it is a good idea to make sure you are taking into account all of the major risks to your electronic protected health information (ePHI).
ADCs have gained traction within the last decade, largely due to increased demand for legacy load balancing appliances to handle more advanced application delivery requirements and improve application performance.
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

758 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

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now