Endianness in memoryblocks from network comms

I’m processing NTP timestamps returned from an NTP server.

The particular issue I’m having is with endianness and I’d like to clarify the best way to do what I need to do.

I have a memoryblock which contains 48 bytes - this is a standard NTP3 response packet.

Bytes 40 to 43 of the response contain a 32 bit (4 byte) unsigned big endian integer. The NTP protocol dictates that it will always be a big endian number in this response.

ntp3response is a memoryblock (44) containing the 44 byte NTP server response with the timestamps in it and ntp_transmit is a uint32

I’ve attempted to extract this 4 byte UInt from the memoryblock by using this :

ntp_transmit = ntp3response.UInt32Value(40)

This (Uint32Value method) returns a little endian (windows default) number even when I set ‘memoryblock.littleendianness=false’ so it won’t work and gives the wrong timestamp value.

I suspect the Uint32Value interprets the number as machine default endianness and I can’t find a way to change this. This is a memory block containing lots of different numbers.

I already tried setting littleendianness=false when I assign the data to the memoryblock but I suspect this isn’t working because right now I’m reading data from the UDP connection and storing it as single lump directly into the memory block instead of reading / processing one number at a time using the memoryblock methods.

I’m populating the memoryblock with this code (dgreply is a datagram) :

dgreply = udpsocket1.read
ntp3response = dgreply.data

I can get the correct number out of this memoryblock using the following method to reverse the byte order within the 4 byte integer :

timeblock.Byte(0) = ntp3response.byte(43)
timeblock.Byte(1) = ntp3response.byte(42)
timeblock.Byte(2) = ntp3response.byte(41)
timeblock.Byte(3) = ntp3response.byte(40)

ntp_transmit = timeblock.UInt32Value(0)

So when I manually reverse the byte order it works on Windows and gives me the correct integer timestamp that I need.

I worry that when run on a Mac the ntp_transmit which is an uint32 will be interpreted as a little endian and reverse my manual byte order reversal.

So to summarise I have a datablock which will always contain a big endian number at the above byte positions.

I want to move it into a variable which will always return the correct number regardless of which system it’s working on.

What’s the best way to do this and ensure that it will work on Windows, Linux and OSX platforms.

I don’t have an OSX system to test this on at the moment.

Have you set the endianness of the memory block right when you create it or right after you create it
Once you shove data in it it may already be too late

I tried it both ways, but it made no difference.

I can understand this behaviour though.

For example, I’m doing the following :

dim ntp3response as new memoryblock(200)
ntp3response.littleendian=false
.
.
.
ntp3response = dgreply.data

I’m assigning a whole bunch of data from dgreply.data which contains a mix of different length big endian integers. It’s just a block of bytes at this stage and there’s no way Xojo can know which bytes form u8ints and which are u32ints

I know it’s coming in from dgreply.data in big endian format.

I suspect that if I assign a uint32 directly into the memoryblock it would be stored correctly as a big endian number with littleendianness set to false but I need to get it out of the memory block in the correct order first.

I use a structure to read and write to MemoryBlock for RPC over TCP/UDP, work with all platforms.

[code]// WRITE:
Structure StructVXI
iClientID As UInt32
iLockDevice As UInt32
End Structure

Dim uVXI As StructVXI
Dim mbData As MemoryBlock

uVXI.iClientID = 10
uVXI.iLockDevice = 20

mbData = uVXI.StringValue(False) // BigEndian
mbData.LittleEndian = False

// READ:
Dim mbData As MemoryBlock
Dim ptrData As Ptr
Dim iClientID, iLockDevice As UInt32

ptrData = mbDataVXI // received data.
mbData = ptrData.StructVXI.StringValue(False) // BigEndian to BigEndian is LittleEndian.
mbData.LittleEndian = True
ptrData = mbData // set pointer to new memoryblock.

iClientID = ptrData.StructVXI.iClientID
iLockDevice = ptrData.StructVXI.iLockDevice[/code]

[quote=43249:@Neil McAliece]I tried it both ways, but it made no difference.
[/quote]
Hmmmmm … that still doesn’t seem right

Sure - that’s exactly why a memory block is exactly right here
And it should just do the right thing knowing when you access the int, units etc & do the necessary byte swapping

[quote=43310:@Norman Palardy]Sure - that’s exactly why a memory block is exactly right here
And it should just do the right thing knowing when you access the int, units etc & do the necessary byte swapping[/quote]

Ok, thanks. I think I understand this a bit more now. I must have been going wrong somewhere as I managed to get it working in the end.