The Pubnub C-core library. It's home is on https://github.com/pubnub/c_core, this is a copy
Dependents: Pubnub_c_core_mbed2_pal Pubnub_c_core_mbed2_pal Pubnub_c_core_mbed2_pal2
pubnub_generate_uuid.h@2:d85e42c1125d, 2016-11-22 (annotated)
- Committer:
- sveljko
- Date:
- Tue Nov 22 22:21:39 2016 +0000
- Revision:
- 2:d85e42c1125d
- Parent:
- 1:929314a174af
Added `pubnub_helper` module
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
sveljko | 1:929314a174af | 1 | /* -*- c-file-style:"stroustrup"; indent-tabs-mode: nil -*- */ |
sveljko | 1:929314a174af | 2 | #if !defined INC_PUBNUB_GENERATE_UUID |
sveljko | 1:929314a174af | 3 | #define INC_PUBNUB_GENERATE_UUID |
sveljko | 1:929314a174af | 4 | |
sveljko | 1:929314a174af | 5 | #include <stdint.h> |
sveljko | 1:929314a174af | 6 | |
sveljko | 1:929314a174af | 7 | |
sveljko | 1:929314a174af | 8 | /** @name pubnub_generate_uuid.h |
sveljko | 1:929314a174af | 9 | This is an UUID generator module for Pubnub, but it is fairly |
sveljko | 1:929314a174af | 10 | general and can be used for other purposes. It follows the IETF |
sveljko | 1:929314a174af | 11 | RFC 4122 and ITU-T X.667 | ISO/IEC 9834-8 |
sveljko | 1:929314a174af | 12 | standards/recommendations. |
sveljko | 1:929314a174af | 13 | It provides interfaces for 4 out of 5 algorithms defined in the |
sveljko | 1:929314a174af | 14 | standards. But, depending on the platform, all, some or none of |
sveljko | 1:929314a174af | 15 | the algorithms will be available. |
sveljko | 1:929314a174af | 16 | It avoids keeping state itself and leaves it to the user, in order |
sveljko | 1:929314a174af | 17 | to be portable. |
sveljko | 1:929314a174af | 18 | Some of the algorithms depend on a good quality random number |
sveljko | 1:929314a174af | 19 | generator to be used by either the algorithm itself, or by the |
sveljko | 1:929314a174af | 20 | user to provide (start/seed) input. We use (and users should, |
sveljko | 1:929314a174af | 21 | too): |
sveljko | 1:929314a174af | 22 | - RtlGenRandon() on Windows |
sveljko | 1:929314a174af | 23 | - `/dev/urandom` on POSIX |
sveljko | 1:929314a174af | 24 | |
sveljko | 1:929314a174af | 25 | */ |
sveljko | 1:929314a174af | 26 | |
sveljko | 1:929314a174af | 27 | struct Pubnub_UUID { |
sveljko | 1:929314a174af | 28 | /* Here is the generic UUID format. Byte order is MSB ("network |
sveljko | 1:929314a174af | 29 | order", "big-endian"). |
sveljko | 1:929314a174af | 30 | 0 1 2 3 |
sveljko | 1:929314a174af | 31 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
sveljko | 1:929314a174af | 32 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
sveljko | 1:929314a174af | 33 | | time_low | |
sveljko | 1:929314a174af | 34 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
sveljko | 1:929314a174af | 35 | | time_mid | time_hi_and_version | |
sveljko | 1:929314a174af | 36 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
sveljko | 1:929314a174af | 37 | |clk_seq_hi_res | clk_seq_low | node (0-1) | |
sveljko | 1:929314a174af | 38 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
sveljko | 1:929314a174af | 39 | | node (2-5) | |
sveljko | 1:929314a174af | 40 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
sveljko | 1:929314a174af | 41 | */ |
sveljko | 1:929314a174af | 42 | uint8_t uuid[16]; |
sveljko | 1:929314a174af | 43 | }; |
sveljko | 1:929314a174af | 44 | |
sveljko | 1:929314a174af | 45 | struct Pubnub_UUID_String { |
sveljko | 1:929314a174af | 46 | /* XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ |
sveljko | 1:929314a174af | 47 | char uuid[36+1]; |
sveljko | 1:929314a174af | 48 | }; |
sveljko | 1:929314a174af | 49 | |
sveljko | 1:929314a174af | 50 | /** This generates an UUID using the v1 algorithm (time-based). This |
sveljko | 1:929314a174af | 51 | algorithm has some state, but, a lot of it is "node" identifier, |
sveljko | 1:929314a174af | 52 | which is the MAC address of your Ethernet-ish network interface, |
sveljko | 1:929314a174af | 53 | and most applications have one. If you don't have a MAC, you can |
sveljko | 1:929314a174af | 54 | use some other identifier. If it has less than 6 octets, will use |
sveljko | 1:929314a174af | 55 | what we have, but UUIDs will be of lesser quality. If you don't |
sveljko | 1:929314a174af | 56 | have an identifier to use, than you can generate a random number. |
sveljko | 1:929314a174af | 57 | If you don't have a random number generator, you can either give |
sveljko | 1:929314a174af | 58 | up, or use the pubnub_time() to obtain a high-resolution time as a |
sveljko | 1:929314a174af | 59 | pseudo-random number. |
sveljko | 1:929314a174af | 60 | Besides that, it has the @p timestamp, which is a 100ns tick timer |
sveljko | 1:929314a174af | 61 | that started at midnight 15 October 1582. If you have a clock, |
sveljko | 1:929314a174af | 62 | just convert it to this format and you're good. Since it requires |
sveljko | 1:929314a174af | 63 | 64-bit integer support, and that is not always available, we are |
sveljko | 1:929314a174af | 64 | accepting it as a 8-octet array. If you don't have a clock, but |
sveljko | 1:929314a174af | 65 | have a timer, you can get time via pubnub_time() operation and |
sveljko | 1:929314a174af | 66 | later add the timer ticks to it. |
sveljko | 1:929314a174af | 67 | Last but not the least, there is the @p io_clock_seq, which is |
sveljko | 1:929314a174af | 68 | generally used if the UUID generator gets the @p i_node and |
sveljko | 1:929314a174af | 69 | @i_timestamp itself and also keep the state, which we don't do, |
sveljko | 1:929314a174af | 70 | for greater portability. We emulate this, by keeping a copy (in |
sveljko | 1:929314a174af | 71 | volatile memory) of the last time-stamp and seeing if it changes |
sveljko | 1:929314a174af | 72 | and assuming that node changes at first call, so we require the |
sveljko | 1:929314a174af | 73 | user to gives a random number for the clock sequence on first |
sveljko | 1:929314a174af | 74 | call. So, basically, on the first call, put a random value in @p |
sveljko | 1:929314a174af | 75 | io_clock_seq, and later just re-use the same variable, this |
sveljko | 1:929314a174af | 76 | function will update it as needed. If you don't have random number |
sveljko | 1:929314a174af | 77 | generator, you can use any pseudo-random number source (say a |
sveljko | 1:929314a174af | 78 | timer tick or some other event counter) - actually use as many as |
sveljko | 1:929314a174af | 79 | you have and mix the values (the simplest option is just to XOR |
sveljko | 1:929314a174af | 80 | the values you have, other is to make a message digest (MD5, |
sveljko | 1:929314a174af | 81 | SHA-1) of all the values). |
sveljko | 1:929314a174af | 82 | |
sveljko | 1:929314a174af | 83 | While rather complex to use, it is very portable and can be made |
sveljko | 1:929314a174af | 84 | to work, with effort, on pretty much any platform, without the |
sveljko | 1:929314a174af | 85 | need to obtain unique identifiers yourself (like you need to do |
sveljko | 1:929314a174af | 86 | for v3 and v5). |
sveljko | 1:929314a174af | 87 | @param o_uuid The place to put the generated UUID to |
sveljko | 1:929314a174af | 88 | @param io_clock_seq Clock Sequence - initialize to a random |
sveljko | 1:929314a174af | 89 | value on first call, later just reuse |
sveljko | 1:929314a174af | 90 | @param i_timestamp Count of 100- nanosecond intervals since |
sveljko | 1:929314a174af | 91 | 00:00:00.00, 15 October 1582 (the date of Gregorian reform to the |
sveljko | 1:929314a174af | 92 | Christian calendar). |
sveljko | 1:929314a174af | 93 | @param i_node A 6-octet "node" identity. Designed to be |
sveljko | 1:929314a174af | 94 | an IEEE 802 MAC address, but if you don't have it on |
sveljko | 1:929314a174af | 95 | your system, you can use something else. |
sveljko | 1:929314a174af | 96 | |
sveljko | 1:929314a174af | 97 | @return 0: OK (generated), otherwise: error, algorithm not available |
sveljko | 1:929314a174af | 98 | */ |
sveljko | 1:929314a174af | 99 | int pubnub_generate_uuid_v1_time(struct Pubnub_UUID *o_uuid, |
sveljko | 1:929314a174af | 100 | uint16_t *io_clock_seq, |
sveljko | 1:929314a174af | 101 | uint8_t const i_timestamp[8], |
sveljko | 1:929314a174af | 102 | uint8_t const i_node[6] |
sveljko | 1:929314a174af | 103 | ); |
sveljko | 1:929314a174af | 104 | |
sveljko | 1:929314a174af | 105 | /** The name based algorithms (this - v3 and the other - v5) don't |
sveljko | 1:929314a174af | 106 | need any other state but the arguments they declare. |
sveljko | 1:929314a174af | 107 | But, they do need a hash, in this case MD5. For various |
sveljko | 1:929314a174af | 108 | reasons, a particular hash may not be available on |
sveljko | 1:929314a174af | 109 | a particular platform. |
sveljko | 1:929314a174af | 110 | @param uuid The place to put the generated UUID to |
sveljko | 1:929314a174af | 111 | @param nsid The UUID of the namespace used. We provide |
sveljko | 1:929314a174af | 112 | a few examples. |
sveljko | 1:929314a174af | 113 | @param name Pointer to the data that defines the name |
sveljko | 1:929314a174af | 114 | you want to use for UUID generation |
sveljko | 1:929314a174af | 115 | @param namelen The length of the @p name data |
sveljko | 1:929314a174af | 116 | @return 0: OK (generated), otherwise: error, algorithm not available |
sveljko | 1:929314a174af | 117 | */ |
sveljko | 1:929314a174af | 118 | int pubnub_generate_uuid_v3_name_md5(struct Pubnub_UUID *uuid, |
sveljko | 1:929314a174af | 119 | struct Pubnub_UUID *nsid, |
sveljko | 1:929314a174af | 120 | void *name, |
sveljko | 1:929314a174af | 121 | unsigned namelen |
sveljko | 1:929314a174af | 122 | ); |
sveljko | 1:929314a174af | 123 | |
sveljko | 1:929314a174af | 124 | /** The nice property of this random-base algorithm is that it needs |
sveljko | 1:929314a174af | 125 | no state what-so-ever. A not so nice property is that it needs a |
sveljko | 1:929314a174af | 126 | random number generator of good quality, and you may not have |
sveljko | 1:929314a174af | 127 | that on a particular platform. |
sveljko | 1:929314a174af | 128 | @param uuid The place to put the generated UUID to |
sveljko | 1:929314a174af | 129 | @return 0: OK (generated), otherwise: error, random number generator |
sveljko | 1:929314a174af | 130 | not available |
sveljko | 1:929314a174af | 131 | */ |
sveljko | 1:929314a174af | 132 | int pubnub_generate_uuid_v4_random(struct Pubnub_UUID *uuid); |
sveljko | 1:929314a174af | 133 | |
sveljko | 1:929314a174af | 134 | /** The name based algorithms (this - v5 and the other - v3) don't |
sveljko | 1:929314a174af | 135 | need any other state but the arguments they declare. |
sveljko | 1:929314a174af | 136 | But, they do need a hash, in this case SHA-1. For various |
sveljko | 1:929314a174af | 137 | reasons, a particular hash may not be available on |
sveljko | 1:929314a174af | 138 | a particular platform. |
sveljko | 1:929314a174af | 139 | @param uuid The place to put the generated UUID to |
sveljko | 1:929314a174af | 140 | @param nsid The UUID of the namespace used. We provide |
sveljko | 1:929314a174af | 141 | a few examples. |
sveljko | 1:929314a174af | 142 | @param name Pointer to the data that defines the name |
sveljko | 1:929314a174af | 143 | you want to use for UUID generation |
sveljko | 1:929314a174af | 144 | @param namelen The length of the @p name data |
sveljko | 1:929314a174af | 145 | @return 0: OK (generated), otherwise: error, algorithm not available |
sveljko | 1:929314a174af | 146 | */ |
sveljko | 1:929314a174af | 147 | int pubnub_generate_uuid_v5_name_sha1(struct Pubnub_UUID *uuid, |
sveljko | 1:929314a174af | 148 | struct Pubnub_UUID *nsid, |
sveljko | 1:929314a174af | 149 | void *name, |
sveljko | 1:929314a174af | 150 | unsigned namelen |
sveljko | 1:929314a174af | 151 | ); |
sveljko | 1:929314a174af | 152 | |
sveljko | 1:929314a174af | 153 | |
sveljko | 1:929314a174af | 154 | /** Returns UUID as a standard HEX-based representation */ |
sveljko | 1:929314a174af | 155 | struct Pubnub_UUID_String pubnub_uuid_to_string(struct Pubnub_UUID const *uuid); |
sveljko | 1:929314a174af | 156 | |
sveljko | 1:929314a174af | 157 | /** Compares two UUIDs (@p left and @p right) and returns: |
sveljko | 1:929314a174af | 158 | - 0: equal |
sveljko | 1:929314a174af | 159 | - <0: left < right |
sveljko | 1:929314a174af | 160 | - >0: left > right |
sveljko | 1:929314a174af | 161 | */ |
sveljko | 1:929314a174af | 162 | int pubnub_uuid_compare(struct Pubnub_UUID const *left, struct Pubnub_UUID const *right); |
sveljko | 1:929314a174af | 163 | |
sveljko | 1:929314a174af | 164 | |
sveljko | 1:929314a174af | 165 | #endif /* !defined INC_PUBNUB_GENERATE_UUID */ |