1

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.

user3284549
  • 313
  • 3
  • 9
  • This question title is so wrong and so common, it's not possible that the problems are happening because some standard function is faulty, it's possible ok... but really unlikely. The problem has to be your code, so blame it first, if it turns out the function was wrong, then you didn't hurt anyone's eyes... – Iharob Al Asimi Mar 05 '15 at 19:09
  • 32bit server with 64 bits client or conversely ? – philippe lhardy Mar 05 '15 at 19:10
  • Both are being run on the same computer for testing – user3284549 Mar 05 '15 at 19:13
  • 1
    You might need to verify that `result == sizeof(bufferlen)` for one thing. For another, are you sending data in between your two "commands"? Is it possible that, although you said you were going to send 1028 bytes the first time, you actually sent a different amount, resulting in your second quoted `read` reading from a different location in the stream than you think you are reading from? – twalberg Mar 05 '15 at 20:24
  • show more code, if problem is not htonl/nhtol this is around your socket write/read buffer. – philippe lhardy Mar 05 '15 at 20:25
  • 1
    Note that 1028 and 67371008 are byte-reversed from each other (`0x404` vs `0x4040000`). Same thing with 1685223288 and 2021093988 (`0x64727778` vs `0x78777264`, which is also either the text string "drwx" or "xwrd", the first of which looks suspiciously like part of the output from `ls -l`)... – twalberg Mar 05 '15 at 20:27
  • Oh it doesn't actually send 1028 bytes at once, it sends the results one line at a time, the 1028 being sent is the byte size of the output, being sent before the output is sent. I'll edit to include some more code. – user3284549 Mar 05 '15 at 20:28
  • @twalberg good catch for "drwx" ! – philippe lhardy Mar 05 '15 at 20:38
  • `char str[5000] ... str[0] = "\0';` does not compile. Recommend to post true code. – chux - Reinstate Monica Mar 05 '15 at 21:06
  • Given that this is likely an endian issue, like to point another concern: Since code is not assuming a given endian, why should code assume `unsigned long` is a consistent width in `read(socketFD, (char *) &bufferlen, sizeof(bufferlen))` between sytems? Suggest using fixed width integers. – chux - Reinstate Monica Mar 05 '15 at 21:17
  • sorry about that, can barely think atm. Should probably take a break and get back to the problem after that. good point yeah it should, not really meant to be used other than locally though (for an assignment) – user3284549 Mar 05 '15 at 21:17

2 Answers2

1

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");
}
user3386109
  • 34,287
  • 7
  • 49
  • 68
  • 1
    While this didn't solve my whole problem, it did solve part of it and help me a lot and I think I know what I need to do now. Thank you! – user3284549 Mar 05 '15 at 22:52
0

htonl and ntohl are 32bits ...

  uint32_t htonl(uint32_t hostlong);
  uint32_t ntohl(uint32_t netlong);

see what happens with big integers with that program with a 64bits system.

#include <stdio.h>

int main(int argc, char** arg)
{
  unsigned long bufferlen = 0;
  unsigned long totalSize = 1024;
  sscanf(arg[1],"%lld",&totalSize);
  printf("%lld  %llx\n", totalSize,totalSize);

  totalSize = htonl(totalSize); // 32 <-> 64bits .
  bufferlen = ntohl(totalSize);

  printf("%lld %llx %lld %llx\n", totalSize,totalSize,bufferlen,bufferlen);

}

testing it :

./test 111111111111111
111111111111111  650e124ef1c7
-940487150 ffffffffc7f14e12 307163591 124ef1c7
philippe lhardy
  • 3,096
  • 29
  • 36