我知道ntoh{s,l}
和hton{s,l}
,它们适用于2和4字节的整数。现在,我遇到了一个问题,需要翻译一个长度为16字节的IPv6地址。
是否有一个现成的函数可以解决这个问题?
谢谢, Jir
我知道ntoh{s,l}
和hton{s,l}
,它们适用于2和4字节的整数。现在,我遇到了一个问题,需要翻译一个长度为16字节的IPv6地址。
是否有一个现成的函数可以解决这个问题?
谢谢, Jir
ntoh
和hton
的相关内容。你没有本地的128位类型,对吧?3.2 IPv6 Address Structure
A new in6_addr structure holds a single IPv6 address and is defined as a result of including :
struct in6_addr { uint8_t s6_addr[16]; /* IPv6 address */ };
This data structure contains an array of sixteen 8-bit elements, which make up one 128-bit IPv6 address. The IPv6 address is stored in network byte order.
The structure in6_addr above is usually implemented with an embedded union with extra fields that force the desired alignment level in a manner similar to BSD implementations of "struct in_addr". Those additional implementation details are omitted here for simplicity.
An example is as follows:
struct in6_addr { union { uint8_t _S6_u8[16]; uint32_t _S6_u32[4]; uint64_t _S6_u64[2]; } _S6_un; }; #define s6_addr _S6_un._S6_u8
警告:如果C预处理器(例如cpp)逐字替换每个s6_addr实例为_S6_un._S6_u8,则务必仅在正确的上下文中使用s6_addr的值。例如,您不能将函数、数据类型或原型命名为's6_addr',因为'void *s6_addr();'会产生无效语法'void *_S6_un._S6_u8();'。
请注意,此代码无法编译:
struct in6_addr {
union {
unsigned char _S6_u8[16];
unsigned long _S6_u32[4];
unsigned long long _S6_u64[2];
} _S6_un;
};
#define s6_addr _S6_un._S6_u8
void *s6_addr();
因此,#define 有一些需要注意的副作用。
是否有一种方法可以实现这个功能而不产生副作用?
IPv6需要网络顺序来处理ipv6地址。 hton和ntoh都是关于将地址从代码中存储的方式转换为它在数据包中需要存储的方式(反之亦然)。因此,问题变成了您在代码中存储它的方式。
此外,在代码中定义IPv6地址可以允许更多的寻址方式,而不仅仅是字节数组:
struct in6_addr
{
union
{
__u8 u6_addr8[16];
__u16 u6_addr16[8];
__u32 u6_addr32[4];
} in6_u;
#define s6_addr in6_u.u6_addr8
#define s6_addr16 in6_u.u6_addr16
#define s6_addr32 in6_u.u6_addr32
};
对于用户而言,IPv6地址被表示为8个16位值。如果您在代码中将地址存储为8个16位值,则需要在使用u6_addr16[]数组将其放入数据包时对每个16位值使用htons,并在从u6_addr16[]检索每个16位值时使用ntohs。
以下链接可能会有所帮助:
// Compile with gcc
#include <x86intrin.h>
#include <stdint.h>
#include <arpa/inet.h>
// C99 supports __int128!
typedef unsigned __int128 uint128_t;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define htonll(v) __builtin_bswap64((v))
uint128_t hton128(uint128_t val)
{
// SSE2 is defined if SSSE3.
# if __SSSE3__
// This routine is 100 cycles faster than the routine below.
__m128i m;
__m128i mask;
m = _mm_loadu_si128((__m128i *)&val);
// mask: 0x0f0e0d0c0b0a09080706050403020100
mask = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
_mm_store_si128((__m128i *)&val, _mm_shuffle_epi8(m, mask));
# else
// No SSSE3.. Slowest approach: use pointers to shuffle.
uint64_t *p, *q;
p = (uint64_t *)&val;
q = p + 1;
*p = htonll(*p);
*q = htonll(*q);
{
uint64_t t;
t = *p;
*p = *q;
*q = t;
}
# endif
return val;
}
#endif