Search code examples
csocketshtonl

htonl/ntohl not correct value on second command?


Edit: I honestly have no idea where the error is happening so I'll just add most of the relevant code, not sure if any of this helps

so basically I have two basic server & client processes. The user specifies a command, the client process then sends the length of the message to the server, the server executes the command and sends back a message length of the response.

This works well on the first command (I tried two ls -la in a row), the value is 1028 on the first command(correct value), and incorrectly 1685223288(in the client) on the second command

The write is done with the following code:

server_handler() {
char str[5000];
char * token = NULL;
unsigned long totalSize = 0;
str[0] = "\0";
totalSize = htonl(totalSize); // Correct size already calculate
if((result = write(clientFD, (char *) &totalSize, sizeof(totalSize)) < 0))
{
     printf("Failed sending size to client\n");
     exit(-1);
}
//Here the server starts sending the results to the client
token = strtok(str, "\n"); // str array contains the results
while(token != NULL)
{
     token[strlen(token)] = '\n';
     write(clientFD, token, strlen(token));
     token = strtok(NULL, "\n);
}

The read is done in the client process in the following way:

static void handle_reply() 
{
char * revBuf = 0;
unsigned long int bytesRead = 0;
unsigned long bufferlen = 0;
while(1) 
{
    result = read(socketFD, (char *) &bufferlen, sizeof(bufferlen));
    bufferlen = ntohl(bufferlen);
    recvBuf = malloc(bufferlen);
   //Here client starts reading results
    while(bytesread < bufferlen)
    {
        result = read(socketFD, recvBuf, bufferlen);
        printf("recvBuf: %s\n", recvBuf);
        bytesRead = strlen(recvBuf) + bytesRead;
    }
    free(recvBuf);
    bufferlen = 0;
   client_handler(); //calls Function that asks for new command
}
}

My question: Why am I receiving the wrong values on commands after the first one?, I have verified that totalSize has the correct value on server side in both cases with a print. Something must be going wrong in the write/read?

I also printed htonl(totalSize) on the server and it is 67371008. However the value received on the client side is 2021093988 before ntohl.


Solution

  • The following code isn't going to work correctly, because you call strlen again after modifying the string.

    token = strtok(str, "\n");
    while(token != NULL)
    {
        token[strlen(token)] = '\n';
        write(clientFD, token, strlen(token));
        token = strtok(NULL, "\n");
    }
    

    To illustrate, assume that str is initially "hello\nworld\n". In hex that's

     68 65 6c 6c 6f 0A 77 6f 72 6c 64 0A 00
                    ^---- the first newline
    

    After the strtok it will be

     68 65 6c 6c 6f 00 77 6f 72 6c 64 0A 00
                    ^---- strtok changed it to a NUL
    

    After the line token[strlen(token)] = '\n' it will be

     68 65 6c 6c 6f 0A 77 6f 72 6c 64 0A 00
                    ^---- you changed it back to a newline
    

    so now the strlen in the write will return 12, so the write will send 12 bytes, not 6 like you expect. This can be fixed by calling strlen once, like this

    token = strtok(str, "\n");
    while(token != NULL)
    {
        size_t length = strlen(token);
        token[length] = '\n';
        write(clientFD, token, length);
        token = strtok(NULL, "\n");
    }