How to convert UUID to big endian?
Asked Answered
P

3

6

My UUID is structured like this:

struct UUID_FIELDS
{
    uint32_t time_low;                
    uint16_t time_mid;                 
    uint16_t time_hi_and_version;      
    uint8_t clock_seq_hi_and_reserved;
    uint8_t clock_seq_low;             
    uint8_t node[6];                   

};

I have functions that swap along 32 bit boundaries and a swap function that swaps along 16 bit boundaries. I have tried calling swap32() on time_low and swap16() on time_mid and time_hi_and_version. I do not believe I need to swap bytes for the rest of the fields because two of them are 8 bit fields and I have read that the node part of a uuid does not change. Here is a link for that reference.

The problem is when I complete the swaps the uuid that is printed does not match the one that was in little endian before being converted.

What is the correct way to convert a uuid following RFC-4122 standard from little endian to big endian. And when converted should the uuids match?

Pyrometallurgy answered 8/6, 2016 at 19:32 Comment(16)
see : online hex convertionComenius
If you are on a little-endian system and receive the UUID as per RFC-4122 standard (big-endian representation) then yes you'll have to swap bytes on time_low, time_mid, and time_high_and_version in order to use them properly.Vickery
@MohammadrezaPanahi you may want to specify how that conversion site possibly relates to the OP's specific (and well worded, I may add) question. A useful site, to be sure, but how does it help solve this problem ?Devest
@Mohammadreza I have seen this link. This does not help me.Pyrometallurgy
Do you know the data is little endian, for a fact? Or is it machine native order? You may want to use htonl and htons instead of unconditional byte swapping, so you don't perform the swap on machines where it is already big endian.Mariannmarianna
I know for a fact the data I have is little endian and it needs to be converted to big endian for the receiver.Pyrometallurgy
So, on the little endian system, you swap the bytes, then transmit the modified structure to the big endian receiver, where the UUID, when printed to text, appears not to match the original one's text? Are you just blasting the raw structure over the network? Might there be alignment issues? What is the value of offsetof(struct UUID_FIELDS, member) for each struct member, on both systems?Lissotrichous
@Lissotrichous yes that is correct. I tried using the above functions to swap bytes on the fields above I talked about. It is possible I am not swapping the correct fields or maybe I am doing not correctly converting a uuid's endianess.Pyrometallurgy
Make a UUID with contents like 0x01020304 ... and so on. Use a unique byte value for each byte of each 32, 16 and byte. Then do the swap and send to the other side, and print all the values (or look at with a debugger, etc). That will reveal where the bytes are ending up: where the 0x01 ended up, the 0x02 and so on. Look at the original structure, locally swapped one and remotely received one.Lissotrichous
You only need to swap bytes in the uint32_t and uint16_ts. Please show your swap function.Rossanarosse
@Rossanarosse I have added the swap32 and swap16 functions to the question. I am still struggling with this issue.Pyrometallurgy
The swapping code you have appears to do exactly what it's supposed to do. The link you provide, assuming it's the authority, does indicate only the first three fields need to have this operation done on them as you suggest. I would follow @Kaz's suggestion. I'd also be curious to see what happens when you send a UUID without modifying via your swap functions.Woods
When I do not modify the uuid with my swap functions, it is all out of order. I currently doing what @kaz said.Pyrometallurgy
I have added my results from using my swap functions.Pyrometallurgy
@Pyrometallurgy While your swap functions looked ok, we don't know how you're using them to tell if perhaps you're giving it the wrong parameters. Please show your swap functions and an example of how you invoke them on a UUIDRossanarosse
I have solved the problem. Take a look at @kaz's answer.Pyrometallurgy
L
4

Re:

Update: Starting uuid in little endian:

446831D3-FBA1-477B-BB07-CB067B00E86B

Result from correctly swapping necessary fields:

FBA1477B-31D3-4468-6BE8-007B06CB07BB

This looks horribly wrong. We can deduce that if the swaps are correct and affect only the 32 and 16 bit fields, then without swapping the necessary fields, it would be this:

Original: 446831D3-FBA1-477B-BB07-CB067B00E86B
           |       _______/   |       _______/
            \____ /_______     \____ /______
            _____/        \    _____/       \
           /               |  /              |
Received: 7B47A1FB-D331-6844-6BE8-007B06CB07BB   # "de-swapped".

What you seem to have have going on here is byte swapping within 64 bit units somewhere in your pipeline. Even the array of bytes is being reversed, suggesting that it might be loaded somewhere as part of a 64 bit load, which is subject to a swap64 operation.

Lissotrichous answered 13/6, 2016 at 18:8 Comment(4)
I believe what you have stated is correct because I used a swap64 function along a 32 bit boundary so 64 bit int x = 0xAABBCCDD11223344 x swapped = 0x11223344AABBCCDD Then treating the whole uuid like 4 32 bit ints I used swap 32 to give me: 0x44332211DDCCBBAA.Pyrometallurgy
Your question doesn't say anything about a swap64, though, haha.Lissotrichous
Well I have a library of functions so I decided to try it on the whole uuid instead of each field. So I basically did: swap64along32(uuid); swap32(uuid); I am not sure why swapping the individual fields was not working. I guess what you said. It was treating the uuid as two 64 bit integers.Pyrometallurgy
Since you basically lead me there. If you write up an answer of summarizing what I did in the comments for other users who might have a similar issue. I will accept your answer.Pyrometallurgy
R
3

Have you tried accessing the individual bytes?

uint8_t packet[4];
uint32_t value;
packet[0] = (value >> 24) & 0xFF;
packet[1] = (value >> 16) & 0xFF;
packet[2] = (value >>  8) & 0xFF;
packet[3] = value & 0xFF;

Probably more efficient than calling a function. :-)

Note: the above method is platform independent. Doesn't require any knowledge how the value is stored.

Explanation:
Let packet be a buffer or memory destination for a uint32_t that needs to be stored into the buffer in Big Endian format (Most Significant Byte First).

The expression (value >> 24) shifts the most significant byte to the least significant (byte) position. The expression "& 0xff" truncates, chops off, any extraneous values, resulting in an unsigned 8-bit value. The value is then stored in the Most Significant position in the buffer at the first location.

Likewise for the remaining bytes.

Rodmann answered 8/6, 2016 at 19:45 Comment(4)
I have not tried this. What does packet represent? Sorry I do not really follow this. Can you elaborate more?Pyrometallurgy
Packet represents your destination packet or buffer.Rodmann
Also I am still not sure if all bytes in the uuid must be swapped or only the bytes I specified above.Pyrometallurgy
The byte order of a UUID depends on the receiver or the protocol. Hint: search the internet for "UUID protocol".Rodmann
E
0

The recommended way is to use the function htonl (htons for 16 bit integers) to convert from host byte order to network byte order, and ntohl (ntohs for 16 bit integers) to convert from network byte order to host byte order

Given the following structure:

struct UUID_FIELDS
{
    uint32_t time_low;                
    uint16_t time_mid;                 
    uint16_t time_hi_and_version;      
    uint8_t clock_seq_hi_and_reserved;
    uint8_t clock_seq_low;             
    uint8_t node[6];                   
};

The code for serialization and deserialization might be as follows:

std::string serialize(UUID_FIELDS fields) {
    std::string buffer(sizeof(fields), '\0');

    // convert all fields with size > 1 byte to big endian (network byte order)
    fields.time_low = htonl(fields.time_low);
    fields.time_mid = htons(fields.time_mid);
    fields.time_hi_and_version = htons(fields.time_hi_and_version);

    memcpy(&buffer[0], &fields, sizeof(fields));

    return buffer;
}

UUID_FIELDS deserialize(const std::string& buffer) {
    UUID_FIELDS fields;

    assert(buffer.size() == sizeof(fields));

    memcpy(&fields, &buffer[0], sizeof(fields));

    // convert all fields with size > 1 byte to little endian (maybe) (host byte order)
    fields.time_low = ntohl(fields.time_low);
    fields.time_mid = ntohs(fields.time_mid);
    fields.time_hi_and_version = ntohs(fields.time_hi_and_version);

    return fields;
}

Note that you have to agree with the receiver/sender in the remote endpoint that you are both sending/receiving numbers in big endian.

Enclasp answered 11/6, 2016 at 3:38 Comment(3)
This will only work if the host is little-endian. If it isn't, it will do nothing.Naphthyl
@EJP Yes you are right, here is a link that references this: beej.us/guide/bgnet/output/html/multipage/htonsman.html "This means on Intel these functions swap all the bytes around, and on PowerPC they do nothing because the bytes are already in Network Byte Order."Pyrometallurgy
@EJP That's how it is supposed to work. Swap bites if host byte order is little endian, do nothing if host byte order is big endian. Maybe you were referring to the other answer where the bytes are always swapped?Enclasp

© 2022 - 2024 — McMap. All rights reserved.