Reputation: 31
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.
Upvotes: 3
Views: 2099
Reputation: 76750
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.
Upvotes: 2
Reputation: 76611
My first guess would be that sizeof(msg) < MAX_MSG_BYTE
and when recv
overflows msg
it trashes i
.
Upvotes: 1