~ubuntu-branches/debian/squeeze/libnice/squeeze

« back to all changes in this revision

Viewing changes to stun/utils.c

  • Committer: Bazaar Package Importer
  • Author(s): Laurent Bigonville
  • Date: 2009-01-04 17:45:34 UTC
  • Revision ID: james.westby@ubuntu.com-20090104174534-dh5u1pfonumqa99c
Tags: upstream-0.0.4
Import upstream version 0.0.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of the Nice GLib ICE library.
 
3
 *
 
4
 * (C) 2007 Nokia Corporation. All rights reserved.
 
5
 *  Contact: Rémi Denis-Courmont
 
6
 *
 
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/
 
11
 *
 
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.
 
16
 *
 
17
 * The Original Code is the Nice GLib ICE library.
 
18
 *
 
19
 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
 
20
 * Corporation. All Rights Reserved.
 
21
 *
 
22
 * Contributors:
 
23
 *   Rémi Denis-Courmont, Nokia
 
24
 *
 
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.
 
34
 */
 
35
 
 
36
#ifdef HAVE_CONFIG_H
 
37
# include <config.h>
 
38
#endif
 
39
 
 
40
#include <string.h>
 
41
#include <stdlib.h>
 
42
#include <stdio.h>
 
43
#include <stdarg.h>
 
44
 
 
45
#ifdef _WIN32
 
46
#define ENOENT -1
 
47
#define EINVAL -2
 
48
#define ENOBUFS -3
 
49
#define EAFNOSUPPORT -4
 
50
#else
 
51
#include <errno.h>
 
52
#endif
 
53
 
 
54
#include "utils.h"
 
55
 
 
56
/** Compares two socket addresses
 
57
 * @return 0 if the addresses are equal, non-zero otherwise
 
58
 */
 
59
int sockaddrcmp (const struct sockaddr *a, const struct sockaddr *b)
 
60
{
 
61
  int res;
 
62
 
 
63
  res = a->sa_family - b->sa_family;
 
64
  if (res)
 
65
    return res;
 
66
 
 
67
  switch (a->sa_family)
 
68
  {
 
69
    case AF_INET:
 
70
    {
 
71
      const struct sockaddr_in *a4 = (const struct sockaddr_in *)a;
 
72
      const struct sockaddr_in *b4 = (const struct sockaddr_in *)b;
 
73
      res = memcmp (&a4->sin_addr, &b4->sin_addr, 4);
 
74
      if (res == 0)
 
75
        res = memcmp (&a4->sin_port, &b4->sin_port, 2);
 
76
      break;
 
77
    }
 
78
 
 
79
    case AF_INET6:
 
80
    {
 
81
      const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *)a;
 
82
      const struct sockaddr_in6 *b6 = (const struct sockaddr_in6 *)b;
 
83
      res = memcmp (&a6->sin6_addr, &b6->sin6_addr, 16);
 
84
      if (res == 0)
 
85
        res = a6->sin6_scope_id - b6->sin6_scope_id;
 
86
      if (res == 0)
 
87
        res = memcmp (&a6->sin6_port, &b6->sin6_port, 2);
 
88
      break;
 
89
    }
 
90
  }
 
91
 
 
92
  return res;
 
93
}
 
94
 
 
95
 
 
96
 
 
97
bool stun_optional (uint16_t t)
 
98
{
 
99
  return (t >> 15) == 1;
 
100
}
 
101
 
 
102
 
 
103
/**
 
104
 * @return complement to the next multiple of 4.
 
105
 */
 
106
size_t stun_padding (size_t l)
 
107
{
 
108
  return (4 - (l & 3)) & 3;
 
109
}
 
110
 
 
111
 
 
112
/**
 
113
 * Rounds up an integer to the next multiple of 4.
 
114
 */
 
115
size_t stun_align (size_t l)
 
116
{
 
117
  return (l + 3) & ~3;
 
118
}
 
119
 
 
120
 
 
121
/**
 
122
 * Reads a word from a non-aligned buffer.
 
123
 * @return host byte order word value.
 
124
 */
 
125
uint16_t stun_getw (const uint8_t *ptr)
 
126
{
 
127
  return ((ptr)[0] << 8) | ptr[1];
 
128
}
 
129
 
 
130
 
 
131
 
 
132
/* /\** */
 
133
/*  * @param msg valid STUN message */
 
134
/*  * @return true if there is at least one unknown mandatory attribute. */
 
135
/*  *\/ */
 
136
/* bool stun_has_unknown (const void *msg) */
 
137
/* { */
 
138
/*   uint16_t dummy; */
 
139
/*   return stun_find_unknown (msg, &dummy, 1); */
 
140
/* } */
 
141
 
 
142
static int debug_enabled = 1;
 
143
 
 
144
void stun_debug_enable (void) {
 
145
  debug_enabled = 1;
 
146
}
 
147
void stun_debug_disable (void) {
 
148
  debug_enabled = 0;
 
149
}
 
150
 
 
151
void stun_debug (const char *fmt, ...)
 
152
{
 
153
  va_list ap;
 
154
  if (debug_enabled) {
 
155
    va_start (ap, fmt);
 
156
    vfprintf (stderr, fmt, ap);
 
157
    va_end (ap);
 
158
  }
 
159
}
 
160
 
 
161
void stun_debug_bytes (const void *data, size_t len)
 
162
{
 
163
  size_t i;
 
164
 
 
165
  stun_debug ("0x");
 
166
  for (i = 0; i < len; i++)
 
167
    stun_debug ("%02x", ((const unsigned char *)data)[i]);
 
168
}
 
169
 
 
170
int stun_xor_address (const StunMessage *msg,
 
171
    struct sockaddr *addr, socklen_t addrlen,
 
172
    uint32_t magic_cookie)
 
173
{
 
174
  switch (addr->sa_family)
 
175
  {
 
176
    case AF_INET:
 
177
    {
 
178
      struct sockaddr_in *ip4 = (struct sockaddr_in *)addr;
 
179
      if ((size_t) addrlen < sizeof (*ip4))
 
180
        return EINVAL;
 
181
 
 
182
      ip4->sin_port ^= htons (magic_cookie >> 16);
 
183
      ip4->sin_addr.s_addr ^= htonl (magic_cookie);
 
184
      return 0;
 
185
    }
 
186
 
 
187
    case AF_INET6:
 
188
    {
 
189
      struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)addr;
 
190
      unsigned short i;
 
191
 
 
192
      if ((size_t) addrlen < sizeof (*ip6))
 
193
        return EINVAL;
 
194
 
 
195
      ip6->sin6_port ^= htons (magic_cookie >> 16);
 
196
      for (i = 0; i < 16; i++)
 
197
        ip6->sin6_addr.s6_addr[i] ^= msg->buffer[4 + i];
 
198
      return 0;
 
199
    }
 
200
  }
 
201
  return EAFNOSUPPORT;
 
202
}
 
203
 
 
204
/**
 
205
 * Compares the length and content of an attribute.
 
206
 *
 
207
 * @param msg valid STUN message buffer
 
208
 * @param type STUN attribute type (host byte order)
 
209
 * @param data pointer to value to compare with
 
210
 * @param len byte length of the value
 
211
 * @return 0 in case of match, ENOENT if attribute was not found,
 
212
 * EINVAL if it did not match (different length, or same length but
 
213
 * different content)
 
214
 */
 
215
int stun_memcmp (const StunMessage *msg, stun_attr_type_t type,
 
216
                 const void *data, size_t len)
 
217
{
 
218
  uint16_t alen;
 
219
  const void *ptr = stun_message_find (msg, type, &alen);
 
220
  if (ptr == NULL)
 
221
    return ENOENT;
 
222
 
 
223
  if ((len != alen) || memcmp (ptr, data, len))
 
224
    return EINVAL;
 
225
  return 0;
 
226
}
 
227
 
 
228
 
 
229
/**
 
230
 * Compares the content of an attribute with a string.
 
231
 * @param msg valid STUN message buffer
 
232
 * @param type STUN attribute type (host byte order)
 
233
 * @param str string to compare with
 
234
 * @return 0 in case of match, ENOENT if attribute was not found,
 
235
 * EINVAL if it did not match
 
236
 */
 
237
int stun_strcmp (const StunMessage *msg, stun_attr_type_t type, const char *str)
 
238
{
 
239
  return stun_memcmp (msg, type, str, strlen (str));
 
240
}
 
241
 
 
242
 
 
243
void *stun_setw (uint8_t *ptr, uint16_t value)
 
244
{
 
245
  *ptr++ = value >> 8;
 
246
  *ptr++ = value & 0xff;
 
247
  return ptr;
 
248
}
 
249
 
 
250
 
 
251
void stun_set_type (uint8_t *h, stun_class_t c, stun_method_t m)
 
252
{
 
253
/*   assert (c < 4); */
 
254
/*   assert (m < (1 << 12)); */
 
255
 
 
256
  h[0] = (c >> 1) | ((m >> 6) & 0x3e);
 
257
  h[1] = ((c << 4) & 0x10) | ((m << 1) & 0xe0) | (m & 0x0f);
 
258
 
 
259
/*   assert (stun_getw (h) < (1 << 14)); */
 
260
/*   assert (stun_get_class (h) == c); */
 
261
/*   assert (stun_get_method (h) == m); */
 
262
}
 
263
 
 
264
 
 
265
/**
 
266
 * @param code host-byte order error code
 
267
 * @return a static pointer to a nul-terminated error message string.
 
268
 */
 
269
const char *stun_strerror (stun_error_t code)
 
270
{
 
271
  static const struct
 
272
  {
 
273
    stun_error_t code;
 
274
    char     phrase[32];
 
275
  } tab[] =
 
276
  {
 
277
    { STUN_ERROR_TRY_ALTERNATE, "Try alternate server" },
 
278
    { STUN_ERROR_BAD_REQUEST, "Bad request" },
 
279
    { STUN_ERROR_UNAUTHORIZED, "Authorization required" },
 
280
    { STUN_ERROR_UNKNOWN_ATTRIBUTE, "Unknown attribute" },
 
281
    /*
 
282
    { STUN_STALE_CREDENTIALS, "Authentication expired" },
 
283
    { STUN_INTEGRITY_CHECK_FAILURE, "Incorrect username/password" },
 
284
    { STUN_MISSING_USERNAME, "Username required" },
 
285
    { STUN_USE_TLS, "Secure connection required" },
 
286
    { STUN_MISSING_REALM, "Authentication domain required" },
 
287
    { STUN_MISSING_NONCE, "Authentication token missing" },
 
288
    { STUN_UNKNOWN_USERNAME, "Unknown user name" },
 
289
    */
 
290
    { STUN_ERROR_NO_BINDING, "Session expired" },
 
291
    { STUN_ERROR_STALE_NONCE, "Authentication token expired" },
 
292
    { STUN_ERROR_ACT_DST_ALREADY, "Changing remote peer forbidden" },
 
293
    { STUN_ERROR_UNSUPP_TRANSPORT, "Unknown transport protocol" },
 
294
    { STUN_ERROR_INVALID_IP, "Address unavailable" },
 
295
    { STUN_ERROR_INVALID_PORT, "Port unavailable" },
 
296
    { STUN_ERROR_OP_TCP_ONLY, "Invalid operation" },
 
297
    { STUN_ERROR_CONN_ALREADY, "Connection already established" },
 
298
    { STUN_ERROR_ALLOC_OVER_QUOTA, "Quota reached" },
 
299
    { STUN_ERROR_ROLE_CONFLICT, "Role conflict" },
 
300
    { STUN_ERROR_SERVER_ERROR, "Temporary server error" },
 
301
    { STUN_ERROR_SERVER_CAPACITY, "Temporary server congestion" },
 
302
  };
 
303
  const char *str = "Unknown error";
 
304
  size_t i;
 
305
 
 
306
  for (i = 0; i < (sizeof (tab) / sizeof (tab[0])); i++)
 
307
  {
 
308
    if (tab[i].code == code)
 
309
    {
 
310
      str = tab[i].phrase;
 
311
      break;
 
312
    }
 
313
  }
 
314
 
 
315
  /* Maximum allowed error message length */
 
316
  //  assert (strlen (str) < 128);
 
317
  return str;
 
318
}