views:

257

answers:

2

Hey all, I have this strange problem with recv(). I'm programming client/server where client send() a message (a structure to be exact) and server recv() it. I am also working with multiple sockets and select().

while(1)
{
    readset = info->read_set;
    info->copy_set = info->read_set;

    timeout.tv_sec = 1; 
    timeout.tv_usec = 0; // 0.5 seconds

    ready = select(info->max_fd+1, &readset, NULL, NULL, &timeout);

    if (ready == -1)
    {
        printf("S: ERROR: select(): %s\nEXITING...", strerror(errno));
        exit(1);
    }
    else if (ready == 0)
    {
        continue;
    }
    else
    {
        printf("S: oh finally you have contacted me!\n");
        for(i = 0; i < (info->max_fd+1); i++)
        {

            if(FD_ISSET(i, &readset)) //this is where problem begins
            {
                printf("S: %i is set\n", i);
                printf("S: we talking about socket %i son\n", i);  // i = 4
                num_bytes = recv(i, &msg, MAX_MSG_BYTE, 0);
                printf("S: number of bytes recieved in socket %i is %i\n", i, num_bytes); // prints out i = 0 what??

                if (num_bytes == 0)
                {
                    printf("S: socket has been closed\n");
                    break;
                }
                else if (num_bytes == -1)
                {
                    printf("S: ERROR recv: %d %s \n", i, strerror(errno));
                    continue;
                }
                else                    
                {
                    handle_request(arg, &msg);
                    printf("S: msg says %s\n", msg->_payload);
                }
            } // if (FD_ISSET(i, &readset)
            else
                printf("S:  %i is not set\n", i);
        } // for (i = 0; i < maxfd+1; i++) to check sockets for msg
    } // if (ready == -1)   

    info->read_set = info->copy_set;
    printf("S: copied\n");

} 

the problem I have is that in read_set, 0~3 aren't set and 4 is. That is fine. But when i call recv(), i suddently becomes 0. Why is that? It doesn't make sense to me why recv() would take an socket file descriptor number and modify to another number. Is that normal? Am I missing something?

S:  0 is not set
S:  1 is not set
S:  2 is not set
S:  3 is not set
S: 4 is set
S: we talking about socket 4 son
S: i is strangely or unstrangely 0
S: number of bytes recieved in socket 0 is 40

That's what it prints out.

+1  A: 

My first guess would be that sizeof(msg) < MAX_MSG_BYTE and when recv overflows msg it trashes i.

R Samuel Klatchko
+2  A: 

recv cannot modify its first argument, since it is taken by value.

You don't show where you've declared msg or i, but based on this line

printf("S: msg says %s\n", msg->_payload);

Where you use the -> operator on msg, I assume it's probably like this:

struct somestruct* msg = malloc(sizeof(struct somestruct));
int i;

Then you do this:

num_bytes = recv(i, &msg, MAX_MSG_BYTE, 0);

Note that msg is already a pointer, so &msg is a pointer to the pointer.

What this will then do is receive data and try to store it in the place where the msg pointer itself is, not the place that msg points to. Typically, pointers are only 4 bytes long, so this will overflow the storage if you receive more than four bytes. If i is declared on the stack after msg, then it is likely that it is being overwritten by this overflow, and it happens to get overwritten by all zero bytes from the received packet.

Since msg is already a pointer, change your receive line to eliminate the superfluous indirection:

num_bytes = recv(i, msg, MAX_MSG_BYTE, 0);

Similarly, you may want to consider making the same change to the line

handle_request(arg, &msg)

if the handle_request function is not really expecting a pointer-to-pointer.

Tyler McHenry
This seems pretty likely to be the problem.
caf