Socket recv doesn't receive anything


I have coded a socket client which sends some data to web server (apache and PHP).

It works fine if I don't use recv. If I don't wait for response of server and simply after sending all data close the socket, I see received data in PHP and it works properly. But now I need to check server's response, so I need to do recv.

I tried to set socket option with SO_RCVTIMEO also. I don't receive anything at all!

I can't receive anything from server. If I don't set SO_RCVTIMEO, my program waits on recv forever. If I set the SO_RCVTIMEO I get in numbytes = -1

Please advice! I'm sure PHP replies with some data AT LEAST HTTP header. How I can solve it?

Even if it's possible to solved using PHP code I would do it. I already added exit() call in PHP code, so I think it will close connection. But it doesn't work.

I tried Connection: Close and Connection: Keep-Alive, NONE worked.

Please advice
LVL 17
Who is Participating?
Infinity08Connect With a Mentor Commented:
>> All things you worried about was correct

Those weren't things I was worrying about - I merely stated them for completeness, but was relatively confident that they were ok (otherwise a simple send would not even work).

What you don't seem to have tried are these suggestions I made :

1) did you try the code I posted ?
2) did you check what errno was set to when recv returns -1 ?
3) did you use a network sniffer (like Wireshark eg. : to check what is actually being sent over the network ? That will immediately uncover the problem.

>> I think we need to flush socket to apache, so apache starts processing.

As I said : if you need to do that, then there's another (possibly more serious) problem. So yes :

>> Nothing to worry, I think. What do you think?

I think there's something to worry about.
Could you show the C++ client code ?
Could you also show the PHP code on the other end ?
CSecurityAuthor Commented:
if ((h=gethostbyname2(THESERVER.c_str())) == NULL) return FALSE;
if ((sock = socket2(AF_INET, SOCK_STREAM, 0)) == -1) return FALSE;
    int iVal=0;

    unsigned int  sz = sizeof(iVal);
      iVal = 6000;
      int ret = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&iVal, sz);

if (connect(sock, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1) return FALSE;

send(sock, slast, 49, 0);

numbytes=recv(sock, bufrec, DATASIZE-1, 0);    <-- Here it hangs! If I set timeout, I get out of hang but without ANY data!

DATASIZE is also defined as 100
#define DATASIZE 100

After timeout I get -1 in numbytes. If I don't set timeout with setsockopt I wait for ever!

PHP part does nothing and works well if I don't do recv and directly close socket with closesocket(sock);

but if I hang on recv PHP won't work also. I should close socket with closesocket(sock); then PHP works and receives what I send.
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

I assume that socket2 is just an alias for socket.

SO_RCVTIMEO is not supported on all systems (only more recent systems support it), but I assume it is on yours.
Either way, if you use it on Linux, you need to pass a struct timeval as argument for setsockopt, not an int :

        struct timeval timeout = { 0 };
        timeout.tv_sec = 6;
        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*) &timeout, sizeof(timeout));

If you use it on Windows, it is indeed an int parameter. And you can use it like you did.

Make sure that a 6 second timeout is sufficient (it should be, but depends on the connection between client and server, as well as the load on the server).

I assume their_addr is set correctly, since the connection succeeds. But in any case, here's an example of what you should have :

        struct addrinfo hints;
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;

        struct addrinfo *their_addrinfo = 0;
        getaddrinfo(THESERVER.c_str(), "80", &hints, &their_addrinfo);

        int sock = socket(their_addrinfo->ai_family, their_addrinfo->ai_socktype, their_addrinfo->ai_protocol);

        connect(sock, their_addrinfo->ai_addr, their_addrinfo->ai_addrlen);

of course you'll need to add error handling everywhere.

Once the connection has succeeded, you can send and recv as the protocol dictates. For standard HTTP, you send the request, and receive the response. Then you usually end the connection (assuming keep-alive is not specified).

BUT, you need to specify the right sizes when you do. I assume you're sending 49 bytes because that is what you specified. Double-check that that is indeed the amount of data you send.
For recv, you don't know how much data you need to receive of course, so you specify a maximum. You specified 100. Make sure that the response is smaller than 100, or you won't receive everything.

Then we get to the error you experience. You say that recv returns -1. In that case, simply check what errno is set to to know what the exact error was that occurred.

>> PHP part does nothing and works well if I don't do recv and directly close socket with closesocket(sock);

Are you sure that the PHP part actually sends back a response ? You can use a network sniffer to see what is actually sent over the network. Use it on both ends to see which packets are sent/received on both ends. That will give you an accurate picture of what's happening.

You can also try your client code with another web server, like eg. to see if it works as it should.
CSecurityAuthor Commented:
I fixed the problem, solution is:

shutdown(socket, SD_SEND);

It closes sender socket and then I got received some data using recv. That's all
This indicates that there's something else going on. It shouldn't be necessary to shut down all sending operations just to be able to receive something.

I would recommend you check everything I pointed out in my previous post, because right now you've just hidden the bug, rather than solved it.
CSecurityAuthor Commented:
All things you worried about was correct, like socket2 is socket, size of data is 49, 6 second is enough as I was testing it with local apache server, etc.

I think we need to flush socket to apache, so apache starts processing. Flushing and ending sent packet occurs when you close send socket. Nothing to worry, I think. What do you think?
CSecurityAuthor Commented:
Got it working... Don't worry! I also had another problem which was adding \r\n in end of HTTP request twice
>> I also had another problem which was adding \r\n in end of HTTP request twice

That's not another problem. That's probably one of the reasons you saw the behavior you did. An extra \r\n could mean that the size was wrong and/or that the receiving end is waiting for more data before continuing.

Even if your problem is solved now, I do recommend to use a network sniffer to double check that all packets sent over the network now are actually how you expect them to be.
CSecurityAuthor Commented:
I checked with sniffer which caused to find source of problems! Now everything works like a charm! :) Thanks
>> I checked with sniffer which caused to find source of problems! Now everything works like a charm! :)

Great :) A sniffer is a great tool ! It's almost always the first thing I use to verify/analyse network behavior/issues.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.