recvfrom gives empty string

W

William

I have declared the following struct:
struct PropagateInfo {
string type; // "registration", "gossip", "termination"
int initiatePeerID;
};

which I used as follows:

PropagateInfo* initiatePeerInfo = new PropagateInfo;
initiatePeerInfo->type = type; // type is set to "registration"
initiatePeerInfo->initiatePeerID = ID;

cout << "type before sending to overseer: " << initiatePeerInfo->type << \
endl; // prints "registration"

// sending the struct initatePeerInfo to the server
if ( (numBytes = sendto(sockfd, (void*)initiatePeerInfo, \
MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&serv_addr, sizeof(struct \
sockaddr))) == -1 ) {
cerr << "send to: " << strerror(errno) << endl;
exit(1);
}
cout << "bytes sent: " << numBytes << endl; // prints 512


/**** server side *****/
numBytes = recvfrom( sockfd, initiatePeer, MAX_UDP_PACKET_SIZE, 0, (struct
sockaddr *) &peer_addr, &addrLen );
// I have also tried sizeof(struct PropagateInfo) instead of
MAX_UDP_PACKET_SIZE

cout << "num bytes received: " << numBytes << endl; // prints 512
initiatePeerID = ((PropagateInfo*)initiatePeer)->initiatePeerID;
cout << "initiatePeerID: " << initiatePeerID << endl; // prints the
correct ID

type = ((PropagateInfo*)initiatePeer)->type;
// error - nothing (i.e. "") is printed!!!
cout << "type after receiving: " << type << endl;

output:
type after receiving:

my question:
Why is ((PropagateInfo*)initiatePeer)->type "registration" before sendto;
but "" after recvfrom?!

Thanks for your help.

Documentation:
http://linux.com.hk/PenguinWeb/manpage.jsp?name=send&section=2
 
V

Victor Bazarov

William said:
I have declared the following struct:
struct PropagateInfo {
string type; // "registration", "gossip", "termination"

Keep in mind that 'string' object does not _itself_ contain the chars
it consists of. It allocates it elsewhere, usually in free store. So,
writing out contents of 'type' as if they were consecutive bytes does
not accomplish writing out "registration" even if type->c_str() actually
yields "registration". That's the problem with serialisation in C++,
it's just not that simple.
int initiatePeerID;
};

[...]
 
M

Malte Starostik

William said:
I have declared the following struct:
struct PropagateInfo {
string type; // "registration", "gossip", "termination"
int initiatePeerID;
};
[snip]

// sending the struct initatePeerInfo to the server
if ( (numBytes = sendto(sockfd, (void*)initiatePeerInfo, \
MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&serv_addr, sizeof(struct \
sockaddr))) == -1 ) {
cerr << "send to: " << strerror(errno) << endl;
exit(1);
}
cout << "bytes sent: " << numBytes << endl; // prints 512

In addition to what Victor said, there is a *major* problem with your
code, plus a few smaller ones:

* the cast to void* is not necessary, but that you felt the need to use
it should have rung every available alarm bell ;)
* use C++ style casts instead
* The big one: you're telling sendto() to send MAX_UDP_PACKET_SIZE
bytes, which is almost guaranteed to be more than sizeof( PropagateInfo
), resulting in undefined behaviour and the potential for very nasty
things to happen. Now sendto() only reads the data you pass, so it's
fortunately only an invalid memory read. The output of 512 should warn
you. PropagateInfo as declared above is never going to be 512 bytes
large...
/**** server side *****/
numBytes = recvfrom( sockfd, initiatePeer, MAX_UDP_PACKET_SIZE, 0, (struct
sockaddr *) &peer_addr, &addrLen );

* And now for the really big one:
Here you're doing the same, but this time around with an operation
(recvfrom()) that will _write_ past the end of initiatePeer. This kind
of bug (buffer overflow) is the number one cause for security problems
in software, especially when it comes to networking.
// I have also tried sizeof(struct PropagateInfo) instead of
MAX_UDP_PACKET_SIZE

That would have been correct except for the more general problem as
mentioned by Victor.
cout << "num bytes received: " << numBytes << endl; // prints 512

You're quite lucky this statement was still executed instead of your
program crashing. Actually, you're not so lucky because a crash would
have had more warning potential than a somewhat working program :)

With code as above in a program that receives data from the network,
you're inviting everyone who can send packets to the machine it's
running on to play with it. It shouldn't take more than a few minutes
to create a UDP packet that will result in your program executing any
code on your machine to the sender's delight. Remember, not only your
client can send data to it - firewalls provide some protection, but
maybe you intend your server to be connectable from the outside...

Please get more familiar with how pointers work before you consider
using them in networked applications. And memorise this: Never trust
any data received from the network to be wellformed and benign - the
same holds for any other kind of input. Expect the unexpected and write
code that will cope nicely with the most bizarre input data imaginable.

That said, I'm not at all trying to prevent you from exploring the world
of socket programming nor pointers. Only the issue is very serious and
you should be aware of the security implications.

Cheers,
Malte
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top