0

I'm using a c program to respond to API calls. I want to reply using JSON. I created a streaming socket listening on my port and create a GET request using a browser (firefox in my case). I then reply using the "send" method based on the request received.

The problem is when my reply is bigger than 29200 bytes. Then the send method returns 29200 and only sends the first 29200 bytes, then it just stops. I cannot find why it would stop at this number.

I tried google and found: C++ socket programming Max size of TCP/IP socket Buffer?

My socket is blocking, so the send() function should block until all data is sent.

I also tried to find if linux blocks anything, but when I checked (not sure how I checked, cannot find the stackoverflow issue describing this) it was set to something way bigger than 29200.

I would like to know why my socket stops at 29200 and, if possible, how I can change the socket to make it send more data?

Edit:

Did some testing with the following results:

Created a test program to just send back 29999 bytes of data: https://pastebin.ca/4010317

I'm using curl to receive the data using curl -X GET -i 'http://:12345'

When running on my computer the response is:

received: -1 bytes
received:
sent 29999 bytes

I can see that on my computer (x64) the receive does not work, but the send does (Curl does receive the data)

but when running on the ARM device the response is:

received: 83 bytes
received: GET / HTTP/1.1
Host: 192.168.1.118:12345
User-Agent: curl/7.47.0
Accept: */*

J
sent 29200 bytes

Here, curl receives 29200 bytes of data.

When trying to loop the send (https://pastebin.ca/4010318), the result is:

received: -1 bytes
received:
sent 29199 bytes

Here, curl receives 29200 bytes, the second send returns -1. So looping is not possible.

I will keep trying, but the help is appreciated.

Junky
  • 21
  • 4
  • 4
    A correct code example will be appreciated. While i'm it, did you try to while-loop your send ? If you have X byte to send and only Y are sended, the you call again send but this time with "buffer + sendedLen" as buffer and "bufferLen - sendedLen" and you stop when sendedLen == bufferLen. – Tom's Mar 30 '18 at 09:46
  • Updated based on your reply. – Junky Apr 03 '18 at 09:26

2 Answers2

0

Your code work. Well, to be more exact, it work despite many little misusing function.

First, I asked you an mvce : you give a code with some useless line of code that add just complexity : if you don't need the information on the client connexion, the you can pass NULL to accept.

accept4(socketId, NULL, NULL, SOCK_NONBLOCK);

This way, we do not have 2 useless variables.

Second : Checking for error is cool, but displaying something (or logging) is better, because you can have hint why this doesn't work.

For example, the "received: -1 bytes" that you interpret as non-working is in fact working : The error (errno) is EAGAIN, meaning that since your socket is non-blocking, the data is not currently available so you have to loop your recv to read the incomming data. Looping recv will "solve" your false problem.

And finally : No, you do not loop your send either : you just merely detect if you haven't send all the data and try again one more time : do a LOOP !

Edit :

You can see how I do your "initServerSocket" function for the "check error and logging" part :

int InitServerSocket(int portNum, int nbClientMax)
{
    int                socketId       = -1;
    struct sockaddr_in addressInfo;
    int                returnFunction = -1;

    if ((socketId = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        // Log !
        goto END_FUNCTION;
    }

    addressInfo.sin_family = AF_INET;
    addressInfo.sin_addr.s_addr = htonl(INADDR_ANY);
    addressInfo.sin_port = htons(portNum);
    if (bind(socketId, (struct sockaddr *)&addressInfo, sizeof(addressInfo)) == -1) {
        // Log !
        goto END_FUNCTION;
    }

    const int flags = fcntl(socketId, F_GETFL, 0);
    fcntl(socketId, F_SETFL, flags ^ O_NONBLOCK);
    // Error detection & log ?


  if (listen(socketId, nbClientMax) == -1) {
        // Log !
        goto END_FUNCTION;
    }


  returnFunction = socketId;
  socketId = -1;
  /* GOTO */END_FUNCTION:
  if (socketId != -1) {
    close(socketId);
  }

    return (returnFunction);
}
Tom's
  • 2,448
  • 10
  • 22
  • Hey Tom, thanks for your reply. Now I do stress, the code uploaded is not the code used, the code used is existing code from the company I work and I cannot just set it online, plus it would be multiple files because the code is convoluted. (I know, I'm the engineer so it still is my fault). Anyway, the information about the accept is good, I did not know passing NULL would work. further, the test was to send 29999 bytes, a loop would only result in crashing because the send function would only return -1, so trying just once was enough to prove it did not work. – Junky Apr 03 '18 at 16:07
  • I did log in my code, did not in the pastebin because i was testing a piece of test code, not the final product. Then you say my code works, but it clearly doesn't (as seen in my tests). Finally, I did solve the problem, as I added to the post. – Junky Apr 03 '18 at 16:12
  • @Junky: Why do you think the send function will return -1? Your question clearly says it returns 29200. – Ben Voigt Apr 03 '18 at 16:18
0

I finally found the issue, the problem was that the

accept4(socket, (struct sockaddr *) &addrInfoFromClient, &sizeAddrInfo, SOCK_NONBLOCK); 

was setting the socket to non blocking, while in the init the socket was set to blocking. On the ARM device, this caused the "write" function to stop writing after 29200 bytes (not sure why).

When i changed the accept4 to:

accept(socket, (struct sockaddr *) &addrInfoFromClient, &sizeAddrInfo);

It worked.

Junky
  • 21
  • 4