blob: 288ca824b083855f1c58f0e1792c07d391c94515 [file] [log] [blame]
Olivier Houcharde962fd82017-08-07 19:20:04 +02001/*
2 * include/common/net_helper.h
3 * This file contains miscellaneous network helper functions.
4 *
5 * Copyright (C) 2017 Olivier Houchard
Willy Tarreaud5370e12017-09-19 14:59:52 +02006 * Copyright (C) 2017 Willy Tarreau
Olivier Houcharde962fd82017-08-07 19:20:04 +02007 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27#ifndef _COMMON_NET_HELPER_H
28#define _COMMON_NET_HELPER_H
29
Willy Tarreaud5370e12017-09-19 14:59:52 +020030#include <common/compiler.h>
Olivier Houcharde962fd82017-08-07 19:20:04 +020031#include <arpa/inet.h>
32
Willy Tarreau2888c082017-09-19 17:27:05 +020033/* Functions to read/write various integers that may be unaligned */
Olivier Houcharde962fd82017-08-07 19:20:04 +020034
Willy Tarreaud5370e12017-09-19 14:59:52 +020035/* Read a uint16_t in native host order */
36static inline uint16_t read_u16(const void *p)
Olivier Houcharde962fd82017-08-07 19:20:04 +020037{
38 const union { uint16_t u16; } __attribute__((packed))*u = p;
39 return u->u16;
40}
41
Willy Tarreau2888c082017-09-19 17:27:05 +020042/* Write a uint16_t in native host order */
43static inline void write_u16(void *p, const uint16_t u16)
44{
45 union { uint16_t u16; } __attribute__((packed))*u = p;
46 u->u16 = u16;
47}
48
Willy Tarreaud5370e12017-09-19 14:59:52 +020049/* Read a uint32_t in native host order */
50static inline uint32_t read_u32(const void *p)
Olivier Houcharde962fd82017-08-07 19:20:04 +020051{
Willy Tarreaud5370e12017-09-19 14:59:52 +020052 const union { uint32_t u32; } __attribute__((packed))*u = p;
53 return u->u32;
Olivier Houcharde962fd82017-08-07 19:20:04 +020054}
55
Willy Tarreau2888c082017-09-19 17:27:05 +020056/* Write a uint32_t in native host order */
57static inline void write_u32(void *p, const uint32_t u32)
58{
59 union { uint32_t u32; } __attribute__((packed))*u = p;
60 u->u32 = u32;
61}
62
Willy Tarreaud5370e12017-09-19 14:59:52 +020063/* Read a possibly wrapping number of bytes <bytes> into destination <dst>. The
64 * first segment is composed of <s1> bytes at p1. The remaining byte(s), if any,
65 * are read from <p2>. <s1> may be zero and may also be larger than <bytes>. The
66 * caller is always responsible for providing enough bytes. Note: the function
67 * is purposely *not* marked inline to let the compiler decide what to do with
68 * it, because it's around 34 bytes long, placed on critical path but rarely
69 * called, and uses uses a lot of arguments if not inlined. The compiler will
70 * thus decide what's best to do with it depending on the context.
71 */
72static void readv_bytes(void *dst, const size_t bytes, const void *p1, size_t s1, const void *p2)
Olivier Houcharde962fd82017-08-07 19:20:04 +020073{
Willy Tarreaud5370e12017-09-19 14:59:52 +020074 size_t idx;
75
76 p2 -= s1;
77 for (idx = 0; idx < bytes; idx++) {
78 if (idx == s1)
79 p1 = p2;
80 ((uint8_t *)dst)[idx] = ((const uint8_t *)p1)[idx];
81 }
82 /* this memory barrier is critical otherwise gcc may over-optimize this
83 * code, completely removing it as well as any surrounding boundary
84 * check (4.7.1..6.4.0)!
85 */
86 __asm__ volatile("" ::: "memory");
Olivier Houcharde962fd82017-08-07 19:20:04 +020087}
88
Willy Tarreau2888c082017-09-19 17:27:05 +020089/* Write a possibly wrapping number of bytes <bytes> from location <src>. The
90 * first segment is composed of <s1> bytes at p1. The remaining byte(s), if any,
91 * are written to <p2>. <s1> may be zero and may also be larger than <bytes>.
92 * The caller is always responsible for providing enough room. Note: the
93 * function is purposely *not* marked inline to let the compiler decide what to
94 * do with it, because it's around 34 bytes long, placed on critical path but
95 * rarely called, and uses uses a lot of arguments if not inlined. The compiler
96 * will thus decide what's best to do with it depending on the context.
97 */
98static void writev_bytes(const void *src, const size_t bytes, void *p1, size_t s1, void *p2)
99{
100 size_t idx;
101
102 p2 -= s1;
103 for (idx = 0; idx < bytes; idx++) {
104 if (idx == s1)
105 p1 = p2;
106 ((uint8_t *)p1)[idx] = ((const uint8_t *)src)[idx];
107 }
108}
109
Willy Tarreaud5370e12017-09-19 14:59:52 +0200110/* Read a possibly wrapping uint16_t in native host order. The first segment is
111 * composed of <s1> bytes at p1. The remaining byte(s), if any, are read from
112 * <p2>. <s1> may be zero and may be larger than the type. The caller is always
113 * responsible for providing enough bytes.
114 */
115static inline uint16_t readv_u16(const void *p1, size_t s1, const void *p2)
Olivier Houcharde962fd82017-08-07 19:20:04 +0200116{
Willy Tarreaud5370e12017-09-19 14:59:52 +0200117 if (unlikely(s1 == 1)) {
118 volatile uint16_t u16;
119
120 ((uint8_t *)&u16)[0] = *(uint8_t *)p1;
121 ((uint8_t *)&u16)[1] = *(uint8_t *)p2;
122 return u16;
123 }
124 else {
125 const union { uint16_t u16; } __attribute__((packed)) *u;
126
127 u = (s1 == 0) ? p2 : p1;
128 return u->u16;
129 }
130}
131
Willy Tarreau2888c082017-09-19 17:27:05 +0200132/* Write a possibly wrapping uint16_t in native host order. The first segment is
133 * composed of <s1> bytes at p1. The remaining byte(s), if any, are written to
134 * <p2>. <s1> may be zero and may be larger than the type. The caller is always
135 * responsible for providing enough room.
136 */
137static inline void writev_u16(void *p1, size_t s1, void *p2, const uint16_t u16)
138{
139 union { uint16_t u16; } __attribute__((packed)) *u;
140
141 if (unlikely(s1 == 1)) {
142 *(uint8_t *)p1 = ((const uint8_t *)&u16)[0];
143 *(uint8_t *)p2 = ((const uint8_t *)&u16)[1];
144 }
145 else {
146 u = (s1 == 0) ? p2 : p1;
147 u->u16 = u16;
148 }
149}
150
Willy Tarreaud5370e12017-09-19 14:59:52 +0200151/* Read a possibly wrapping uint32_t in native host order. The first segment is
152 * composed of <s1> bytes at p1. The remaining byte(s), if any, are read from
153 * <p2>. <s1> may be zero and may be larger than the type. The caller is always
154 * responsible for providing enough bytes.
155 */
156static inline uint32_t readv_u32(const void *p1, size_t s1, const void *p2)
157{
158 uint32_t u32;
159
160 if (!unlikely(s1 < sizeof(u32)))
161 u32 = read_u32(p1);
162 else
163 readv_bytes(&u32, sizeof(u32), p1, s1, p2);
164 return u32;
165}
166
Willy Tarreau2888c082017-09-19 17:27:05 +0200167/* Write a possibly wrapping uint32_t in native host order. The first segment is
168 * composed of <s1> bytes at p1. The remaining byte(s), if any, are written to
169 * <p2>. <s1> may be zero and may be larger than the type. The caller is always
170 * responsible for providing enough room.
171 */
172static inline void writev_u32(void *p1, size_t s1, void *p2, const uint32_t u32)
173{
174 if (!unlikely(s1 < sizeof(u32)))
175 write_u32(p1, u32);
176 else
177 writev_bytes(&u32, sizeof(u32), p1, s1, p2);
178}
179
Willy Tarreaud5370e12017-09-19 14:59:52 +0200180/* Signed integer versions : return the same data but signed */
181
182/* Read an int16_t in native host order */
183static inline int16_t read_i16(const void *p)
184{
185 return read_u16(p);
Olivier Houcharde962fd82017-08-07 19:20:04 +0200186}
187
Willy Tarreaud5370e12017-09-19 14:59:52 +0200188/* Read an int32_t in native host order */
189static inline int32_t read_i32(const void *p)
Olivier Houcharde962fd82017-08-07 19:20:04 +0200190{
Willy Tarreaud5370e12017-09-19 14:59:52 +0200191 return read_u32(p);
Olivier Houcharde962fd82017-08-07 19:20:04 +0200192}
193
Willy Tarreaud5370e12017-09-19 14:59:52 +0200194/* Read a possibly wrapping int16_t in native host order */
195static inline int16_t readv_i16(const void *p1, size_t s1, const void *p2)
196{
197 return readv_u16(p1, s1, p2);
198}
199
200/* Read a possibly wrapping int32_t in native host order */
201static inline int32_t readv_i32(const void *p1, size_t s1, const void *p2)
202{
203 return readv_u32(p1, s1, p2);
204}
205
206/* Read a uint16_t, and convert from network order to host order */
207static inline uint16_t read_n16(const void *p)
208{
209 return ntohs(read_u16(p));
210}
211
Willy Tarreau2888c082017-09-19 17:27:05 +0200212/* Write a uint16_t after converting it from host order to network order */
213static inline void write_n16(void *p, const uint16_t u16)
214{
215 write_u16(p, htons(u16));
216}
217
Olivier Houcharde962fd82017-08-07 19:20:04 +0200218/* Read a uint32_t, and convert from network order to host order */
Willy Tarreaud5370e12017-09-19 14:59:52 +0200219static inline uint32_t read_n32(const void *p)
Olivier Houcharde962fd82017-08-07 19:20:04 +0200220{
Willy Tarreaud5370e12017-09-19 14:59:52 +0200221 return ntohl(read_u32(p));
222}
223
Willy Tarreau2888c082017-09-19 17:27:05 +0200224/* Write a uint32_t after converting it from host order to network order */
225static inline void write_n32(void *p, const uint32_t u32)
226{
227 write_u32(p, htonl(u32));
228}
229
Willy Tarreaud5370e12017-09-19 14:59:52 +0200230/* Read a possibly wrapping uint16_t in network order. The first segment is
231 * composed of <s1> bytes at p1. The remaining byte(s), if any, are read from
232 * <p2>. <s1> may be zero and may be larger than the type. The caller is always
233 * responsible for providing enough bytes.
234 */
235static inline uint16_t readv_n16(const void *p1, size_t s1, const void *p2)
236{
237 if (unlikely(s1 < 2)) {
238 if (s1 == 0)
239 p1 = p2++;
240 }
241 else
242 p2 = p1 + 1;
243 return (*(uint8_t *)p1 << 8) + *(uint8_t *)p2;
244}
245
Willy Tarreau2888c082017-09-19 17:27:05 +0200246/* Write a possibly wrapping uint16_t in network order. The first segment is
247 * composed of <s1> bytes at p1. The remaining byte(s), if any, are written to
248 * <p2>. <s1> may be zero and may be larger than the type. The caller is always
249 * responsible for providing enough room.
250 */
251static inline void writev_n16(const void *p1, size_t s1, const void *p2, const uint16_t u16)
252{
253 if (unlikely(s1 < 2)) {
254 if (s1 == 0)
255 p1 = p2++;
256 }
257 else
258 p2 = p1 + 1;
259 *(uint8_t *)p1 = u16 >> 8;
260 *(uint8_t *)p2 = u16;
261}
262
Willy Tarreaud5370e12017-09-19 14:59:52 +0200263/* Read a possibly wrapping uint32_t in network order. The first segment is
264 * composed of <s1> bytes at p1. The remaining byte(s), if any, are read from
265 * <p2>. <s1> may be zero and may be larger than the type. The caller is always
266 * responsible for providing enough bytes.
267 */
268static inline uint32_t readv_n32(const void *p1, size_t s1, const void *p2)
269{
270 return ntohl(readv_u32(p1, s1, p2));
Olivier Houcharde962fd82017-08-07 19:20:04 +0200271}
272
Willy Tarreau2888c082017-09-19 17:27:05 +0200273/* Write a possibly wrapping uint32_t in network order. The first segment is
274 * composed of <s1> bytes at p1. The remaining byte(s), if any, are written to
275 * <p2>. <s1> may be zero and may be larger than the type. The caller is always
276 * responsible for providing enough room.
277 */
278static inline void writev_n32(void *p1, size_t s1, void *p2, const uint32_t u32)
279{
280 writev_u32(p1, s1, p2, htonl(u32));
281}
282
Olivier Houcharde962fd82017-08-07 19:20:04 +0200283#endif /* COMMON_NET_HELPER_H */