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
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.
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.
44 #include <sys/socket.h>
45 #include <netinet/in.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
)
57 res
= a
->sa_family
- b
->sa_family
;
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);
69 res
= memcmp (&a4
->sin_port
, &b4
->sin_port
, 2);
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);
79 res
= a6
->sin6_scope_id
- b6
->sin6_scope_id
;
81 res
= memcmp (&a6
->sin6_port
, &b6
->sin6_port
, 2);
91 bool stun_optional (uint16_t t
)
93 return (t
>> 15) == 1;
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
)
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];
127 /* * @param msg valid STUN message */
128 /* * @return true if there is at least one unknown mandatory attribute. */
130 /* bool stun_has_unknown (const void *msg) */
132 /* uint16_t dummy; */
133 /* return stun_find_unknown (msg, &dummy, 1); */
136 static int debug_enabled
= 0;
138 void stun_debug_enable (void) {
141 void stun_debug_disable (void) {
145 void stun_debug (const char *fmt
, ...)
150 vfprintf (stderr
, fmt
, ap
);
155 void stun_debug_bytes (const void *data
, size_t len
)
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
)
172 struct sockaddr_in
*ip4
= (struct sockaddr_in
*)addr
;
173 if (addrlen
< sizeof (*ip4
))
176 ip4
->sin_port
^= htons (magic_cookie
>> 16);
177 ip4
->sin_addr
.s_addr
^= htonl (magic_cookie
);
183 struct sockaddr_in6
*ip6
= (struct sockaddr_in6
*)addr
;
186 if (addrlen
< sizeof (*ip6
))
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
];
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
209 int stun_memcmp (const StunMessage
*msg
, stun_attr_type_t type
,
210 const void *data
, size_t len
)
213 const void *ptr
= stun_message_find (msg
, type
, &alen
);
217 if ((len
!= alen
) || memcmp (ptr
, data
, len
))
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
)
240 *ptr
++ = value
& 0xff;
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
)
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";
300 for (i
= 0; i
< (sizeof (tab
) / sizeof (tab
[0])); i
++)
302 if (tab
[i
].code
== code
)
309 /* Maximum allowed error message length */
310 // assert (strlen (str) < 128);