Daniel Martin wrote:
akbarhome <akbarhome@gmail.com> writes:
I try to port this c code:
*(uint16_t *)(ptr+FSP_OFFSET_KEY)=htons(p->key);
*(uint16_t *)(ptr+FSP_OFFSET_SEQ)=htons(p->seq);
*(uint16_t *)(ptr+FSP_OFFSET_LEN)=htons(p->len);
*(uint32_t *)(ptr+FSP_OFFSET_POS)=htonl(p->pos);
About uint16_t, I have bit-struct library. But htons messed up my
head.
You are thinking about too low a level of porting.
Look, what is this code doing? It is packing up a structure, probably
to be sent over the wire. So let's just do that part, okay? Don't
try to separately do the htonl conversion and the structure-packing.
There's a reason the function isn't in the ruby standard library: the
only time it's needed is when you're packing things up anyway, so it's
built into pack and unpack.
Here's a rough translation of what I think you're trying to write:
# A translation of fsp_pkt_write from # http://csourcesearch.net/package/gftp/2.0.18/gftp-2.0.18/lib/fsplib/fsplib.c
# Note that in ruby we return the new string, and don't worry about
# preallocating a buffer.
# Also, I'd rename this method to something like "fsp_pkt_make" since
# it doesn't really *write* the data to the output, but that's what
# the function is called in C, so...
def fsp_pkt_write(fsp_pkt)
fsp_string = [fsp_pkt.cmd, 0, fsp_pkt.key,
fsp_pkt.seq, fsp_pkt.len, fsp_pkt.pos].pack("CCnnnN")
# I assume that in the ruby version, p.buf contains both the data
# block and the "extra data" block
fsp_string += fsp_pkt.buf
checksum = 0
fsp_string.each_byte {|i| checksum += i+1}
# Note: adding 1 above at each byte is equivalent to adding the length
fsp_string[1] = (checksum & 0xFF)
return fsp_string
end
Now, wasn't that easier than hauling out bitstruct to get a
line-by-line translation?
bit-struct wouldn't be useful for a line-by-line translation.
The fsp_pkt_write method is nice and simple. (The only problem is that checksum&0xFF is not the same as checksum + (checksum >> 8), but maybe there is something about fsp packets that I'm missing here.)
If you do want to use bit-struct, see below. One disadvantage with bit-struct is that you might be tempted to assign to members after initializing the struct and calculating the checksum, which would invalidate the checksum. Having a single method that does all of the calculations and gives you a string prevents this temptation. YMMV.
require 'bit-struct'
class FSPPacket < BitStruct
# This is already the default:
#default_options :endian => :network
unsigned :cmd, 8
unsigned :sum, 8
unsigned :key, 16
unsigned :seq, 16
unsigned :len, 16
unsigned :pos, 32
rest :buf
def initialize(*)
super
self.len = buf.length # ?? is this right?
self.sum = 0
checksum = length
each_byte { |i| checksum += i }
self.sum = checksum + (checksum >> 8)
end
end
fsp = FSPPacket.new do |pkt|
pkt.cmd = 123
pkt.key = 42
pkt.buf = "foo bar"
# ...
# all changes within this block will be reflected in the sum and len
end
p fsp # #<FSPPacket cmd=123, sum=91, key=42, seq=0, len=7, pos=0, buf="foo bar">
···
--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407