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