1 /*
2 * ngtcp2
3 *
4 * Copyright (c) 2017 ngtcp2 contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "ngtcp2_str.h"
26
27 #include <string.h>
28
29 #include "ngtcp2_macro.h"
30
ngtcp2_cpymem(void * dest,const void * src,size_t n)31 void *ngtcp2_cpymem(void *dest, const void *src, size_t n) {
32 memcpy(dest, src, n);
33 return (uint8_t *)dest + n;
34 }
35
ngtcp2_setmem(uint8_t * dest,uint8_t b,size_t n)36 uint8_t *ngtcp2_setmem(uint8_t *dest, uint8_t b, size_t n) {
37 memset(dest, b, n);
38 return dest + n;
39 }
40
41 #define LOWER_XDIGITS "0123456789abcdef"
42
ngtcp2_encode_hex(uint8_t * dest,const uint8_t * data,size_t len)43 uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len) {
44 size_t i;
45 uint8_t *p = dest;
46
47 for (i = 0; i < len; ++i) {
48 *p++ = (uint8_t)LOWER_XDIGITS[data[i] >> 4];
49 *p++ = (uint8_t)LOWER_XDIGITS[data[i] & 0xf];
50 }
51
52 *p = '\0';
53
54 return dest;
55 }
56
ngtcp2_encode_printable_ascii(char * dest,const uint8_t * data,size_t len)57 char *ngtcp2_encode_printable_ascii(char *dest, const uint8_t *data,
58 size_t len) {
59 size_t i;
60 char *p = dest;
61 uint8_t c;
62
63 for (i = 0; i < len; ++i) {
64 c = data[i];
65 if (0x20 <= c && c <= 0x7e) {
66 *p++ = (char)c;
67 } else {
68 *p++ = '.';
69 }
70 }
71
72 *p = '\0';
73
74 return dest;
75 }
76
77 /*
78 * write_uint writes |n| to the buffer pointed by |p| in decimal
79 * representation. It returns |p| plus the number of bytes written.
80 * The function assumes that the buffer has enough capacity to contain
81 * a string.
82 */
write_uint(uint8_t * p,uint64_t n)83 static uint8_t *write_uint(uint8_t *p, uint64_t n) {
84 size_t nlen = 0;
85 uint64_t t;
86 uint8_t *res;
87
88 if (n == 0) {
89 *p++ = '0';
90 return p;
91 }
92 for (t = n; t; t /= 10, ++nlen)
93 ;
94 p += nlen;
95 res = p;
96 for (; n; n /= 10) {
97 *--p = (uint8_t)((n % 10) + '0');
98 }
99 return res;
100 }
101
ngtcp2_encode_ipv4(uint8_t * dest,const uint8_t * addr)102 uint8_t *ngtcp2_encode_ipv4(uint8_t *dest, const uint8_t *addr) {
103 size_t i;
104 uint8_t *p = dest;
105
106 p = write_uint(p, addr[0]);
107
108 for (i = 1; i < 4; ++i) {
109 *p++ = '.';
110 p = write_uint(p, addr[i]);
111 }
112
113 *p = '\0';
114
115 return dest;
116 }
117
118 /*
119 * write_hex_zsup writes the content of buffer pointed by |data| of
120 * length |len| to |dest| in hex string. Any leading zeros are
121 * suppressed. It returns |dest| plus the number of bytes written.
122 */
write_hex_zsup(uint8_t * dest,const uint8_t * data,size_t len)123 static uint8_t *write_hex_zsup(uint8_t *dest, const uint8_t *data, size_t len) {
124 size_t i;
125 uint8_t *p = dest;
126 uint8_t d;
127
128 for (i = 0; i < len; ++i) {
129 d = data[i];
130 if (d >> 4) {
131 break;
132 }
133
134 d &= 0xf;
135
136 if (d) {
137 *p++ = (uint8_t)LOWER_XDIGITS[d];
138 ++i;
139 break;
140 }
141 }
142
143 if (p == dest && i == len) {
144 *p++ = '0';
145 return p;
146 }
147
148 for (; i < len; ++i) {
149 d = data[i];
150 *p++ = (uint8_t)LOWER_XDIGITS[d >> 4];
151 *p++ = (uint8_t)LOWER_XDIGITS[d & 0xf];
152 }
153
154 return p;
155 }
156
ngtcp2_encode_ipv6(uint8_t * dest,const uint8_t * addr)157 uint8_t *ngtcp2_encode_ipv6(uint8_t *dest, const uint8_t *addr) {
158 uint16_t blks[8];
159 size_t i;
160 size_t zlen, zoff;
161 size_t max_zlen = 0, max_zoff = 8;
162 uint8_t *p = dest;
163
164 for (i = 0; i < 16; i += sizeof(uint16_t)) {
165 /* Copy in network byte order. */
166 memcpy(&blks[i / sizeof(uint16_t)], addr + i, sizeof(uint16_t));
167 }
168
169 for (i = 0; i < 8;) {
170 if (blks[i]) {
171 ++i;
172 continue;
173 }
174
175 zlen = 1;
176 zoff = i;
177
178 ++i;
179 for (; i < 8 && blks[i] == 0; ++i, ++zlen)
180 ;
181 if (zlen > max_zlen) {
182 max_zlen = zlen;
183 max_zoff = zoff;
184 }
185 }
186
187 /* Do not suppress a single '0' block */
188 if (max_zlen == 1) {
189 max_zoff = 8;
190 }
191
192 if (max_zoff != 0) {
193 p = write_hex_zsup(p, (const uint8_t *)blks, sizeof(uint16_t));
194
195 for (i = 1; i < max_zoff; ++i) {
196 *p++ = ':';
197 p = write_hex_zsup(p, (const uint8_t *)(blks + i), sizeof(uint16_t));
198 }
199 }
200
201 if (max_zoff != 8) {
202 *p++ = ':';
203
204 if (max_zoff + max_zlen == 8) {
205 *p++ = ':';
206 } else {
207 for (i = max_zoff + max_zlen; i < 8; ++i) {
208 *p++ = ':';
209 p = write_hex_zsup(p, (const uint8_t *)(blks + i), sizeof(uint16_t));
210 }
211 }
212 }
213
214 *p = '\0';
215
216 return dest;
217 }
218
ngtcp2_cmemeq(const uint8_t * a,const uint8_t * b,size_t n)219 int ngtcp2_cmemeq(const uint8_t *a, const uint8_t *b, size_t n) {
220 size_t i;
221 int rv = 0;
222
223 for (i = 0; i < n; ++i) {
224 rv |= a[i] ^ b[i];
225 }
226
227 return rv == 0;
228 }
229