document sockaddrcmp's return value
[sipe-libnice.git] / stun / utils.c
blob635bdba065fe317e8b4612321bdc8a1a28de3bf2
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2007 Nokia Corporation. All rights reserved.
5 * Contact: Rémi Denis-Courmont
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is the Nice GLib ICE library.
19 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
20 * Corporation. All Rights Reserved.
22 * Contributors:
23 * Rémi Denis-Courmont, Nokia
25 * Alternatively, the contents of this file may be used under the terms of the
26 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
27 * case the provisions of LGPL are applicable instead of those above. If you
28 * wish to allow use of your version of this file only under the terms of the
29 * LGPL and not to allow others to use your version of this file under the
30 * MPL, indicate your decision by deleting the provisions above and replace
31 * them with the notice and other provisions required by the LGPL. If you do
32 * not delete the provisions above, a recipient may use your version of this
33 * file under either the MPL or the LGPL.
36 #ifdef HAVE_CONFIG_H
37 # include <config.h>
38 #endif
40 #include <string.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <stdarg.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
47 #include <errno.h>
48 #include "utils.h"
50 /** Compares two socket addresses
51 * @return 0 if the addresses are equal, non-zero otherwise
53 int sockaddrcmp (const struct sockaddr *a, const struct sockaddr *b)
55 int res;
57 res = a->sa_family - b->sa_family;
58 if (res)
59 return res;
61 switch (a->sa_family)
63 case AF_INET:
65 const struct sockaddr_in *a4 = (const struct sockaddr_in *)a;
66 const struct sockaddr_in *b4 = (const struct sockaddr_in *)b;
67 res = memcmp (&a4->sin_addr, &b4->sin_addr, 4);
68 if (res == 0)
69 res = memcmp (&a4->sin_port, &b4->sin_port, 2);
70 break;
73 case AF_INET6:
75 const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *)a;
76 const struct sockaddr_in6 *b6 = (const struct sockaddr_in6 *)b;
77 res = memcmp (&a6->sin6_addr, &b6->sin6_addr, 16);
78 if (res == 0)
79 res = a6->sin6_scope_id - b6->sin6_scope_id;
80 if (res == 0)
81 res = memcmp (&a6->sin6_port, &b6->sin6_port, 2);
82 break;
86 return res;
91 bool stun_optional (uint16_t t)
93 return (t >> 15) == 1;
97 /**
98 * @return complement to the next multiple of 4.
100 size_t stun_padding (size_t l)
102 return (4 - (l & 3)) & 3;
107 * Rounds up an integer to the next multiple of 4.
109 size_t stun_align (size_t l)
111 return (l + 3) & ~3;
116 * Reads a word from a non-aligned buffer.
117 * @return host byte order word value.
119 uint16_t stun_getw (const uint8_t *ptr)
121 return ((ptr)[0] << 8) | ptr[1];
126 /* /\** */
127 /* * @param msg valid STUN message */
128 /* * @return true if there is at least one unknown mandatory attribute. */
129 /* *\/ */
130 /* bool stun_has_unknown (const void *msg) */
131 /* { */
132 /* uint16_t dummy; */
133 /* return stun_find_unknown (msg, &dummy, 1); */
134 /* } */
136 static int debug_enabled = 0;
138 void stun_debug_enable (void) {
139 debug_enabled = 1;
141 void stun_debug_disable (void) {
142 debug_enabled = 0;
145 void stun_debug (const char *fmt, ...)
147 va_list ap;
148 if (debug_enabled) {
149 va_start (ap, fmt);
150 vfprintf (stderr, fmt, ap);
151 va_end (ap);
155 void stun_debug_bytes (const void *data, size_t len)
157 size_t i;
159 stun_debug ("0x");
160 for (i = 0; i < len; i++)
161 stun_debug ("%02x", ((const unsigned char *)data)[i]);
164 int stun_xor_address (const StunMessage *msg,
165 struct sockaddr *restrict addr, socklen_t addrlen,
166 uint32_t magic_cookie)
168 switch (addr->sa_family)
170 case AF_INET:
172 struct sockaddr_in *ip4 = (struct sockaddr_in *)addr;
173 if (addrlen < sizeof (*ip4))
174 return EINVAL;
176 ip4->sin_port ^= htons (magic_cookie >> 16);
177 ip4->sin_addr.s_addr ^= htonl (magic_cookie);
178 return 0;
181 case AF_INET6:
183 struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)addr;
184 unsigned short i;
186 if (addrlen < sizeof (*ip6))
187 return EINVAL;
189 ip6->sin6_port ^= htons (magic_cookie >> 16);
190 for (i = 0; i < 16; i++)
191 ip6->sin6_addr.s6_addr[i] ^= msg->buffer[4 + i];
192 return 0;
195 return EAFNOSUPPORT;
199 * Compares the length and content of an attribute.
201 * @param msg valid STUN message buffer
202 * @param type STUN attribute type (host byte order)
203 * @param data pointer to value to compare with
204 * @param len byte length of the value
205 * @return 0 in case of match, ENOENT if attribute was not found,
206 * EINVAL if it did not match (different length, or same length but
207 * different content)
209 int stun_memcmp (const StunMessage *msg, stun_attr_type_t type,
210 const void *data, size_t len)
212 uint16_t alen;
213 const void *ptr = stun_message_find (msg, type, &alen);
214 if (ptr == NULL)
215 return ENOENT;
217 if ((len != alen) || memcmp (ptr, data, len))
218 return EINVAL;
219 return 0;
224 * Compares the content of an attribute with a string.
225 * @param msg valid STUN message buffer
226 * @param type STUN attribute type (host byte order)
227 * @param str string to compare with
228 * @return 0 in case of match, ENOENT if attribute was not found,
229 * EINVAL if it did not match
231 int stun_strcmp (const StunMessage *msg, stun_attr_type_t type, const char *str)
233 return stun_memcmp (msg, type, str, strlen (str));
237 void *stun_setw (uint8_t *ptr, uint16_t value)
239 *ptr++ = value >> 8;
240 *ptr++ = value & 0xff;
241 return ptr;
245 void stun_set_type (uint8_t *h, stun_class_t c, stun_method_t m)
247 /* assert (c < 4); */
248 /* assert (m < (1 << 12)); */
250 h[0] = (c >> 1) | ((m >> 6) & 0x3e);
251 h[1] = ((c << 4) & 0x10) | ((m << 1) & 0xe0) | (m & 0x0f);
253 /* assert (stun_getw (h) < (1 << 14)); */
254 /* assert (stun_get_class (h) == c); */
255 /* assert (stun_get_method (h) == m); */
260 * @param code host-byte order error code
261 * @return a static pointer to a nul-terminated error message string.
263 const char *stun_strerror (stun_error_t code)
265 static const struct
267 stun_error_t code;
268 char phrase[32];
269 } tab[] =
271 { STUN_ERROR_TRY_ALTERNATE, "Try alternate server" },
272 { STUN_ERROR_BAD_REQUEST, "Bad request" },
273 { STUN_ERROR_UNAUTHORIZED, "Authorization required" },
274 { STUN_ERROR_UNKNOWN_ATTRIBUTE, "Unknown attribute" },
276 { STUN_STALE_CREDENTIALS, "Authentication expired" },
277 { STUN_INTEGRITY_CHECK_FAILURE, "Incorrect username/password" },
278 { STUN_MISSING_USERNAME, "Username required" },
279 { STUN_USE_TLS, "Secure connection required" },
280 { STUN_MISSING_REALM, "Authentication domain required" },
281 { STUN_MISSING_NONCE, "Authentication token missing" },
282 { STUN_UNKNOWN_USERNAME, "Unknown user name" },
284 { STUN_ERROR_NO_BINDING, "Session expired" },
285 { STUN_ERROR_STALE_NONCE, "Authentication token expired" },
286 { STUN_ERROR_ACT_DST_ALREADY, "Changing remote peer forbidden" },
287 { STUN_ERROR_UNSUPP_TRANSPORT, "Unknown transport protocol" },
288 { STUN_ERROR_INVALID_IP, "Address unavailable" },
289 { STUN_ERROR_INVALID_PORT, "Port unavailable" },
290 { STUN_ERROR_OP_TCP_ONLY, "Invalid operation" },
291 { STUN_ERROR_CONN_ALREADY, "Connection already established" },
292 { STUN_ERROR_ALLOC_OVER_QUOTA, "Quota reached" },
293 { STUN_ERROR_ROLE_CONFLICT, "Role conflict" },
294 { STUN_ERROR_SERVER_ERROR, "Temporary server error" },
295 { STUN_ERROR_SERVER_CAPACITY, "Temporary server congestion" },
297 const char *str = "Unknown error";
298 size_t i;
300 for (i = 0; i < (sizeof (tab) / sizeof (tab[0])); i++)
302 if (tab[i].code == code)
304 str = tab[i].phrase;
305 break;
309 /* Maximum allowed error message length */
310 // assert (strlen (str) < 128);
311 return str;