Re: [dev] network protocol packing

2014-07-01 Thread Steve Dee
See also: https://kentonv.github.io/capnproto/



Re: [dev] network protocol packing

2014-07-01 Thread Markus Teich
Rob wrote:
 You've got alignment issues here - msg will be aligned to support any
 type (as malloc's interface specifies) so msg+1 will most likely be on
 an odd address, one byte off a highly aligned address. This means if
 your struct contains anything other than chars, you'll have UB. This is
 fine on x86, which allows unaligned access with a performance penalty
 but on something like an ARM machine you'll have issues.
 
 You probably want to memcpy the struct in from an existing one.

Heyho Rop,

thanks for your feedback. What about declaring a struct for each message-type:

struct msg_signed_data {
unsigned int op;
struct foo data;
struct bar signature;
};

This should also solve the alignment issues, or am I mistaken here? It also
reduces the amount of memcpy.

--Markus



Re: [dev] network protocol packing

2014-07-01 Thread Martti Kühne
On Tue, Jul 1, 2014 at 2:56 PM, Markus Teich markus.te...@stusta.mhn.de wrote:
 thanks for your feedback. What about declaring a struct for each message-type:

 struct msg_signed_data {
 unsigned int op;
 struct foo data;
 struct bar signature;
 };

 This should also solve the alignment issues, or am I mistaken here? It also
 reduces the amount of memcpy.


Is this skipping the padding or including it now? Including it would
mean there would be more to memcpy?
if you want to look at struct paddings, here we go... [0]

cheers!
mar77i

[0] https://gist.github.com/mar77i/b2cbe1a6c0c2194d7804



Re: [dev] network protocol packing

2014-07-01 Thread Dimitris Papastamos
On Tue, Jul 01, 2014 at 01:56:04PM +0200, Markus Teich wrote:
 struct msg_signed_data {
   unsigned int op;
   struct foo data;
   struct bar signature;
 };

If this is data that goes across the network then instead of
directly mapping a struct on that data I'd simply have functions that
create a struct out of that data.

The format of the data on the wire would be specified somewhere.

So the data would arrive as a series of bytes and whenever my packet
parsing function would indicate that a valid packet has been seen, it would
extract data from that ring buffer and map it onto a struct.  The particular
layout of that struct could be different across different architectures/ABIs
in order to meet alignment requirements etc.

Parsing valid packets for further processing could be done with
a table of function pointers indexed by the packet type.

You'd expect to access the struct via functions in the above case.

This is not specific to data across a network, that's just used as an
example.



Re: [dev] network protocol packing

2014-07-01 Thread Markus Teich
Rob wrote:
 You've got alignment issues here - msg will be aligned to support any
 type (as malloc's interface specifies) so msg+1 will most likely be on
 an odd address, one byte off a highly aligned address. This means if
 your struct contains anything other than chars, you'll have UB. This is
 fine on x86, which allows unaligned access with a performance penalty
 but on something like an ARM machine you'll have issues.

Heyho,

so if every field in the message is a multiple of 4 bytes long, this should fix
the problem? In this case I would just make op an uint32_t and htonl it before
sending, ntohl after receiving.

--Markus



Re: [dev] network protocol packing

2014-07-01 Thread Dimitris Papastamos
On Tue, Jul 01, 2014 at 05:01:43PM +0200, Markus Teich wrote:
 Rob wrote:
  You've got alignment issues here - msg will be aligned to support any
  type (as malloc's interface specifies) so msg+1 will most likely be on
  an odd address, one byte off a highly aligned address. This means if
  your struct contains anything other than chars, you'll have UB. This is
  fine on x86, which allows unaligned access with a performance penalty
  but on something like an ARM machine you'll have issues.
 
 Heyho,
 
 so if every field in the message is a multiple of 4 bytes long, this should 
 fix
 the problem? In this case I would just make op an uint32_t and htonl it before
 sending, ntohl after receiving.

Do not assume that.  It is wrong in the general case.



Re: [dev] network protocol packing

2014-07-01 Thread Steve Dee
On Tue, Jul 1, 2014 at 8:01 AM, Markus Teich markus.te...@stusta.mhn.de wrote:
 Rob wrote:
 You've got alignment issues here - msg will be aligned to support any
 type (as malloc's interface specifies) so msg+1 will most likely be on
 an odd address, one byte off a highly aligned address. This means if
 your struct contains anything other than chars, you'll have UB. This is
 fine on x86, which allows unaligned access with a performance penalty
 but on something like an ARM machine you'll have issues.

 Heyho,

 so if every field in the message is a multiple of 4 bytes long, this should 
 fix
 the problem? In this case I would just make op an uint32_t and htonl it before
 sending, ntohl after receiving.

It may be worth taking a look at capnproto as I mentioned above if you
haven't yet. It's taken a very similar approach to the problem, and
come up with a rather low-suck solution. Messages are all aligned to
64-bit words and sent that way over the wire, with an optional
lightweight packing format to reduce message sizes. There are C
bindings in a mostly-working state. You don't need to touch C++ except
to compile their protocol format, which you shouldn't have to do most
of the time. The only thing from your strawman that capnproto doesn't
do directly in a similarly simple manner is message signing, and it's
not hard to imagine adding it.

That said, I think your strawman is great, and I'm not trying to shoot
it down -- just pointing in the direction of similar work that might
be inspiring or might save you some effort.


 --Markus




Re: [dev] network protocol packing

2014-07-01 Thread Markus Wichmann
On Mon, Jun 30, 2014 at 08:54:52PM +0200, Markus Teich wrote:
 Heyho,
 
 since I did not find any suckless project regarding this issue, I would like 
 to
 ask you guys for some feedback:
 
 
 unsigned char *msg;
 size_t msg_size;
 struct foo *msg_data;
 struct bar *msg_signature;
 
 msg_size = sizeof(unsigned char)// op
   + sizeof(struct foo)// data
   + sizeof(struct bar)// signature
 msg = malloc(msg_size);
 
 *msg = MSG_OP_SIGNED_DATA;
 
 msg_data = (struct foo *)(msg + 1);
 msg_data-field0 = bla;
 msg_data-field1 = blub;
 
 msg_signature = (struct bar *)(msg_data + 1);
 create_signature(msg, msg_signature);
 
 sendmsg(msg);
 
 free(msg);
 
 
 I feel it is pretty good already compared to other message packing I've seen,
 but do you know a way to make it suck even less?
 
 --Markus
 

The alignment issue was already mentioned (there's nothing like your
program working at home and then suddenly dying of SIGBUS in the field
to hammer that point home), but unless all your data is single bytes,
you also have byte order problems. Solving these requires some suck.

There are basically only two ways to resolve these problems: Either copy
the data into the buffer and flip it later, or flip it on the way. I'd
personally go with flipping on the way:

unsigned char *p = msg;
*p++ = MSG_OP_SIGNED_DATA;
align32(p, msg);
write_be32(p, bla);
write_be16(p, blub);
/* and so on */

Then implement them like:

void write_be32(unsigned char **p, uint32_t i)
{
*(*p)++ = i  24;
*(*p)++ = i  16;
*(*p)++ = i   8;
*(*p)++ = i;
}

Then you are even independent of the host processor's byte order.

HTH,
Markus



[dev] network protocol packing

2014-06-30 Thread Markus Teich
Heyho,

since I did not find any suckless project regarding this issue, I would like to
ask you guys for some feedback:


unsigned char *msg;
size_t msg_size;
struct foo *msg_data;
struct bar *msg_signature;

msg_size = sizeof(unsigned char)// op
+ sizeof(struct foo)// data
+ sizeof(struct bar)// signature
msg = malloc(msg_size);

*msg = MSG_OP_SIGNED_DATA;

msg_data = (struct foo *)(msg + 1);
msg_data-field0 = bla;
msg_data-field1 = blub;

msg_signature = (struct bar *)(msg_data + 1);
create_signature(msg, msg_signature);

sendmsg(msg);

free(msg);


I feel it is pretty good already compared to other message packing I've seen,
but do you know a way to make it suck even less?

--Markus



Re: [dev] network protocol packing

2014-06-30 Thread Rob

On 30/06/14, Markus Teich wrote:

Heyho,


Hello there,


since I did not find any suckless project regarding this issue, I
would like to ask you guys for some feedback:


unsigned char *msg;
size_t msg_size;
struct foo *msg_data;
struct bar *msg_signature;

msg_size = sizeof(unsigned char)// op
+ sizeof(struct foo)// data
+ sizeof(struct bar)// signature
msg = malloc(msg_size);

*msg = MSG_OP_SIGNED_DATA;

msg_data = (struct foo *)(msg + 1);


You've got alignment issues here - msg will be aligned to support any
type (as malloc's interface specifies) so msg+1 will most likely be on
an odd address, one byte off a highly aligned address. This means if
your struct contains anything other than chars, you'll have UB. This is
fine on x86, which allows unaligned access with a performance penalty
but on something like an ARM machine you'll have issues.

You probably want to memcpy the struct in from an existing one.


msg_data-field0 = bla;
msg_data-field1 = blub;

msg_signature = (struct bar *)(msg_data + 1);
create_signature(msg, msg_signature);

sendmsg(msg);

free(msg);


I feel it is pretty good already compared to other message packing
I've seen, but do you know a way to make it suck even less?


Seems pretty straightforward otherwise :)

Cheers,
Rob