blob: ffdf09f1251241a76901cec5a225c43e8873c4ce [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjnath/stun_msg.h>
21#include <pjnath/errno.h>
22#include <pjlib-util/crc32.h>
23#include <pjlib-util/hmac_sha1.h>
24#include <pj/assert.h>
25#include <pj/log.h>
26#include <pj/os.h>
27#include <pj/pool.h>
28#include <pj/rand.h>
29#include <pj/string.h>
30
31#define THIS_FILE "stun_msg.c"
32#define STUN_XOR_FINGERPRINT 0x5354554eL
33
34static int padding_char;
35
36static const char *stun_method_names[PJ_STUN_METHOD_MAX] =
37{
38 "Unknown", /* 0 */
39 "Binding", /* 1 */
40 "SharedSecret", /* 2 */
41 "Allocate", /* 3 */
42 "Refresh", /* 4 */
43 "???", /* 5 */
44 "Send", /* 6 */
45 "Data", /* 7 */
46 "CreatePermission", /* 8 */
47 "ChannelBind", /* 9 */
48};
49
50static struct
51{
52 int err_code;
53 const char *err_msg;
54} stun_err_msg_map[] =
55{
56 { PJ_STUN_SC_TRY_ALTERNATE, "Try Alternate"},
57 { PJ_STUN_SC_BAD_REQUEST, "Bad Request"},
58 { PJ_STUN_SC_UNAUTHORIZED, "Unauthorized"},
59 { PJ_STUN_SC_FORBIDDEN, "Forbidden"},
60 { PJ_STUN_SC_UNKNOWN_ATTRIBUTE, "Unknown Attribute"},
61 //{ PJ_STUN_SC_STALE_CREDENTIALS, "Stale Credentials"},
62 //{ PJ_STUN_SC_INTEGRITY_CHECK_FAILURE, "Integrity Check Failure"},
63 //{ PJ_STUN_SC_MISSING_USERNAME, "Missing Username"},
64 //{ PJ_STUN_SC_USE_TLS, "Use TLS"},
65 //{ PJ_STUN_SC_MISSING_REALM, "Missing Realm"},
66 //{ PJ_STUN_SC_MISSING_NONCE, "Missing Nonce"},
67 //{ PJ_STUN_SC_UNKNOWN_USERNAME, "Unknown Username"},
68 { PJ_STUN_SC_ALLOCATION_MISMATCH, "Allocation Mismatch"},
69 { PJ_STUN_SC_STALE_NONCE, "Stale Nonce"},
70 { PJ_STUN_SC_TRANSITIONING, "Active Destination Already Set"},
71 { PJ_STUN_SC_WRONG_CREDENTIALS, "Wrong Credentials"},
72 { PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO, "Unsupported Transport Protocol"},
73 { PJ_STUN_SC_OPER_TCP_ONLY, "Operation for TCP Only"},
74 { PJ_STUN_SC_CONNECTION_FAILURE, "Connection Failure"},
75 { PJ_STUN_SC_CONNECTION_TIMEOUT, "Connection Timeout"},
76 { PJ_STUN_SC_ALLOCATION_QUOTA_REACHED, "Allocation Quota Reached"},
77 { PJ_STUN_SC_ROLE_CONFLICT, "Role Conflict"},
78 { PJ_STUN_SC_SERVER_ERROR, "Server Error"},
79 { PJ_STUN_SC_INSUFFICIENT_CAPACITY, "Insufficient Capacity"},
80 { PJ_STUN_SC_GLOBAL_FAILURE, "Global Failure"}
81};
82
83
84
85struct attr_desc
86{
87 const char *name;
88 pj_status_t (*decode_attr)(pj_pool_t *pool, const pj_uint8_t *buf,
89 const pj_stun_msg_hdr *msghdr, void **p_attr);
90 pj_status_t (*encode_attr)(const void *a, pj_uint8_t *buf,
91 unsigned len, const pj_stun_msg_hdr *msghdr,
92 unsigned *printed);
93 void* (*clone_attr)(pj_pool_t *pool, const void *src);
94};
95
96static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
97 const pj_uint8_t *buf,
98 const pj_stun_msg_hdr *msghdr,
99 void **p_attr);
100static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
101 const pj_uint8_t *buf,
102 const pj_stun_msg_hdr *msghdr,
103 void **p_attr);
104static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf,
105 unsigned len,
106 const pj_stun_msg_hdr *msghdr,
107 unsigned *printed);
108static void* clone_sockaddr_attr(pj_pool_t *pool, const void *src);
109static pj_status_t decode_string_attr(pj_pool_t *pool,
110 const pj_uint8_t *buf,
111 const pj_stun_msg_hdr *msghdr,
112 void **p_attr);
113static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
114 unsigned len,
115 const pj_stun_msg_hdr *msghdr,
116 unsigned *printed);
117static void* clone_string_attr(pj_pool_t *pool, const void *src);
118static pj_status_t decode_msgint_attr(pj_pool_t *pool,
119 const pj_uint8_t *buf,
120 const pj_stun_msg_hdr *msghdr,
121 void **p_attr);
122static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf,
123 unsigned len,
124 const pj_stun_msg_hdr *msghdr,
125 unsigned *printed);
126static void* clone_msgint_attr(pj_pool_t *pool, const void *src);
127static pj_status_t decode_errcode_attr(pj_pool_t *pool,
128 const pj_uint8_t *buf,
129 const pj_stun_msg_hdr *msghdr,
130 void **p_attr);
131static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf,
132 unsigned len,
133 const pj_stun_msg_hdr *msghdr,
134 unsigned *printed);
135static void* clone_errcode_attr(pj_pool_t *pool, const void *src);
136static pj_status_t decode_unknown_attr(pj_pool_t *pool,
137 const pj_uint8_t *buf,
138 const pj_stun_msg_hdr *msghdr,
139 void **p_attr);
140static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
141 unsigned len,
142 const pj_stun_msg_hdr *msghdr,
143 unsigned *printed);
144static void* clone_unknown_attr(pj_pool_t *pool, const void *src);
145static pj_status_t decode_uint_attr(pj_pool_t *pool,
146 const pj_uint8_t *buf,
147 const pj_stun_msg_hdr *msghdr,
148 void **p_attr);
149static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf,
150 unsigned len,
151 const pj_stun_msg_hdr *msghdr,
152 unsigned *printed);
153static void* clone_uint_attr(pj_pool_t *pool, const void *src);
154static pj_status_t decode_uint64_attr(pj_pool_t *pool,
155 const pj_uint8_t *buf,
156 const pj_stun_msg_hdr *msghdr,
157 void **p_attr);
158static pj_status_t encode_uint64_attr(const void *a, pj_uint8_t *buf,
159 unsigned len,
160 const pj_stun_msg_hdr *msghdr,
161 unsigned *printed);
162static void* clone_uint64_attr(pj_pool_t *pool, const void *src);
163static pj_status_t decode_binary_attr(pj_pool_t *pool,
164 const pj_uint8_t *buf,
165 const pj_stun_msg_hdr *msghdr,
166 void **p_attr);
167static pj_status_t encode_binary_attr(const void *a, pj_uint8_t *buf,
168 unsigned len,
169 const pj_stun_msg_hdr *msghdr,
170 unsigned *printed);
171static void* clone_binary_attr(pj_pool_t *pool, const void *src);
172static pj_status_t decode_empty_attr(pj_pool_t *pool,
173 const pj_uint8_t *buf,
174 const pj_stun_msg_hdr *msghdr,
175 void **p_attr);
176static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
177 unsigned len,
178 const pj_stun_msg_hdr *msghdr,
179 unsigned *printed);
180static void* clone_empty_attr(pj_pool_t *pool, const void *src);
181
182static struct attr_desc mandatory_attr_desc[] =
183{
184 {
185 /* type zero */
186 NULL,
187 NULL,
188 NULL,
189 NULL
190 },
191 {
192 /* PJ_STUN_ATTR_MAPPED_ADDR, */
193 "MAPPED-ADDRESS",
194 &decode_sockaddr_attr,
195 &encode_sockaddr_attr,
196 &clone_sockaddr_attr
197 },
198 {
199 /* PJ_STUN_ATTR_RESPONSE_ADDR, */
200 "RESPONSE-ADDRESS",
201 &decode_sockaddr_attr,
202 &encode_sockaddr_attr,
203 &clone_sockaddr_attr
204 },
205 {
206 /* PJ_STUN_ATTR_CHANGE_REQUEST, */
207 "CHANGE-REQUEST",
208 &decode_uint_attr,
209 &encode_uint_attr,
210 &clone_uint_attr
211 },
212 {
213 /* PJ_STUN_ATTR_SOURCE_ADDR, */
214 "SOURCE-ADDRESS",
215 &decode_sockaddr_attr,
216 &encode_sockaddr_attr,
217 &clone_sockaddr_attr
218 },
219 {
220 /* PJ_STUN_ATTR_CHANGED_ADDR, */
221 "CHANGED-ADDRESS",
222 &decode_sockaddr_attr,
223 &encode_sockaddr_attr,
224 &clone_sockaddr_attr
225 },
226 {
227 /* PJ_STUN_ATTR_USERNAME, */
228 "USERNAME",
229 &decode_string_attr,
230 &encode_string_attr,
231 &clone_string_attr
232 },
233 {
234 /* PJ_STUN_ATTR_PASSWORD, */
235 "PASSWORD",
236 &decode_string_attr,
237 &encode_string_attr,
238 &clone_string_attr
239 },
240 {
241 /* PJ_STUN_ATTR_MESSAGE_INTEGRITY, */
242 "MESSAGE-INTEGRITY",
243 &decode_msgint_attr,
244 &encode_msgint_attr,
245 &clone_msgint_attr
246 },
247 {
248 /* PJ_STUN_ATTR_ERROR_CODE, */
249 "ERROR-CODE",
250 &decode_errcode_attr,
251 &encode_errcode_attr,
252 &clone_errcode_attr
253 },
254 {
255 /* PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, */
256 "UNKNOWN-ATTRIBUTES",
257 &decode_unknown_attr,
258 &encode_unknown_attr,
259 &clone_unknown_attr
260 },
261 {
262 /* PJ_STUN_ATTR_REFLECTED_FROM, */
263 "REFLECTED-FROM",
264 &decode_sockaddr_attr,
265 &encode_sockaddr_attr,
266 &clone_sockaddr_attr
267 },
268 {
269 /* PJ_STUN_ATTR_CHANNEL_NUMBER (0x000C) */
270 "CHANNEL-NUMBER",
271 &decode_uint_attr,
272 &encode_uint_attr,
273 &clone_uint_attr
274 },
275 {
276 /* PJ_STUN_ATTR_LIFETIME, */
277 "LIFETIME",
278 &decode_uint_attr,
279 &encode_uint_attr,
280 &clone_uint_attr
281 },
282 {
283 /* ID 0x000E is not assigned */
284 NULL,
285 NULL,
286 NULL,
287 NULL
288 },
289 {
290 /* PJ_STUN_ATTR_MAGIC_COOKIE */
291 "MAGIC-COOKIE",
292 &decode_uint_attr,
293 &encode_uint_attr,
294 &clone_uint_attr
295 },
296 {
297 /* PJ_STUN_ATTR_BANDWIDTH, */
298 "BANDWIDTH",
299 &decode_uint_attr,
300 &encode_uint_attr,
301 &clone_uint_attr
302 },
303 {
304 /* ID 0x0011 is not assigned */
305 NULL,
306 NULL,
307 NULL,
308 NULL
309 },
310 {
311 /* PJ_STUN_ATTR_XOR_PEER_ADDRESS, */
312 "XOR-PEER-ADDRESS",
313 &decode_xored_sockaddr_attr,
314 &encode_sockaddr_attr,
315 &clone_sockaddr_attr
316 },
317 {
318 /* PJ_STUN_ATTR_DATA, */
319 "DATA",
320 &decode_binary_attr,
321 &encode_binary_attr,
322 &clone_binary_attr
323 },
324 {
325 /* PJ_STUN_ATTR_REALM, */
326 "REALM",
327 &decode_string_attr,
328 &encode_string_attr,
329 &clone_string_attr
330 },
331 {
332 /* PJ_STUN_ATTR_NONCE, */
333 "NONCE",
334 &decode_string_attr,
335 &encode_string_attr,
336 &clone_string_attr
337 },
338 {
339 /* PJ_STUN_ATTR_XOR_RELAYED_ADDR, */
340 "XOR-RELAYED-ADDRESS",
341 &decode_xored_sockaddr_attr,
342 &encode_sockaddr_attr,
343 &clone_sockaddr_attr
344 },
345 {
346 /* PJ_STUN_ATTR_REQUESTED_ADDR_TYPE, */
347 "REQUESTED-ADDRESS-TYPE",
348 &decode_uint_attr,
349 &encode_uint_attr,
350 &clone_uint_attr
351 },
352 {
353 /* PJ_STUN_ATTR_EVEN_PORT, */
354 "EVEN-PORT",
355 &decode_uint_attr,
356 &encode_uint_attr,
357 &clone_uint_attr
358 },
359 {
360 /* PJ_STUN_ATTR_REQUESTED_TRANSPORT, */
361 "REQUESTED-TRANSPORT",
362 &decode_uint_attr,
363 &encode_uint_attr,
364 &clone_uint_attr
365 },
366 {
367 /* PJ_STUN_ATTR_DONT_FRAGMENT */
368 "DONT-FRAGMENT",
369 &decode_empty_attr,
370 &encode_empty_attr,
371 &clone_empty_attr
372 },
373 {
374 /* ID 0x001B is not assigned */
375 NULL,
376 NULL,
377 NULL,
378 NULL
379 },
380 {
381 /* ID 0x001C is not assigned */
382 NULL,
383 NULL,
384 NULL,
385 NULL
386 },
387 {
388 /* ID 0x001D is not assigned */
389 NULL,
390 NULL,
391 NULL,
392 NULL
393 },
394 {
395 /* ID 0x001E is not assigned */
396 NULL,
397 NULL,
398 NULL,
399 NULL
400 },
401 {
402 /* ID 0x001F is not assigned */
403 NULL,
404 NULL,
405 NULL,
406 NULL
407 },
408 {
409 /* PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, */
410 "XOR-MAPPED-ADDRESS",
411 &decode_xored_sockaddr_attr,
412 &encode_sockaddr_attr,
413 &clone_sockaddr_attr
414 },
415 {
416 /* PJ_STUN_ATTR_TIMER_VAL, */
417 "TIMER-VAL",
418 &decode_uint_attr,
419 &encode_uint_attr,
420 &clone_uint_attr
421 },
422 {
423 /* PJ_STUN_ATTR_RESERVATION_TOKEN, */
424 "RESERVATION-TOKEN",
425 &decode_uint64_attr,
426 &encode_uint64_attr,
427 &clone_uint64_attr
428 },
429 {
430 /* PJ_STUN_ATTR_XOR_REFLECTED_FROM, */
431 "XOR-REFLECTED-FROM",
432 &decode_xored_sockaddr_attr,
433 &encode_sockaddr_attr,
434 &clone_sockaddr_attr
435 },
436 {
437 /* PJ_STUN_ATTR_PRIORITY, */
438 "PRIORITY",
439 &decode_uint_attr,
440 &encode_uint_attr,
441 &clone_uint_attr
442 },
443 {
444 /* PJ_STUN_ATTR_USE_CANDIDATE, */
445 "USE-CANDIDATE",
446 &decode_empty_attr,
447 &encode_empty_attr,
448 &clone_empty_attr
449 },
450 {
451 /* ID 0x0026 is not assigned */
452 NULL,
453 NULL,
454 NULL,
455 NULL
456 },
457 {
458 /* ID 0x0027 is not assigned */
459 NULL,
460 NULL,
461 NULL,
462 NULL
463 },
464 {
465 /* ID 0x0028 is not assigned */
466 NULL,
467 NULL,
468 NULL,
469 NULL
470 },
471 {
472 /* ID 0x0029 is not assigned */
473 NULL,
474 NULL,
475 NULL,
476 NULL
477 },
478 {
479 /* ID 0x002a is not assigned */
480 NULL,
481 NULL,
482 NULL,
483 NULL
484 },
485 {
486 /* ID 0x002b is not assigned */
487 NULL,
488 NULL,
489 NULL,
490 NULL
491 },
492 {
493 /* ID 0x002c is not assigned */
494 NULL,
495 NULL,
496 NULL,
497 NULL
498 },
499 {
500 /* ID 0x002d is not assigned */
501 NULL,
502 NULL,
503 NULL,
504 NULL
505 },
506 {
507 /* ID 0x002e is not assigned */
508 NULL,
509 NULL,
510 NULL,
511 NULL
512 },
513 {
514 /* ID 0x002f is not assigned */
515 NULL,
516 NULL,
517 NULL,
518 NULL
519 },
520 {
521 /* PJ_STUN_ATTR_ICMP, */
522 "ICMP",
523 &decode_uint_attr,
524 &encode_uint_attr,
525 &clone_uint_attr
526 },
527
528 /* Sentinel */
529 {
530 /* PJ_STUN_ATTR_END_MANDATORY_ATTR */
531 NULL,
532 NULL,
533 NULL,
534 NULL
535 }
536};
537
538static struct attr_desc extended_attr_desc[] =
539{
540 {
541 /* ID 0x8021 is not assigned */
542 NULL,
543 NULL,
544 NULL,
545 NULL
546 },
547 {
548 /* PJ_STUN_ATTR_SOFTWARE, */
549 "SOFTWARE",
550 &decode_string_attr,
551 &encode_string_attr,
552 &clone_string_attr
553 },
554 {
555 /* PJ_STUN_ATTR_ALTERNATE_SERVER, */
556 "ALTERNATE-SERVER",
557 &decode_sockaddr_attr,
558 &encode_sockaddr_attr,
559 &clone_sockaddr_attr
560 },
561 {
562 /* PJ_STUN_ATTR_REFRESH_INTERVAL, */
563 "REFRESH-INTERVAL",
564 &decode_uint_attr,
565 &encode_uint_attr,
566 &clone_uint_attr
567 },
568 {
569 /* ID 0x8025 is not assigned*/
570 NULL,
571 NULL,
572 NULL,
573 NULL
574 },
575 {
576 /* PADDING, 0x8026 */
577 NULL,
578 NULL,
579 NULL,
580 NULL
581 },
582 {
583 /* CACHE-TIMEOUT, 0x8027 */
584 NULL,
585 NULL,
586 NULL,
587 NULL
588 },
589 {
590 /* PJ_STUN_ATTR_FINGERPRINT, */
591 "FINGERPRINT",
592 &decode_uint_attr,
593 &encode_uint_attr,
594 &clone_uint_attr
595 },
596 {
597 /* PJ_STUN_ATTR_ICE_CONTROLLED, */
598 "ICE-CONTROLLED",
599 &decode_uint64_attr,
600 &encode_uint64_attr,
601 &clone_uint64_attr
602 },
603 {
604 /* PJ_STUN_ATTR_ICE_CONTROLLING, */
605 "ICE-CONTROLLING",
606 &decode_uint64_attr,
607 &encode_uint64_attr,
608 &clone_uint64_attr
609 }
610};
611
612
613
614/*
615 * Get STUN message type name.
616 */
617PJ_DEF(const char*) pj_stun_get_method_name(unsigned msg_type)
618{
619 unsigned method = PJ_STUN_GET_METHOD(msg_type);
620
621 if (method >= PJ_ARRAY_SIZE(stun_method_names))
622 return "???";
623
624 return stun_method_names[method];
625}
626
627
628/*
629 * Get STUN message class name.
630 */
631PJ_DEF(const char*) pj_stun_get_class_name(unsigned msg_type)
632{
633 if (PJ_STUN_IS_REQUEST(msg_type))
634 return "request";
635 else if (PJ_STUN_IS_SUCCESS_RESPONSE(msg_type))
636 return "success response";
637 else if (PJ_STUN_IS_ERROR_RESPONSE(msg_type))
638 return "error response";
639 else if (PJ_STUN_IS_INDICATION(msg_type))
640 return "indication";
641 else
642 return "???";
643}
644
645
646static const struct attr_desc *find_attr_desc(unsigned attr_type)
647{
648 struct attr_desc *desc;
649
650 /* Check that attr_desc array is valid */
651 pj_assert(PJ_ARRAY_SIZE(mandatory_attr_desc)==
652 PJ_STUN_ATTR_END_MANDATORY_ATTR+1);
653 pj_assert(mandatory_attr_desc[PJ_STUN_ATTR_END_MANDATORY_ATTR].decode_attr
654 == NULL);
655 pj_assert(mandatory_attr_desc[PJ_STUN_ATTR_USE_CANDIDATE].decode_attr
656 == &decode_empty_attr);
657 pj_assert(PJ_ARRAY_SIZE(extended_attr_desc) ==
658 PJ_STUN_ATTR_END_EXTENDED_ATTR-PJ_STUN_ATTR_START_EXTENDED_ATTR);
659
660 if (attr_type < PJ_STUN_ATTR_END_MANDATORY_ATTR)
661 desc = &mandatory_attr_desc[attr_type];
662 else if (attr_type >= PJ_STUN_ATTR_START_EXTENDED_ATTR &&
663 attr_type < PJ_STUN_ATTR_END_EXTENDED_ATTR)
664 desc = &extended_attr_desc[attr_type-PJ_STUN_ATTR_START_EXTENDED_ATTR];
665 else
666 return NULL;
667
668 return desc->decode_attr == NULL ? NULL : desc;
669}
670
671
672/*
673 * Get STUN attribute name.
674 */
675PJ_DEF(const char*) pj_stun_get_attr_name(unsigned attr_type)
676{
677 const struct attr_desc *attr_desc;
678
679 attr_desc = find_attr_desc(attr_type);
680 if (!attr_desc || attr_desc->name==NULL)
681 return "???";
682
683 return attr_desc->name;
684}
685
686
687/**
688 * Get STUN standard reason phrase for the specified error code.
689 */
690PJ_DEF(pj_str_t) pj_stun_get_err_reason(int err_code)
691{
692#if 0
693 /* Find error using linear search */
694 unsigned i;
695
696 for (i=0; i<PJ_ARRAY_SIZE(stun_err_msg_map); ++i) {
697 if (stun_err_msg_map[i].err_code == err_code)
698 return pj_str((char*)stun_err_msg_map[i].err_msg);
699 }
700 return pj_str(NULL);
701#else
702 /* Find error message using binary search */
703 int first = 0;
704 int n = PJ_ARRAY_SIZE(stun_err_msg_map);
705
706 while (n > 0) {
707 int half = n/2;
708 int mid = first + half;
709
710 if (stun_err_msg_map[mid].err_code < err_code) {
711 first = mid+1;
712 n -= (half+1);
713 } else if (stun_err_msg_map[mid].err_code > err_code) {
714 n = half;
715 } else {
716 first = mid;
717 break;
718 }
719 }
720
721
722 if (stun_err_msg_map[first].err_code == err_code) {
723 return pj_str((char*)stun_err_msg_map[first].err_msg);
724 } else {
725 return pj_str(NULL);
726 }
727#endif
728}
729
730
731/*
732 * Set padding character.
733 */
734PJ_DEF(int) pj_stun_set_padding_char(int chr)
735{
736 int old_pad = padding_char;
737 padding_char = chr;
738 return old_pad;
739}
740
741
742//////////////////////////////////////////////////////////////////////////////
743
744
745#define INIT_ATTR(a,t,l) (a)->hdr.type=(pj_uint16_t)(t), \
746 (a)->hdr.length=(pj_uint16_t)(l)
747#define ATTR_HDR_LEN 4
748
749static pj_uint16_t GETVAL16H(const pj_uint8_t *buf, unsigned pos)
750{
751 return (pj_uint16_t) ((buf[pos + 0] << 8) | \
752 (buf[pos + 1] << 0));
753}
754
755PJ_INLINE(pj_uint16_t) GETVAL16N(const pj_uint8_t *buf, unsigned pos)
756{
757 return pj_htons(GETVAL16H(buf,pos));
758}
759
760static void PUTVAL16H(pj_uint8_t *buf, unsigned pos, pj_uint16_t hval)
761{
762 buf[pos+0] = (pj_uint8_t) ((hval & 0xFF00) >> 8);
763 buf[pos+1] = (pj_uint8_t) ((hval & 0x00FF) >> 0);
764}
765
766PJ_INLINE(pj_uint32_t) GETVAL32H(const pj_uint8_t *buf, unsigned pos)
767{
768 return (pj_uint32_t) ((buf[pos + 0] << 24UL) | \
769 (buf[pos + 1] << 16UL) | \
770 (buf[pos + 2] << 8UL) | \
771 (buf[pos + 3] << 0UL));
772}
773
774PJ_INLINE(pj_uint32_t) GETVAL32N(const pj_uint8_t *buf, unsigned pos)
775{
776 return pj_htonl(GETVAL32H(buf,pos));
777}
778
779static void PUTVAL32H(pj_uint8_t *buf, unsigned pos, pj_uint32_t hval)
780{
781 buf[pos+0] = (pj_uint8_t) ((hval & 0xFF000000UL) >> 24);
782 buf[pos+1] = (pj_uint8_t) ((hval & 0x00FF0000UL) >> 16);
783 buf[pos+2] = (pj_uint8_t) ((hval & 0x0000FF00UL) >> 8);
784 buf[pos+3] = (pj_uint8_t) ((hval & 0x000000FFUL) >> 0);
785}
786
787static void GETVAL64H(const pj_uint8_t *buf, unsigned pos, pj_timestamp *ts)
788{
789 ts->u32.hi = GETVAL32H(buf, pos);
790 ts->u32.lo = GETVAL32H(buf, pos+4);
791}
792
793static void PUTVAL64H(pj_uint8_t *buf, unsigned pos, const pj_timestamp *ts)
794{
795 PUTVAL32H(buf, pos, ts->u32.hi);
796 PUTVAL32H(buf, pos+4, ts->u32.lo);
797}
798
799
800static void GETATTRHDR(const pj_uint8_t *buf, pj_stun_attr_hdr *hdr)
801{
802 hdr->type = GETVAL16H(buf, 0);
803 hdr->length = GETVAL16H(buf, 2);
804}
805
806//////////////////////////////////////////////////////////////////////////////
807/*
808 * STUN generic IP address container
809 */
810#define STUN_GENERIC_IPV4_ADDR_LEN 8
811#define STUN_GENERIC_IPV6_ADDR_LEN 20
812
813/*
814 * Init sockaddr attr
815 */
816PJ_DEF(pj_status_t) pj_stun_sockaddr_attr_init( pj_stun_sockaddr_attr *attr,
817 int attr_type,
818 pj_bool_t xor_ed,
819 const pj_sockaddr_t *addr,
820 unsigned addr_len)
821{
822 unsigned attr_len;
823
824 PJ_ASSERT_RETURN(attr && addr_len && addr, PJ_EINVAL);
825 PJ_ASSERT_RETURN(addr_len == sizeof(pj_sockaddr_in) ||
826 addr_len == sizeof(pj_sockaddr_in6), PJ_EINVAL);
827
828 attr_len = pj_sockaddr_get_addr_len(addr) + 4;
829 INIT_ATTR(attr, attr_type, attr_len);
830
831 pj_memcpy(&attr->sockaddr, addr, addr_len);
832 attr->xor_ed = xor_ed;
833
834 return PJ_SUCCESS;
835}
836
837
838/*
839 * Create a generic STUN IP address attribute for IPv4 address.
840 */
841PJ_DEF(pj_status_t) pj_stun_sockaddr_attr_create(pj_pool_t *pool,
842 int attr_type,
843 pj_bool_t xor_ed,
844 const pj_sockaddr_t *addr,
845 unsigned addr_len,
846 pj_stun_sockaddr_attr **p_attr)
847{
848 pj_stun_sockaddr_attr *attr;
849
850 PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
851 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
852 *p_attr = attr;
853 return pj_stun_sockaddr_attr_init(attr, attr_type, xor_ed,
854 addr, addr_len);
855}
856
857
858/*
859 * Create and add generic STUN IP address attribute to a STUN message.
860 */
861PJ_DEF(pj_status_t) pj_stun_msg_add_sockaddr_attr(pj_pool_t *pool,
862 pj_stun_msg *msg,
863 int attr_type,
864 pj_bool_t xor_ed,
865 const pj_sockaddr_t *addr,
866 unsigned addr_len)
867{
868 pj_stun_sockaddr_attr *attr;
869 pj_status_t status;
870
871 status = pj_stun_sockaddr_attr_create(pool, attr_type, xor_ed,
872 addr, addr_len, &attr);
873 if (status != PJ_SUCCESS)
874 return status;
875
876 return pj_stun_msg_add_attr(msg, &attr->hdr);
877}
878
879static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
880 const pj_uint8_t *buf,
881 const pj_stun_msg_hdr *msghdr,
882 void **p_attr)
883{
884 pj_stun_sockaddr_attr *attr;
885 int af;
886 unsigned addr_len;
887 pj_uint32_t val;
888
889 PJ_CHECK_STACK();
890
891 PJ_UNUSED_ARG(msghdr);
892
893 /* Create the attribute */
894 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
895 GETATTRHDR(buf, &attr->hdr);
896
897 /* Check that the attribute length is valid */
898 if (attr->hdr.length != STUN_GENERIC_IPV4_ADDR_LEN &&
899 attr->hdr.length != STUN_GENERIC_IPV6_ADDR_LEN)
900 {
901 return PJNATH_ESTUNINATTRLEN;
902 }
903
904 /* Check address family */
905 val = *(pj_uint8_t*)(buf + ATTR_HDR_LEN + 1);
906
907 /* Check address family is valid */
908 if (val == 1) {
909 if (attr->hdr.length != STUN_GENERIC_IPV4_ADDR_LEN)
910 return PJNATH_ESTUNINATTRLEN;
911 af = pj_AF_INET();
912 addr_len = 4;
913 } else if (val == 2) {
914 if (attr->hdr.length != STUN_GENERIC_IPV6_ADDR_LEN)
915 return PJNATH_ESTUNINATTRLEN;
916 af = pj_AF_INET6();
917 addr_len = 16;
918 } else {
919 /* Invalid address family */
920 return PJNATH_EINVAF;
921 }
922
923 /* Get port and address */
924 pj_sockaddr_init(af, &attr->sockaddr, NULL, 0);
925 pj_sockaddr_set_port(&attr->sockaddr,
926 GETVAL16H(buf, ATTR_HDR_LEN+2));
927 pj_memcpy(pj_sockaddr_get_addr(&attr->sockaddr),
928 buf+ATTR_HDR_LEN+4,
929 addr_len);
930
931 /* Done */
932 *p_attr = (void*)attr;
933
934 return PJ_SUCCESS;
935}
936
937
938static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
939 const pj_uint8_t *buf,
940 const pj_stun_msg_hdr *msghdr,
941 void **p_attr)
942{
943 pj_stun_sockaddr_attr *attr;
944 pj_status_t status;
945
946 status = decode_sockaddr_attr(pool, buf, msghdr, p_attr);
947 if (status != PJ_SUCCESS)
948 return status;
949
950 attr = *(pj_stun_sockaddr_attr**)p_attr;
951
952 attr->xor_ed = PJ_TRUE;
953
954 if (attr->sockaddr.addr.sa_family == pj_AF_INET()) {
955 attr->sockaddr.ipv4.sin_port ^= pj_htons(PJ_STUN_MAGIC >> 16);
956 attr->sockaddr.ipv4.sin_addr.s_addr ^= pj_htonl(PJ_STUN_MAGIC);
957 } else if (attr->sockaddr.addr.sa_family == pj_AF_INET6()) {
958 unsigned i;
959 pj_uint8_t *dst = (pj_uint8_t*) &attr->sockaddr.ipv6.sin6_addr;
960 pj_uint32_t magic = pj_htonl(PJ_STUN_MAGIC);
961
962 attr->sockaddr.ipv6.sin6_port ^= pj_htons(PJ_STUN_MAGIC >> 16);
963
964 /* If the IP address family is IPv6, X-Address is computed by
965 * taking the mapped IP address in host byte order, XOR'ing it
966 * with the concatenation of the magic cookie and the 96-bit
967 * transaction ID, and converting the result to network byte
968 * order.
969 */
970 for (i=0; i<4; ++i) {
971 dst[i] ^= ((const pj_uint8_t*)&magic)[i];
972 }
973 pj_assert(sizeof(msghdr->tsx_id[0]) == 1);
974 for (i=0; i<12; ++i) {
975 dst[i+4] ^= msghdr->tsx_id[i];
976 }
977
978 } else {
979 return PJNATH_EINVAF;
980 }
981
982 /* Done */
983 *p_attr = attr;
984
985 return PJ_SUCCESS;
986}
987
988
989static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf,
990 unsigned len,
991 const pj_stun_msg_hdr *msghdr,
992 unsigned *printed)
993{
994 pj_uint8_t *start_buf = buf;
995 const pj_stun_sockaddr_attr *ca =
996 (const pj_stun_sockaddr_attr *)a;
997
998 PJ_CHECK_STACK();
999
1000 /* Common: attribute type */
1001 PUTVAL16H(buf, 0, ca->hdr.type);
1002
1003 if (ca->sockaddr.addr.sa_family == pj_AF_INET()) {
1004 enum {
1005 ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IPV4_ADDR_LEN
1006 };
1007
1008 if (len < ATTR_LEN)
1009 return PJ_ETOOSMALL;
1010
1011 /* attribute len */
1012 PUTVAL16H(buf, 2, STUN_GENERIC_IPV4_ADDR_LEN);
1013 buf += ATTR_HDR_LEN;
1014
1015 /* Ignored */
1016 *buf++ = '\0';
1017
1018 /* Address family, 1 for IPv4 */
1019 *buf++ = 1;
1020
1021 /* IPv4 address */
1022 if (ca->xor_ed) {
1023 pj_uint32_t addr;
1024 pj_uint16_t port;
1025
1026 addr = ca->sockaddr.ipv4.sin_addr.s_addr;
1027 port = ca->sockaddr.ipv4.sin_port;
1028
1029 port ^= pj_htons(PJ_STUN_MAGIC >> 16);
1030 addr ^= pj_htonl(PJ_STUN_MAGIC);
1031
1032 /* Port */
1033 pj_memcpy(buf, &port, 2);
1034 buf += 2;
1035
1036 /* Address */
1037 pj_memcpy(buf, &addr, 4);
1038 buf += 4;
1039
1040 } else {
1041 /* Port */
1042 pj_memcpy(buf, &ca->sockaddr.ipv4.sin_port, 2);
1043 buf += 2;
1044
1045 /* Address */
1046 pj_memcpy(buf, &ca->sockaddr.ipv4.sin_addr, 4);
1047 buf += 4;
1048 }
1049
1050 pj_assert(buf - start_buf == ATTR_LEN);
1051
1052 } else if (ca->sockaddr.addr.sa_family == pj_AF_INET6()) {
1053 /* IPv6 address */
1054 enum {
1055 ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IPV6_ADDR_LEN
1056 };
1057
1058 if (len < ATTR_LEN)
1059 return PJ_ETOOSMALL;
1060
1061 /* attribute len */
1062 PUTVAL16H(buf, 2, STUN_GENERIC_IPV6_ADDR_LEN);
1063 buf += ATTR_HDR_LEN;
1064
1065 /* Ignored */
1066 *buf++ = '\0';
1067
1068 /* Address family, 2 for IPv6 */
1069 *buf++ = 2;
1070
1071 /* IPv6 address */
1072 if (ca->xor_ed) {
1073 unsigned i;
1074 pj_uint8_t *dst;
1075 const pj_uint8_t *src;
1076 pj_uint32_t magic = pj_htonl(PJ_STUN_MAGIC);
1077 pj_uint16_t port = ca->sockaddr.ipv6.sin6_port;
1078
1079 /* Port */
1080 port ^= pj_htons(PJ_STUN_MAGIC >> 16);
1081 pj_memcpy(buf, &port, 2);
1082 buf += 2;
1083
1084 /* Address */
1085 dst = buf;
1086 src = (const pj_uint8_t*) &ca->sockaddr.ipv6.sin6_addr;
1087 for (i=0; i<4; ++i) {
1088 dst[i] = (pj_uint8_t)(src[i] ^ ((const pj_uint8_t*)&magic)[i]);
1089 }
1090 pj_assert(sizeof(msghdr->tsx_id[0]) == 1);
1091 for (i=0; i<12; ++i) {
1092 dst[i+4] = (pj_uint8_t)(src[i+4] ^ msghdr->tsx_id[i]);
1093 }
1094
1095 buf += 16;
1096
1097 } else {
1098 /* Port */
1099 pj_memcpy(buf, &ca->sockaddr.ipv6.sin6_port, 2);
1100 buf += 2;
1101
1102 /* Address */
1103 pj_memcpy(buf, &ca->sockaddr.ipv6.sin6_addr, 16);
1104 buf += 16;
1105 }
1106
1107 pj_assert(buf - start_buf == ATTR_LEN);
1108
1109 } else {
1110 return PJNATH_EINVAF;
1111 }
1112
1113 /* Done */
1114 *printed = (unsigned)(buf - start_buf);
1115
1116 return PJ_SUCCESS;
1117}
1118
1119
1120static void* clone_sockaddr_attr(pj_pool_t *pool, const void *src)
1121{
1122 pj_stun_sockaddr_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_sockaddr_attr);
1123 pj_memcpy(dst, src, sizeof(pj_stun_sockaddr_attr));
1124 return (void*)dst;
1125}
1126
1127//////////////////////////////////////////////////////////////////////////////
1128/*
1129 * STUN generic string attribute
1130 */
1131
1132/*
1133 * Initialize a STUN generic string attribute.
1134 */
1135PJ_DEF(pj_status_t) pj_stun_string_attr_init( pj_stun_string_attr *attr,
1136 pj_pool_t *pool,
1137 int attr_type,
1138 const pj_str_t *value)
1139{
1140 INIT_ATTR(attr, attr_type, value->slen);
1141 if (value && value->slen)
1142 pj_strdup(pool, &attr->value, value);
1143 else
1144 attr->value.slen = 0;
1145 return PJ_SUCCESS;
1146}
1147
1148
1149/*
1150 * Create a STUN generic string attribute.
1151 */
1152PJ_DEF(pj_status_t) pj_stun_string_attr_create(pj_pool_t *pool,
1153 int attr_type,
1154 const pj_str_t *value,
1155 pj_stun_string_attr **p_attr)
1156{
1157 pj_stun_string_attr *attr;
1158
1159 PJ_ASSERT_RETURN(pool && value && p_attr, PJ_EINVAL);
1160
1161 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_string_attr);
1162 *p_attr = attr;
1163
1164 return pj_stun_string_attr_init(attr, pool, attr_type, value);
1165}
1166
1167
1168/*
1169 * Create and add STUN generic string attribute to the message.
1170 */
1171PJ_DEF(pj_status_t) pj_stun_msg_add_string_attr(pj_pool_t *pool,
1172 pj_stun_msg *msg,
1173 int attr_type,
1174 const pj_str_t *value)
1175{
1176 pj_stun_string_attr *attr = NULL;
1177 pj_status_t status;
1178
1179 status = pj_stun_string_attr_create(pool, attr_type, value,
1180 &attr);
1181 if (status != PJ_SUCCESS)
1182 return status;
1183
1184 return pj_stun_msg_add_attr(msg, &attr->hdr);
1185}
1186
1187
1188static pj_status_t decode_string_attr(pj_pool_t *pool,
1189 const pj_uint8_t *buf,
1190 const pj_stun_msg_hdr *msghdr,
1191 void **p_attr)
1192{
1193 pj_stun_string_attr *attr;
1194 pj_str_t value;
1195
1196 PJ_UNUSED_ARG(msghdr);
1197
1198 /* Create the attribute */
1199 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_string_attr);
1200 GETATTRHDR(buf, &attr->hdr);
1201
1202 /* Get pointer to the string in the message */
1203 value.ptr = ((char*)buf + ATTR_HDR_LEN);
1204 value.slen = attr->hdr.length;
1205
1206 /* Copy the string to the attribute */
1207 pj_strdup(pool, &attr->value, &value);
1208
1209 /* Done */
1210 *p_attr = attr;
1211
1212 return PJ_SUCCESS;
1213
1214}
1215
1216
1217static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
1218 unsigned len,
1219 const pj_stun_msg_hdr *msghdr,
1220 unsigned *printed)
1221{
1222 const pj_stun_string_attr *ca =
1223 (const pj_stun_string_attr*)a;
1224
1225 PJ_CHECK_STACK();
1226
1227 PJ_UNUSED_ARG(msghdr);
1228
1229 /* Calculated total attr_len (add padding if necessary) */
1230 *printed = ((unsigned)ca->value.slen + ATTR_HDR_LEN + 3) & (~3);
1231 if (len < *printed) {
1232 *printed = 0;
1233 return PJ_ETOOSMALL;
1234 }
1235
1236 PUTVAL16H(buf, 0, ca->hdr.type);
1237
1238 /* Special treatment for SOFTWARE attribute:
1239 * This attribute had caused interop problem when talking to
1240 * legacy RFC 3489 STUN servers, due to different "length"
1241 * rules with RFC 5389.
1242 */
1243 if (msghdr->magic != PJ_STUN_MAGIC ||
1244 ca->hdr.type == PJ_STUN_ATTR_SOFTWARE)
1245 {
1246 /* Set the length to be 4-bytes aligned so that we can
1247 * communicate with RFC 3489 endpoints
1248 */
1249 PUTVAL16H(buf, 2, (pj_uint16_t)((ca->value.slen + 3) & (~3)));
1250 } else {
1251 /* Use RFC 5389 rule */
1252 PUTVAL16H(buf, 2, (pj_uint16_t)ca->value.slen);
1253 }
1254
1255 /* Copy the string */
1256 pj_memcpy(buf+ATTR_HDR_LEN, ca->value.ptr, ca->value.slen);
1257
1258 /* Add padding character, if string is not 4-bytes aligned. */
1259 if (ca->value.slen & 0x03) {
1260 pj_uint8_t pad[3];
1261 pj_memset(pad, padding_char, sizeof(pad));
1262 pj_memcpy(buf+ATTR_HDR_LEN+ca->value.slen, pad,
1263 4-(ca->value.slen & 0x03));
1264 }
1265
1266 /* Done */
1267 return PJ_SUCCESS;
1268}
1269
1270
1271static void* clone_string_attr(pj_pool_t *pool, const void *src)
1272{
1273 const pj_stun_string_attr *asrc = (const pj_stun_string_attr*)src;
1274 pj_stun_string_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_string_attr);
1275
1276 pj_memcpy(dst, src, sizeof(pj_stun_attr_hdr));
1277 pj_strdup(pool, &dst->value, &asrc->value);
1278
1279 return (void*)dst;
1280}
1281
1282//////////////////////////////////////////////////////////////////////////////
1283/*
1284 * STUN empty attribute (used by USE-CANDIDATE).
1285 */
1286
1287/*
1288 * Create a STUN empty attribute.
1289 */
1290PJ_DEF(pj_status_t) pj_stun_empty_attr_create(pj_pool_t *pool,
1291 int attr_type,
1292 pj_stun_empty_attr **p_attr)
1293{
1294 pj_stun_empty_attr *attr;
1295
1296 PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
1297
1298 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_empty_attr);
1299 INIT_ATTR(attr, attr_type, 0);
1300
1301 *p_attr = attr;
1302
1303 return PJ_SUCCESS;
1304}
1305
1306
1307/*
1308 * Create STUN empty attribute and add the attribute to the message.
1309 */
1310PJ_DEF(pj_status_t) pj_stun_msg_add_empty_attr( pj_pool_t *pool,
1311 pj_stun_msg *msg,
1312 int attr_type)
1313{
1314 pj_stun_empty_attr *attr = NULL;
1315 pj_status_t status;
1316
1317 status = pj_stun_empty_attr_create(pool, attr_type, &attr);
1318 if (status != PJ_SUCCESS)
1319 return status;
1320
1321 return pj_stun_msg_add_attr(msg, &attr->hdr);
1322}
1323
1324static pj_status_t decode_empty_attr(pj_pool_t *pool,
1325 const pj_uint8_t *buf,
1326 const pj_stun_msg_hdr *msghdr,
1327 void **p_attr)
1328{
1329 pj_stun_empty_attr *attr;
1330
1331 PJ_UNUSED_ARG(msghdr);
1332
1333 /* Check that the struct address is valid */
1334 pj_assert(sizeof(pj_stun_empty_attr) == ATTR_HDR_LEN);
1335
1336 /* Create the attribute */
1337 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_empty_attr);
1338 GETATTRHDR(buf, &attr->hdr);
1339
1340 /* Check that the attribute length is valid */
1341 if (attr->hdr.length != 0)
1342 return PJNATH_ESTUNINATTRLEN;
1343
1344 /* Done */
1345 *p_attr = attr;
1346
1347 return PJ_SUCCESS;
1348}
1349
1350
1351static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
1352 unsigned len,
1353 const pj_stun_msg_hdr *msghdr,
1354 unsigned *printed)
1355{
1356 const pj_stun_empty_attr *ca = (pj_stun_empty_attr*)a;
1357
1358 PJ_UNUSED_ARG(msghdr);
1359
1360 if (len < ATTR_HDR_LEN)
1361 return PJ_ETOOSMALL;
1362
1363 PUTVAL16H(buf, 0, ca->hdr.type);
1364 PUTVAL16H(buf, 2, 0);
1365
1366 /* Done */
1367 *printed = ATTR_HDR_LEN;
1368
1369 return PJ_SUCCESS;
1370}
1371
1372
1373static void* clone_empty_attr(pj_pool_t *pool, const void *src)
1374{
1375 pj_stun_empty_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_empty_attr);
1376
1377 pj_memcpy(dst, src, sizeof(pj_stun_empty_attr));
1378
1379 return (void*) dst;
1380}
1381
1382//////////////////////////////////////////////////////////////////////////////
1383/*
1384 * STUN generic 32bit integer attribute.
1385 */
1386
1387/*
1388 * Create a STUN generic 32bit value attribute.
1389 */
1390PJ_DEF(pj_status_t) pj_stun_uint_attr_create(pj_pool_t *pool,
1391 int attr_type,
1392 pj_uint32_t value,
1393 pj_stun_uint_attr **p_attr)
1394{
1395 pj_stun_uint_attr *attr;
1396
1397 PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
1398
1399 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint_attr);
1400 INIT_ATTR(attr, attr_type, 4);
1401 attr->value = value;
1402
1403 *p_attr = attr;
1404
1405 return PJ_SUCCESS;
1406}
1407
1408/* Create and add STUN generic 32bit value attribute to the message. */
1409PJ_DEF(pj_status_t) pj_stun_msg_add_uint_attr(pj_pool_t *pool,
1410 pj_stun_msg *msg,
1411 int attr_type,
1412 pj_uint32_t value)
1413{
1414 pj_stun_uint_attr *attr = NULL;
1415 pj_status_t status;
1416
1417 status = pj_stun_uint_attr_create(pool, attr_type, value, &attr);
1418 if (status != PJ_SUCCESS)
1419 return status;
1420
1421 return pj_stun_msg_add_attr(msg, &attr->hdr);
1422}
1423
1424static pj_status_t decode_uint_attr(pj_pool_t *pool,
1425 const pj_uint8_t *buf,
1426 const pj_stun_msg_hdr *msghdr,
1427 void **p_attr)
1428{
1429 pj_stun_uint_attr *attr;
1430
1431 PJ_UNUSED_ARG(msghdr);
1432
1433 /* Create the attribute */
1434 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint_attr);
1435 GETATTRHDR(buf, &attr->hdr);
1436
1437 attr->value = GETVAL32H(buf, 4);
1438
1439 /* Check that the attribute length is valid */
1440 if (attr->hdr.length != 4)
1441 return PJNATH_ESTUNINATTRLEN;
1442
1443 /* Done */
1444 *p_attr = attr;
1445
1446 return PJ_SUCCESS;
1447}
1448
1449
1450static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf,
1451 unsigned len,
1452 const pj_stun_msg_hdr *msghdr,
1453 unsigned *printed)
1454{
1455 const pj_stun_uint_attr *ca = (const pj_stun_uint_attr*)a;
1456
1457 PJ_CHECK_STACK();
1458
1459 PJ_UNUSED_ARG(msghdr);
1460
1461 if (len < 8)
1462 return PJ_ETOOSMALL;
1463
1464 PUTVAL16H(buf, 0, ca->hdr.type);
1465 PUTVAL16H(buf, 2, (pj_uint16_t)4);
1466 PUTVAL32H(buf, 4, ca->value);
1467
1468 /* Done */
1469 *printed = 8;
1470
1471 return PJ_SUCCESS;
1472}
1473
1474
1475static void* clone_uint_attr(pj_pool_t *pool, const void *src)
1476{
1477 pj_stun_uint_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_uint_attr);
1478
1479 pj_memcpy(dst, src, sizeof(pj_stun_uint_attr));
1480
1481 return (void*)dst;
1482}
1483
1484//////////////////////////////////////////////////////////////////////////////
1485
1486/*
1487 * Create a STUN generic 64bit value attribute.
1488 */
1489PJ_DEF(pj_status_t) pj_stun_uint64_attr_create(pj_pool_t *pool,
1490 int attr_type,
1491 const pj_timestamp *value,
1492 pj_stun_uint64_attr **p_attr)
1493{
1494 pj_stun_uint64_attr *attr;
1495
1496 PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
1497
1498 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint64_attr);
1499 INIT_ATTR(attr, attr_type, 8);
1500
1501 if (value) {
1502 attr->value.u32.hi = value->u32.hi;
1503 attr->value.u32.lo = value->u32.lo;
1504 }
1505
1506 *p_attr = attr;
1507
1508 return PJ_SUCCESS;
1509}
1510
1511/* Create and add STUN generic 64bit value attribute to the message. */
1512PJ_DEF(pj_status_t) pj_stun_msg_add_uint64_attr(pj_pool_t *pool,
1513 pj_stun_msg *msg,
1514 int attr_type,
1515 const pj_timestamp *value)
1516{
1517 pj_stun_uint64_attr *attr = NULL;
1518 pj_status_t status;
1519
1520 status = pj_stun_uint64_attr_create(pool, attr_type, value, &attr);
1521 if (status != PJ_SUCCESS)
1522 return status;
1523
1524 return pj_stun_msg_add_attr(msg, &attr->hdr);
1525}
1526
1527static pj_status_t decode_uint64_attr(pj_pool_t *pool,
1528 const pj_uint8_t *buf,
1529 const pj_stun_msg_hdr *msghdr,
1530 void **p_attr)
1531{
1532 pj_stun_uint64_attr *attr;
1533
1534 PJ_UNUSED_ARG(msghdr);
1535
1536 /* Create the attribute */
1537 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint64_attr);
1538 GETATTRHDR(buf, &attr->hdr);
1539
1540 if (attr->hdr.length != 8)
1541 return PJNATH_ESTUNINATTRLEN;
1542
1543 GETVAL64H(buf, 4, &attr->value);
1544
1545 /* Done */
1546 *p_attr = attr;
1547
1548 return PJ_SUCCESS;
1549}
1550
1551
1552static pj_status_t encode_uint64_attr(const void *a, pj_uint8_t *buf,
1553 unsigned len,
1554 const pj_stun_msg_hdr *msghdr,
1555 unsigned *printed)
1556{
1557 const pj_stun_uint64_attr *ca = (const pj_stun_uint64_attr*)a;
1558
1559 PJ_CHECK_STACK();
1560
1561 PJ_UNUSED_ARG(msghdr);
1562
1563 if (len < 12)
1564 return PJ_ETOOSMALL;
1565
1566 PUTVAL16H(buf, 0, ca->hdr.type);
1567 PUTVAL16H(buf, 2, (pj_uint16_t)8);
1568 PUTVAL64H(buf, 4, &ca->value);
1569
1570 /* Done */
1571 *printed = 12;
1572
1573 return PJ_SUCCESS;
1574}
1575
1576
1577static void* clone_uint64_attr(pj_pool_t *pool, const void *src)
1578{
1579 pj_stun_uint64_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_uint64_attr);
1580
1581 pj_memcpy(dst, src, sizeof(pj_stun_uint64_attr));
1582
1583 return (void*)dst;
1584}
1585
1586
1587//////////////////////////////////////////////////////////////////////////////
1588/*
1589 * STUN MESSAGE-INTEGRITY attribute.
1590 */
1591
1592/*
1593 * Create a STUN MESSAGE-INTEGRITY attribute.
1594 */
1595PJ_DEF(pj_status_t) pj_stun_msgint_attr_create(pj_pool_t *pool,
1596 pj_stun_msgint_attr **p_attr)
1597{
1598 pj_stun_msgint_attr *attr;
1599
1600 PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
1601
1602 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_msgint_attr);
1603 INIT_ATTR(attr, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 20);
1604
1605 *p_attr = attr;
1606
1607 return PJ_SUCCESS;
1608}
1609
1610
1611PJ_DEF(pj_status_t) pj_stun_msg_add_msgint_attr(pj_pool_t *pool,
1612 pj_stun_msg *msg)
1613{
1614 pj_stun_msgint_attr *attr = NULL;
1615 pj_status_t status;
1616
1617 status = pj_stun_msgint_attr_create(pool, &attr);
1618 if (status != PJ_SUCCESS)
1619 return status;
1620
1621 return pj_stun_msg_add_attr(msg, &attr->hdr);
1622}
1623
1624static pj_status_t decode_msgint_attr(pj_pool_t *pool,
1625 const pj_uint8_t *buf,
1626 const pj_stun_msg_hdr *msghdr,
1627 void **p_attr)
1628{
1629 pj_stun_msgint_attr *attr;
1630
1631 PJ_UNUSED_ARG(msghdr);
1632
1633 /* Create attribute */
1634 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_msgint_attr);
1635 GETATTRHDR(buf, &attr->hdr);
1636
1637 /* Check that the attribute length is valid */
1638 if (attr->hdr.length != 20)
1639 return PJNATH_ESTUNINATTRLEN;
1640
1641 /* Copy hmac */
1642 pj_memcpy(attr->hmac, buf+4, 20);
1643
1644 /* Done */
1645 *p_attr = attr;
1646 return PJ_SUCCESS;
1647}
1648
1649
1650static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf,
1651 unsigned len,
1652 const pj_stun_msg_hdr *msghdr,
1653 unsigned *printed)
1654{
1655 const pj_stun_msgint_attr *ca = (const pj_stun_msgint_attr*)a;
1656
1657 PJ_CHECK_STACK();
1658
1659 PJ_UNUSED_ARG(msghdr);
1660
1661 if (len < 24)
1662 return PJ_ETOOSMALL;
1663
1664 /* Copy and convert attribute to network byte order */
1665 PUTVAL16H(buf, 0, ca->hdr.type);
1666 PUTVAL16H(buf, 2, ca->hdr.length);
1667
1668 pj_memcpy(buf+4, ca->hmac, 20);
1669
1670 /* Done */
1671 *printed = 24;
1672
1673 return PJ_SUCCESS;
1674}
1675
1676
1677static void* clone_msgint_attr(pj_pool_t *pool, const void *src)
1678{
1679 pj_stun_msgint_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_msgint_attr);
1680
1681 pj_memcpy(dst, src, sizeof(pj_stun_msgint_attr));
1682
1683 return (void*) dst;
1684}
1685
1686//////////////////////////////////////////////////////////////////////////////
1687/*
1688 * STUN ERROR-CODE
1689 */
1690
1691/*
1692 * Create a STUN ERROR-CODE attribute.
1693 */
1694PJ_DEF(pj_status_t) pj_stun_errcode_attr_create(pj_pool_t *pool,
1695 int err_code,
1696 const pj_str_t *err_reason,
1697 pj_stun_errcode_attr **p_attr)
1698{
1699 pj_stun_errcode_attr *attr;
1700 char err_buf[80];
1701 pj_str_t str;
1702
1703 PJ_ASSERT_RETURN(pool && err_code && p_attr, PJ_EINVAL);
1704
1705 if (err_reason == NULL) {
1706 str = pj_stun_get_err_reason(err_code);
1707 if (str.slen == 0) {
1708 str.slen = pj_ansi_snprintf(err_buf, sizeof(err_buf),
1709 "Unknown error %d", err_code);
1710 str.ptr = err_buf;
1711 }
1712 err_reason = &str;
1713 }
1714
1715 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_errcode_attr);
1716 INIT_ATTR(attr, PJ_STUN_ATTR_ERROR_CODE, 4+err_reason->slen);
1717 attr->err_code = err_code;
1718 pj_strdup(pool, &attr->reason, err_reason);
1719
1720 *p_attr = attr;
1721
1722 return PJ_SUCCESS;
1723}
1724
1725
1726PJ_DEF(pj_status_t) pj_stun_msg_add_errcode_attr(pj_pool_t *pool,
1727 pj_stun_msg *msg,
1728 int err_code,
1729 const pj_str_t *err_reason)
1730{
1731 pj_stun_errcode_attr *err_attr = NULL;
1732 pj_status_t status;
1733
1734 status = pj_stun_errcode_attr_create(pool, err_code, err_reason,
1735 &err_attr);
1736 if (status != PJ_SUCCESS)
1737 return status;
1738
1739 return pj_stun_msg_add_attr(msg, &err_attr->hdr);
1740}
1741
1742static pj_status_t decode_errcode_attr(pj_pool_t *pool,
1743 const pj_uint8_t *buf,
1744 const pj_stun_msg_hdr *msghdr,
1745 void **p_attr)
1746{
1747 pj_stun_errcode_attr *attr;
1748 pj_str_t value;
1749
1750 PJ_UNUSED_ARG(msghdr);
1751
1752 /* Create the attribute */
1753 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_errcode_attr);
1754 GETATTRHDR(buf, &attr->hdr);
1755
1756 attr->err_code = buf[6] * 100 + buf[7];
1757
1758 /* Get pointer to the string in the message */
1759 value.ptr = ((char*)buf + ATTR_HDR_LEN + 4);
1760 value.slen = attr->hdr.length - 4;
1761
1762 /* Copy the string to the attribute */
1763 pj_strdup(pool, &attr->reason, &value);
1764
1765 /* Done */
1766 *p_attr = attr;
1767
1768 return PJ_SUCCESS;
1769}
1770
1771
1772static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf,
1773 unsigned len,
1774 const pj_stun_msg_hdr *msghdr,
1775 unsigned *printed)
1776{
1777 const pj_stun_errcode_attr *ca =
1778 (const pj_stun_errcode_attr*)a;
1779
1780 PJ_CHECK_STACK();
1781
1782 PJ_UNUSED_ARG(msghdr);
1783
1784 if (len < ATTR_HDR_LEN + 4 + (unsigned)ca->reason.slen)
1785 return PJ_ETOOSMALL;
1786
1787 /* Copy and convert attribute to network byte order */
1788 PUTVAL16H(buf, 0, ca->hdr.type);
1789 PUTVAL16H(buf, 2, (pj_uint16_t)(4 + ca->reason.slen));
1790 PUTVAL16H(buf, 4, 0);
1791 buf[6] = (pj_uint8_t)(ca->err_code / 100);
1792 buf[7] = (pj_uint8_t)(ca->err_code % 100);
1793
1794 /* Copy error string */
1795 pj_memcpy(buf + ATTR_HDR_LEN + 4, ca->reason.ptr, ca->reason.slen);
1796
1797 /* Done */
1798 *printed = (ATTR_HDR_LEN + 4 + (unsigned)ca->reason.slen + 3) & (~3);
1799
1800 return PJ_SUCCESS;
1801}
1802
1803
1804static void* clone_errcode_attr(pj_pool_t *pool, const void *src)
1805{
1806 const pj_stun_errcode_attr *asrc = (const pj_stun_errcode_attr*)src;
1807 pj_stun_errcode_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_errcode_attr);
1808
1809 pj_memcpy(dst, src, sizeof(pj_stun_errcode_attr));
1810 pj_strdup(pool, &dst->reason, &asrc->reason);
1811
1812 return (void*)dst;
1813}
1814
1815//////////////////////////////////////////////////////////////////////////////
1816/*
1817 * STUN UNKNOWN-ATTRIBUTES attribute
1818 */
1819
1820/*
1821 * Create an empty instance of STUN UNKNOWN-ATTRIBUTES attribute.
1822 *
1823 * @param pool The pool to allocate memory from.
1824 * @param p_attr Pointer to receive the attribute.
1825 *
1826 * @return PJ_SUCCESS on success or the appropriate error code.
1827 */
1828PJ_DEF(pj_status_t) pj_stun_unknown_attr_create(pj_pool_t *pool,
1829 unsigned attr_cnt,
1830 const pj_uint16_t attr_array[],
1831 pj_stun_unknown_attr **p_attr)
1832{
1833 pj_stun_unknown_attr *attr;
1834 unsigned i;
1835
1836 PJ_ASSERT_RETURN(pool && attr_cnt < PJ_STUN_MAX_ATTR && p_attr, PJ_EINVAL);
1837
1838 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_unknown_attr);
1839 INIT_ATTR(attr, PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, attr_cnt * 2);
1840
1841 attr->attr_count = attr_cnt;
1842 for (i=0; i<attr_cnt; ++i) {
1843 attr->attrs[i] = attr_array[i];
1844 }
1845
1846 /* If the number of unknown attributes is an odd number, one of the
1847 * attributes MUST be repeated in the list.
1848 */
1849 /* No longer necessary
1850 if ((attr_cnt & 0x01)) {
1851 attr->attrs[attr_cnt] = attr_array[attr_cnt-1];
1852 }
1853 */
1854
1855 *p_attr = attr;
1856
1857 return PJ_SUCCESS;
1858}
1859
1860
1861/* Create and add STUN UNKNOWN-ATTRIBUTES attribute to the message. */
1862PJ_DEF(pj_status_t) pj_stun_msg_add_unknown_attr(pj_pool_t *pool,
1863 pj_stun_msg *msg,
1864 unsigned attr_cnt,
1865 const pj_uint16_t attr_type[])
1866{
1867 pj_stun_unknown_attr *attr = NULL;
1868 pj_status_t status;
1869
1870 status = pj_stun_unknown_attr_create(pool, attr_cnt, attr_type, &attr);
1871 if (status != PJ_SUCCESS)
1872 return status;
1873
1874 return pj_stun_msg_add_attr(msg, &attr->hdr);
1875}
1876
1877static pj_status_t decode_unknown_attr(pj_pool_t *pool,
1878 const pj_uint8_t *buf,
1879 const pj_stun_msg_hdr *msghdr,
1880 void **p_attr)
1881{
1882 pj_stun_unknown_attr *attr;
1883 const pj_uint16_t *punk_attr;
1884 unsigned i;
1885
1886 PJ_UNUSED_ARG(msghdr);
1887
1888 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_unknown_attr);
1889 GETATTRHDR(buf, &attr->hdr);
1890
1891 attr->attr_count = (attr->hdr.length >> 1);
1892 if (attr->attr_count > PJ_STUN_MAX_ATTR)
1893 return PJ_ETOOMANY;
1894
1895 punk_attr = (const pj_uint16_t*)(buf + ATTR_HDR_LEN);
1896 for (i=0; i<attr->attr_count; ++i) {
1897 attr->attrs[i] = pj_ntohs(punk_attr[i]);
1898 }
1899
1900 /* Done */
1901 *p_attr = attr;
1902
1903 return PJ_SUCCESS;
1904}
1905
1906
1907static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
1908 unsigned len,
1909 const pj_stun_msg_hdr *msghdr,
1910 unsigned *printed)
1911{
1912 const pj_stun_unknown_attr *ca = (const pj_stun_unknown_attr*) a;
1913 pj_uint16_t *dst_unk_attr;
1914 unsigned i;
1915
1916 PJ_CHECK_STACK();
1917
1918 PJ_UNUSED_ARG(msghdr);
1919
1920 /* Check that buffer is enough */
1921 if (len < ATTR_HDR_LEN + (ca->attr_count << 1))
1922 return PJ_ETOOSMALL;
1923
1924 PUTVAL16H(buf, 0, ca->hdr.type);
1925 PUTVAL16H(buf, 2, (pj_uint16_t)(ca->attr_count << 1));
1926
1927 /* Copy individual attribute */
1928 dst_unk_attr = (pj_uint16_t*)(buf + ATTR_HDR_LEN);
1929 for (i=0; i < ca->attr_count; ++i, ++dst_unk_attr) {
1930 *dst_unk_attr = pj_htons(ca->attrs[i]);
1931 }
1932
1933 /* Done */
1934 *printed = (ATTR_HDR_LEN + (ca->attr_count << 1) + 3) & (~3);
1935
1936 return PJ_SUCCESS;
1937}
1938
1939
1940static void* clone_unknown_attr(pj_pool_t *pool, const void *src)
1941{
1942 pj_stun_unknown_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_unknown_attr);
1943
1944 pj_memcpy(dst, src, sizeof(pj_stun_unknown_attr));
1945
1946 return (void*)dst;
1947}
1948
1949//////////////////////////////////////////////////////////////////////////////
1950/*
1951 * STUN generic binary attribute
1952 */
1953
1954/*
1955 * Initialize STUN binary attribute.
1956 */
1957PJ_DEF(pj_status_t) pj_stun_binary_attr_init( pj_stun_binary_attr *attr,
1958 pj_pool_t *pool,
1959 int attr_type,
1960 const pj_uint8_t *data,
1961 unsigned length)
1962{
1963 PJ_ASSERT_RETURN(attr_type, PJ_EINVAL);
1964
1965 INIT_ATTR(attr, attr_type, length);
1966
1967 attr->magic = PJ_STUN_MAGIC;
1968
1969 if (data && length) {
1970 attr->length = length;
1971 attr->data = (pj_uint8_t*) pj_pool_alloc(pool, length);
1972 pj_memcpy(attr->data, data, length);
1973 } else {
1974 attr->data = NULL;
1975 attr->length = 0;
1976 }
1977
1978 return PJ_SUCCESS;
1979}
1980
1981
1982/*
1983 * Create a blank binary attribute.
1984 */
1985PJ_DEF(pj_status_t) pj_stun_binary_attr_create(pj_pool_t *pool,
1986 int attr_type,
1987 const pj_uint8_t *data,
1988 unsigned length,
1989 pj_stun_binary_attr **p_attr)
1990{
1991 pj_stun_binary_attr *attr;
1992
1993 PJ_ASSERT_RETURN(pool && attr_type && p_attr, PJ_EINVAL);
1994 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_binary_attr);
1995 *p_attr = attr;
1996 return pj_stun_binary_attr_init(attr, pool, attr_type, data, length);
1997}
1998
1999
2000/* Create and add binary attr. */
2001PJ_DEF(pj_status_t) pj_stun_msg_add_binary_attr(pj_pool_t *pool,
2002 pj_stun_msg *msg,
2003 int attr_type,
2004 const pj_uint8_t *data,
2005 unsigned length)
2006{
2007 pj_stun_binary_attr *attr = NULL;
2008 pj_status_t status;
2009
2010 status = pj_stun_binary_attr_create(pool, attr_type,
2011 data, length, &attr);
2012 if (status != PJ_SUCCESS)
2013 return status;
2014
2015 return pj_stun_msg_add_attr(msg, &attr->hdr);
2016}
2017
2018
2019static pj_status_t decode_binary_attr(pj_pool_t *pool,
2020 const pj_uint8_t *buf,
2021 const pj_stun_msg_hdr *msghdr,
2022 void **p_attr)
2023{
2024 pj_stun_binary_attr *attr;
2025
2026 PJ_UNUSED_ARG(msghdr);
2027
2028 /* Create the attribute */
2029 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_binary_attr);
2030 GETATTRHDR(buf, &attr->hdr);
2031
2032 /* Copy the data to the attribute */
2033 attr->length = attr->hdr.length;
2034 attr->data = (pj_uint8_t*) pj_pool_alloc(pool, attr->length);
2035 pj_memcpy(attr->data, buf+ATTR_HDR_LEN, attr->length);
2036
2037 /* Done */
2038 *p_attr = attr;
2039
2040 return PJ_SUCCESS;
2041
2042}
2043
2044
2045static pj_status_t encode_binary_attr(const void *a, pj_uint8_t *buf,
2046 unsigned len,
2047 const pj_stun_msg_hdr *msghdr,
2048 unsigned *printed)
2049{
2050 const pj_stun_binary_attr *ca = (const pj_stun_binary_attr*)a;
2051
2052 PJ_CHECK_STACK();
2053
2054 PJ_UNUSED_ARG(msghdr);
2055
2056 /* Calculated total attr_len (add padding if necessary) */
2057 *printed = (ca->length + ATTR_HDR_LEN + 3) & (~3);
2058 if (len < *printed)
2059 return PJ_ETOOSMALL;
2060
2061 PUTVAL16H(buf, 0, ca->hdr.type);
2062 PUTVAL16H(buf, 2, (pj_uint16_t) ca->length);
2063
2064 /* Copy the data */
2065 pj_memcpy(buf+ATTR_HDR_LEN, ca->data, ca->length);
2066
2067 /* Done */
2068 return PJ_SUCCESS;
2069}
2070
2071
2072static void* clone_binary_attr(pj_pool_t *pool, const void *src)
2073{
2074 const pj_stun_binary_attr *asrc = (const pj_stun_binary_attr*)src;
2075 pj_stun_binary_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_binary_attr);
2076
2077 pj_memcpy(dst, src, sizeof(pj_stun_binary_attr));
2078
2079 if (asrc->length) {
2080 dst->data = (pj_uint8_t*) pj_pool_alloc(pool, asrc->length);
2081 pj_memcpy(dst->data, asrc->data, asrc->length);
2082 }
2083
2084 return (void*)dst;
2085}
2086
2087//////////////////////////////////////////////////////////////////////////////
2088
2089/*
2090 * Initialize a generic STUN message.
2091 */
2092PJ_DEF(pj_status_t) pj_stun_msg_init( pj_stun_msg *msg,
2093 unsigned msg_type,
2094 pj_uint32_t magic,
2095 const pj_uint8_t tsx_id[12])
2096{
2097 PJ_ASSERT_RETURN(msg && msg_type, PJ_EINVAL);
2098
2099 msg->hdr.type = (pj_uint16_t) msg_type;
2100 msg->hdr.length = 0;
2101 msg->hdr.magic = magic;
2102 msg->attr_count = 0;
2103
2104 if (tsx_id) {
2105 pj_memcpy(&msg->hdr.tsx_id, tsx_id, sizeof(msg->hdr.tsx_id));
2106 } else {
2107 struct transaction_id
2108 {
2109 pj_uint32_t proc_id;
2110 pj_uint32_t random;
2111 pj_uint32_t counter;
2112 } id;
2113 static pj_uint32_t pj_stun_tsx_id_counter;
2114
2115 if (!pj_stun_tsx_id_counter)
2116 pj_stun_tsx_id_counter = pj_rand();
2117
2118 id.proc_id = pj_getpid();
2119 id.random = pj_rand();
2120 id.counter = pj_stun_tsx_id_counter++;
2121
2122 pj_memcpy(&msg->hdr.tsx_id, &id, sizeof(msg->hdr.tsx_id));
2123 }
2124
2125 return PJ_SUCCESS;
2126}
2127
2128
2129/*
2130 * Create a blank STUN message.
2131 */
2132PJ_DEF(pj_status_t) pj_stun_msg_create( pj_pool_t *pool,
2133 unsigned msg_type,
2134 pj_uint32_t magic,
2135 const pj_uint8_t tsx_id[12],
2136 pj_stun_msg **p_msg)
2137{
2138 pj_stun_msg *msg;
2139
2140 PJ_ASSERT_RETURN(pool && msg_type && p_msg, PJ_EINVAL);
2141
2142 msg = PJ_POOL_ZALLOC_T(pool, pj_stun_msg);
2143 *p_msg = msg;
2144 return pj_stun_msg_init(msg, msg_type, magic, tsx_id);
2145}
2146
2147
2148/*
2149 * Clone a STUN message with all of its attributes.
2150 */
2151PJ_DEF(pj_stun_msg*) pj_stun_msg_clone( pj_pool_t *pool,
2152 const pj_stun_msg *src)
2153{
2154 pj_stun_msg *dst;
2155 unsigned i;
2156
2157 PJ_ASSERT_RETURN(pool && src, NULL);
2158
2159 dst = PJ_POOL_ZALLOC_T(pool, pj_stun_msg);
2160 pj_memcpy(dst, src, sizeof(pj_stun_msg));
2161
2162 /* Duplicate the attributes */
2163 for (i=0, dst->attr_count=0; i<src->attr_count; ++i) {
2164 dst->attr[dst->attr_count] = pj_stun_attr_clone(pool, src->attr[i]);
2165 if (dst->attr[dst->attr_count])
2166 ++dst->attr_count;
2167 }
2168
2169 return dst;
2170}
2171
2172
2173/*
2174 * Add STUN attribute to STUN message.
2175 */
2176PJ_DEF(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg,
2177 pj_stun_attr_hdr *attr)
2178{
2179 PJ_ASSERT_RETURN(msg && attr, PJ_EINVAL);
2180 PJ_ASSERT_RETURN(msg->attr_count < PJ_STUN_MAX_ATTR, PJ_ETOOMANY);
2181
2182 msg->attr[msg->attr_count++] = attr;
2183 return PJ_SUCCESS;
2184}
2185
2186
2187/*
2188 * Check that the PDU is potentially a valid STUN message.
2189 */
2190PJ_DEF(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, pj_size_t pdu_len,
2191 unsigned options)
2192{
2193 pj_uint32_t msg_len;
2194
2195 PJ_ASSERT_RETURN(pdu, PJ_EINVAL);
2196
2197 if (pdu_len < sizeof(pj_stun_msg_hdr))
2198 return PJNATH_EINSTUNMSGLEN;
2199
2200 /* First byte of STUN message is always 0x00 or 0x01. */
2201 if (*pdu != 0x00 && *pdu != 0x01)
2202 return PJNATH_EINSTUNMSGTYPE;
2203
2204 /* Check the PDU length */
2205 msg_len = GETVAL16H(pdu, 2);
2206 if ((msg_len + 20 > pdu_len) ||
2207 ((options & PJ_STUN_IS_DATAGRAM) && msg_len + 20 != pdu_len))
2208 {
2209 return PJNATH_EINSTUNMSGLEN;
2210 }
2211
2212 /* STUN message is always padded to the nearest 4 bytes, thus
2213 * the last two bits of the length field are always zero.
2214 */
2215 if ((msg_len & 0x03) != 0) {
2216 return PJNATH_EINSTUNMSGLEN;
2217 }
2218
2219 /* If magic is set, then there is great possibility that this is
2220 * a STUN message.
2221 */
2222 if (GETVAL32H(pdu, 4) == PJ_STUN_MAGIC) {
2223
2224 /* Check if FINGERPRINT attribute is present */
2225 if ((options & PJ_STUN_NO_FINGERPRINT_CHECK )==0 &&
2226 GETVAL16H(pdu, msg_len + 20 - 8) == PJ_STUN_ATTR_FINGERPRINT)
2227 {
2228 pj_uint16_t attr_len = GETVAL16H(pdu, msg_len + 20 - 8 + 2);
2229 pj_uint32_t fingerprint = GETVAL32H(pdu, msg_len + 20 - 8 + 4);
2230 pj_uint32_t crc;
2231
2232 if (attr_len != 4)
2233 return PJNATH_ESTUNINATTRLEN;
2234
2235 crc = pj_crc32_calc(pdu, msg_len + 20 - 8);
2236 crc ^= STUN_XOR_FINGERPRINT;
2237
2238 if (crc != fingerprint)
2239 return PJNATH_ESTUNFINGERPRINT;
2240 }
2241 }
2242
2243 /* Could be a STUN message */
2244 return PJ_SUCCESS;
2245}
2246
2247
2248/* Create error response */
2249PJ_DEF(pj_status_t) pj_stun_msg_create_response(pj_pool_t *pool,
2250 const pj_stun_msg *req_msg,
2251 unsigned err_code,
2252 const pj_str_t *err_msg,
2253 pj_stun_msg **p_response)
2254{
2255 unsigned msg_type = req_msg->hdr.type;
2256 pj_stun_msg *response = NULL;
2257 pj_status_t status;
2258
2259 PJ_ASSERT_RETURN(pool && p_response, PJ_EINVAL);
2260
2261 PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(msg_type),
2262 PJNATH_EINSTUNMSGTYPE);
2263
2264 /* Create response or error response */
2265 if (err_code)
2266 msg_type |= PJ_STUN_ERROR_RESPONSE_BIT;
2267 else
2268 msg_type |= PJ_STUN_SUCCESS_RESPONSE_BIT;
2269
2270 status = pj_stun_msg_create(pool, msg_type, req_msg->hdr.magic,
2271 req_msg->hdr.tsx_id, &response);
2272 if (status != PJ_SUCCESS) {
2273 return status;
2274 }
2275
2276 /* Add error code attribute */
2277 if (err_code) {
2278 status = pj_stun_msg_add_errcode_attr(pool, response,
2279 err_code, err_msg);
2280 if (status != PJ_SUCCESS) {
2281 return status;
2282 }
2283 }
2284
2285 *p_response = response;
2286 return PJ_SUCCESS;
2287}
2288
2289
2290/*
2291 * Parse incoming packet into STUN message.
2292 */
2293PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
2294 const pj_uint8_t *pdu,
2295 pj_size_t pdu_len,
2296 unsigned options,
2297 pj_stun_msg **p_msg,
2298 pj_size_t *p_parsed_len,
2299 pj_stun_msg **p_response)
2300{
2301
2302 pj_stun_msg *msg;
2303 unsigned uattr_cnt;
2304 const pj_uint8_t *start_pdu = pdu;
2305 pj_bool_t has_msg_int = PJ_FALSE;
2306 pj_bool_t has_fingerprint = PJ_FALSE;
2307 pj_status_t status;
2308
2309 PJ_UNUSED_ARG(options);
2310
2311 PJ_ASSERT_RETURN(pool && pdu && pdu_len && p_msg, PJ_EINVAL);
2312 PJ_ASSERT_RETURN(sizeof(pj_stun_msg_hdr) == 20, PJ_EBUG);
2313
2314 if (p_parsed_len)
2315 *p_parsed_len = 0;
2316 if (p_response)
2317 *p_response = NULL;
2318
2319 /* Check if this is a STUN message, if necessary */
2320 if (options & PJ_STUN_CHECK_PACKET) {
2321 status = pj_stun_msg_check(pdu, pdu_len, options);
2322 if (status != PJ_SUCCESS)
2323 return status;
2324 }
2325
2326 /* Create the message, copy the header, and convert to host byte order */
2327 msg = PJ_POOL_ZALLOC_T(pool, pj_stun_msg);
2328 pj_memcpy(&msg->hdr, pdu, sizeof(pj_stun_msg_hdr));
2329 msg->hdr.type = pj_ntohs(msg->hdr.type);
2330 msg->hdr.length = pj_ntohs(msg->hdr.length);
2331 msg->hdr.magic = pj_ntohl(msg->hdr.magic);
2332
2333 pdu += sizeof(pj_stun_msg_hdr);
2334 /* pdu_len -= sizeof(pj_stun_msg_hdr); */
2335 pdu_len = msg->hdr.length;
2336
2337 /* No need to create response if this is not a request */
2338 if (!PJ_STUN_IS_REQUEST(msg->hdr.type))
2339 p_response = NULL;
2340
2341 /* Parse attributes */
2342 uattr_cnt = 0;
2343 while (pdu_len >= 4) {
2344 unsigned attr_type, attr_val_len;
2345 const struct attr_desc *adesc;
2346
2347 /* Get attribute type and length. If length is not aligned
2348 * to 4 bytes boundary, add padding.
2349 */
2350 attr_type = GETVAL16H(pdu, 0);
2351 attr_val_len = GETVAL16H(pdu, 2);
2352 attr_val_len = (attr_val_len + 3) & (~3);
2353
2354 /* Check length */
2355 if (pdu_len < attr_val_len) {
2356 pj_str_t err_msg;
2357 char err_msg_buf[80];
2358
2359 err_msg.ptr = err_msg_buf;
2360 err_msg.slen = pj_ansi_snprintf(err_msg_buf, sizeof(err_msg_buf),
2361 "Attribute %s has invalid length",
2362 pj_stun_get_attr_name(attr_type));
2363
2364 PJ_LOG(4,(THIS_FILE, "Error decoding message: %.*s",
2365 (int)err_msg.slen, err_msg.ptr));
2366
2367 if (p_response) {
2368 pj_stun_msg_create_response(pool, msg,
2369 PJ_STUN_SC_BAD_REQUEST,
2370 &err_msg, p_response);
2371 }
2372 return PJNATH_ESTUNINATTRLEN;
2373 }
2374
2375 /* Get the attribute descriptor */
2376 adesc = find_attr_desc(attr_type);
2377
2378 if (adesc == NULL) {
2379 /* Unrecognized attribute */
2380 pj_stun_binary_attr *attr = NULL;
2381
2382 PJ_LOG(5,(THIS_FILE, "Unrecognized attribute type 0x%x",
2383 attr_type));
2384
2385 /* Is this a fatal condition? */
2386 if (attr_type <= 0x7FFF) {
2387 /* This is a mandatory attribute, we must return error
2388 * if we don't understand the attribute.
2389 */
2390 if (p_response) {
2391 unsigned err_code = PJ_STUN_SC_UNKNOWN_ATTRIBUTE;
2392
2393 status = pj_stun_msg_create_response(pool, msg,
2394 err_code, NULL,
2395 p_response);
2396 if (status==PJ_SUCCESS) {
2397 pj_uint16_t d = (pj_uint16_t)attr_type;
2398 pj_stun_msg_add_unknown_attr(pool, *p_response, 1, &d);
2399 }
2400 }
2401
2402 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNKNOWN_ATTRIBUTE);
2403 }
2404
2405 /* Make sure we have rooms for the new attribute */
2406 if (msg->attr_count >= PJ_STUN_MAX_ATTR) {
2407 if (p_response) {
2408 pj_stun_msg_create_response(pool, msg,
2409 PJ_STUN_SC_SERVER_ERROR,
2410 NULL, p_response);
2411 }
2412 return PJNATH_ESTUNTOOMANYATTR;
2413 }
2414
2415 /* Create binary attribute to represent this */
2416 status = pj_stun_binary_attr_create(pool, attr_type, pdu+4,
2417 GETVAL16H(pdu, 2), &attr);
2418 if (status != PJ_SUCCESS) {
2419 if (p_response) {
2420 pj_stun_msg_create_response(pool, msg,
2421 PJ_STUN_SC_SERVER_ERROR,
2422 NULL, p_response);
2423 }
2424
2425 PJ_LOG(4,(THIS_FILE,
2426 "Error parsing unknown STUN attribute type %d",
2427 attr_type));
2428
2429 return status;
2430 }
2431
2432 /* Add the attribute */
2433 msg->attr[msg->attr_count++] = &attr->hdr;
2434
2435 } else {
2436 void *attr;
2437 char err_msg1[PJ_ERR_MSG_SIZE],
2438 err_msg2[PJ_ERR_MSG_SIZE];
2439
2440 /* Parse the attribute */
2441 status = (adesc->decode_attr)(pool, pdu, &msg->hdr, &attr);
2442
2443 if (status != PJ_SUCCESS) {
2444 pj_strerror(status, err_msg1, sizeof(err_msg1));
2445
2446 if (p_response) {
2447 pj_str_t e;
2448
2449 e.ptr = err_msg2;
2450 e.slen= pj_ansi_snprintf(err_msg2, sizeof(err_msg2),
2451 "%s in %s",
2452 err_msg1,
2453 pj_stun_get_attr_name(attr_type));
2454
2455 pj_stun_msg_create_response(pool, msg,
2456 PJ_STUN_SC_BAD_REQUEST,
2457 &e, p_response);
2458 }
2459
2460 PJ_LOG(4,(THIS_FILE,
2461 "Error parsing STUN attribute %s: %s",
2462 pj_stun_get_attr_name(attr_type),
2463 err_msg1));
2464
2465 return status;
2466 }
2467
2468 if (attr_type == PJ_STUN_ATTR_MESSAGE_INTEGRITY &&
2469 !has_fingerprint)
2470 {
2471 if (has_msg_int) {
2472 /* Already has MESSAGE-INTEGRITY */
2473 if (p_response) {
2474 pj_stun_msg_create_response(pool, msg,
2475 PJ_STUN_SC_BAD_REQUEST,
2476 NULL, p_response);
2477 }
2478 return PJNATH_ESTUNDUPATTR;
2479 }
2480 has_msg_int = PJ_TRUE;
2481
2482 } else if (attr_type == PJ_STUN_ATTR_FINGERPRINT) {
2483 if (has_fingerprint) {
2484 /* Already has FINGERPRINT */
2485 if (p_response) {
2486 pj_stun_msg_create_response(pool, msg,
2487 PJ_STUN_SC_BAD_REQUEST,
2488 NULL, p_response);
2489 }
2490 return PJNATH_ESTUNDUPATTR;
2491 }
2492 has_fingerprint = PJ_TRUE;
2493 } else {
2494 if (has_fingerprint) {
2495 /* Another attribute is found which is not FINGERPRINT
2496 * after FINGERPRINT. Note that non-FINGERPRINT is
2497 * allowed to appear after M-I
2498 */
2499 if (p_response) {
2500 pj_stun_msg_create_response(pool, msg,
2501 PJ_STUN_SC_BAD_REQUEST,
2502 NULL, p_response);
2503 }
2504 return PJNATH_ESTUNFINGERPOS;
2505 }
2506 }
2507
2508 /* Make sure we have rooms for the new attribute */
2509 if (msg->attr_count >= PJ_STUN_MAX_ATTR) {
2510 if (p_response) {
2511 pj_stun_msg_create_response(pool, msg,
2512 PJ_STUN_SC_SERVER_ERROR,
2513 NULL, p_response);
2514 }
2515 return PJNATH_ESTUNTOOMANYATTR;
2516 }
2517
2518 /* Add the attribute */
2519 msg->attr[msg->attr_count++] = (pj_stun_attr_hdr*)attr;
2520 }
2521
2522 /* Next attribute */
2523 if (attr_val_len + 4 >= pdu_len) {
2524 pdu += pdu_len;
2525 pdu_len = 0;
2526 } else {
2527 pdu += (attr_val_len + 4);
2528 pdu_len -= (attr_val_len + 4);
2529 }
2530 }
2531
2532 if (pdu_len > 0) {
2533 /* Stray trailing bytes */
2534 PJ_LOG(4,(THIS_FILE,
2535 "Error decoding STUN message: unparsed trailing %d bytes",
2536 pdu_len));
2537 return PJNATH_EINSTUNMSGLEN;
2538 }
2539
2540 *p_msg = msg;
2541
2542 if (p_parsed_len)
2543 *p_parsed_len = (pdu - start_pdu);
2544
2545 return PJ_SUCCESS;
2546}
2547
2548/*
2549static char *print_binary(const pj_uint8_t *data, unsigned data_len)
2550{
2551 static char static_buffer[1024];
2552 char *buffer = static_buffer;
2553 unsigned length=sizeof(static_buffer), i;
2554
2555 if (length < data_len * 2 + 8)
2556 return "";
2557
2558 pj_ansi_sprintf(buffer, ", data=");
2559 buffer += 7;
2560
2561 for (i=0; i<data_len; ++i) {
2562 pj_ansi_sprintf(buffer, "%02x", (*data) & 0xFF);
2563 buffer += 2;
2564 data++;
2565 }
2566
2567 pj_ansi_sprintf(buffer, "\n");
2568 buffer++;
2569
2570 return static_buffer;
2571}
2572*/
2573
2574/*
2575 * Print the message structure to a buffer.
2576 */
2577PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
2578 pj_uint8_t *buf, pj_size_t buf_size,
2579 unsigned options,
2580 const pj_str_t *key,
2581 pj_size_t *p_msg_len)
2582{
2583 pj_uint8_t *start = buf;
2584 pj_stun_msgint_attr *amsgint = NULL;
2585 pj_stun_fingerprint_attr *afingerprint = NULL;
2586 unsigned printed = 0, body_len;
2587 pj_status_t status;
2588 unsigned i;
2589
2590
2591 PJ_ASSERT_RETURN(msg && buf && buf_size, PJ_EINVAL);
2592
2593 PJ_UNUSED_ARG(options);
2594 PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
2595
2596 /* Copy the message header part and convert the header fields to
2597 * network byte order
2598 */
2599 if (buf_size < sizeof(pj_stun_msg_hdr))
2600 return PJ_ETOOSMALL;
2601
2602 PUTVAL16H(buf, 0, msg->hdr.type);
2603 PUTVAL16H(buf, 2, 0); /* length will be calculated later */
2604 PUTVAL32H(buf, 4, msg->hdr.magic);
2605 pj_memcpy(buf+8, msg->hdr.tsx_id, sizeof(msg->hdr.tsx_id));
2606
2607 buf += sizeof(pj_stun_msg_hdr);
2608 buf_size -= sizeof(pj_stun_msg_hdr);
2609
2610 /* Encode each attribute to the message */
2611 for (i=0; i<msg->attr_count; ++i) {
2612 const struct attr_desc *adesc;
2613 const pj_stun_attr_hdr *attr_hdr = msg->attr[i];
2614
2615 if (attr_hdr->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
2616 pj_assert(amsgint == NULL);
2617 amsgint = (pj_stun_msgint_attr*) attr_hdr;
2618
2619 /* Stop when encountering MESSAGE-INTEGRITY */
2620 break;
2621
2622 } else if (attr_hdr->type == PJ_STUN_ATTR_FINGERPRINT) {
2623 afingerprint = (pj_stun_fingerprint_attr*) attr_hdr;
2624 break;
2625 }
2626
2627 adesc = find_attr_desc(attr_hdr->type);
2628 if (adesc) {
2629 status = adesc->encode_attr(attr_hdr, buf, (unsigned)buf_size,
2630 &msg->hdr, &printed);
2631 } else {
2632 /* This may be a generic attribute */
2633 const pj_stun_binary_attr *bin_attr = (const pj_stun_binary_attr*)
2634 attr_hdr;
2635 PJ_ASSERT_RETURN(bin_attr->magic == PJ_STUN_MAGIC, PJ_EBUG);
2636 status = encode_binary_attr(bin_attr, buf, (unsigned)buf_size,
2637 &msg->hdr, &printed);
2638 }
2639
2640 if (status != PJ_SUCCESS)
2641 return status;
2642
2643 buf += printed;
2644 buf_size -= printed;
2645 }
2646
2647 /* We may have stopped printing attribute because we found
2648 * MESSAGE-INTEGRITY or FINGERPRINT. Scan the rest of the
2649 * attributes.
2650 */
2651 for ( ++i; i<msg->attr_count; ++i) {
2652 const pj_stun_attr_hdr *attr_hdr = msg->attr[i];
2653
2654 /* There mustn't any attribute after FINGERPRINT */
2655 PJ_ASSERT_RETURN(afingerprint == NULL, PJNATH_ESTUNFINGERPOS);
2656
2657 if (attr_hdr->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
2658 /* There mustn't be MESSAGE-INTEGRITY before */
2659 PJ_ASSERT_RETURN(amsgint == NULL,
2660 PJNATH_ESTUNMSGINTPOS);
2661 amsgint = (pj_stun_msgint_attr*) attr_hdr;
2662
2663 } else if (attr_hdr->type == PJ_STUN_ATTR_FINGERPRINT) {
2664 afingerprint = (pj_stun_fingerprint_attr*) attr_hdr;
2665 }
2666 }
2667
2668#if PJ_STUN_OLD_STYLE_MI_FINGERPRINT
2669 /*
2670 * This is the old style MESSAGE-INTEGRITY and FINGERPRINT
2671 * calculation, used in rfc3489bis-06 and older.
2672 */
2673 /* We MUST update the message length in the header NOW before
2674 * calculating MESSAGE-INTEGRITY and FINGERPRINT.
2675 * Note that length is not including the 20 bytes header.
2676 */
2677 if (amsgint && afingerprint) {
2678 body_len = (pj_uint16_t)((buf - start) - 20 + 24 + 8);
2679 } else if (amsgint) {
2680 body_len = (pj_uint16_t)((buf - start) - 20 + 24);
2681 } else if (afingerprint) {
2682 body_len = (pj_uint16_t)((buf - start) - 20 + 8);
2683 } else {
2684 body_len = (pj_uint16_t)((buf - start) - 20);
2685 }
2686#else
2687 /* If MESSAGE-INTEGRITY is present, include the M-I attribute
2688 * in message length before calculating M-I
2689 */
2690 if (amsgint) {
2691 body_len = (pj_uint16_t)((buf - start) - 20 + 24);
2692 } else {
2693 body_len = (pj_uint16_t)((buf - start) - 20);
2694 }
2695#endif /* PJ_STUN_OLD_STYLE_MI_FINGERPRINT */
2696
2697 /* hdr->length = pj_htons(length); */
2698 PUTVAL16H(start, 2, (pj_uint16_t)body_len);
2699
2700 /* Calculate message integrity, if present */
2701 if (amsgint != NULL) {
2702 pj_hmac_sha1_context ctx;
2703
2704 /* Key MUST be specified */
2705 PJ_ASSERT_RETURN(key, PJ_EINVALIDOP);
2706
2707 /* MESSAGE-INTEGRITY must be the last attribute in the message, or
2708 * the last attribute before FINGERPRINT.
2709 */
2710 if (msg->attr_count>1 && i < msg->attr_count-2) {
2711 /* Should not happen for message generated by us */
2712 pj_assert(PJ_FALSE);
2713 return PJNATH_ESTUNMSGINTPOS;
2714
2715 } else if (i == msg->attr_count-2) {
2716 if (msg->attr[i+1]->type != PJ_STUN_ATTR_FINGERPRINT) {
2717 /* Should not happen for message generated by us */
2718 pj_assert(PJ_FALSE);
2719 return PJNATH_ESTUNMSGINTPOS;
2720 } else {
2721 afingerprint = (pj_stun_fingerprint_attr*) msg->attr[i+1];
2722 }
2723 }
2724
2725 /* Calculate HMAC-SHA1 digest, add zero padding to input
2726 * if necessary to make the input 64 bytes aligned.
2727 */
2728 pj_hmac_sha1_init(&ctx, (const pj_uint8_t*)key->ptr,
2729 (unsigned)key->slen);
2730 pj_hmac_sha1_update(&ctx, (const pj_uint8_t*)start,
2731 (unsigned)(buf-start));
2732#if PJ_STUN_OLD_STYLE_MI_FINGERPRINT
2733 // These are obsoleted in rfc3489bis-08
2734 if ((buf-start) & 0x3F) {
2735 pj_uint8_t zeroes[64];
2736 pj_bzero(zeroes, sizeof(zeroes));
2737 pj_hmac_sha1_update(&ctx, zeroes, 64-((buf-start) & 0x3F));
2738 }
2739#endif /* PJ_STUN_OLD_STYLE_MI_FINGERPRINT */
2740 pj_hmac_sha1_final(&ctx, amsgint->hmac);
2741
2742 /* Put this attribute in the message */
2743 status = encode_msgint_attr(amsgint, buf, (unsigned)buf_size,
2744 &msg->hdr, &printed);
2745 if (status != PJ_SUCCESS)
2746 return status;
2747
2748 buf += printed;
2749 buf_size -= printed;
2750 }
2751
2752 /* Calculate FINGERPRINT if present */
2753 if (afingerprint != NULL) {
2754
2755#if !PJ_STUN_OLD_STYLE_MI_FINGERPRINT
2756 /* Update message length */
2757 PUTVAL16H(start, 2,
2758 (pj_uint16_t)(GETVAL16H(start, 2)+8));
2759#endif
2760
2761 afingerprint->value = pj_crc32_calc(start, buf-start);
2762 afingerprint->value ^= STUN_XOR_FINGERPRINT;
2763
2764 /* Put this attribute in the message */
2765 status = encode_uint_attr(afingerprint, buf, (unsigned)buf_size,
2766 &msg->hdr, &printed);
2767 if (status != PJ_SUCCESS)
2768 return status;
2769
2770 buf += printed;
2771 buf_size -= printed;
2772 }
2773
2774 /* Update message length. */
2775 msg->hdr.length = (pj_uint16_t) ((buf - start) - 20);
2776
2777 /* Return the length */
2778 if (p_msg_len)
2779 *p_msg_len = (buf - start);
2780
2781 return PJ_SUCCESS;
2782}
2783
2784
2785/*
2786 * Find STUN attribute in the STUN message, starting from the specified
2787 * index.
2788 */
2789PJ_DEF(pj_stun_attr_hdr*) pj_stun_msg_find_attr( const pj_stun_msg *msg,
2790 int attr_type,
2791 unsigned index)
2792{
2793 PJ_ASSERT_RETURN(msg, NULL);
2794
2795 for (; index < msg->attr_count; ++index) {
2796 if (msg->attr[index]->type == attr_type)
2797 return (pj_stun_attr_hdr*) msg->attr[index];
2798 }
2799
2800 return NULL;
2801}
2802
2803
2804/*
2805 * Clone a STUN attribute.
2806 */
2807PJ_DEF(pj_stun_attr_hdr*) pj_stun_attr_clone( pj_pool_t *pool,
2808 const pj_stun_attr_hdr *attr)
2809{
2810 const struct attr_desc *adesc;
2811
2812 /* Get the attribute descriptor */
2813 adesc = find_attr_desc(attr->type);
2814 if (adesc) {
2815 return (pj_stun_attr_hdr*) (*adesc->clone_attr)(pool, attr);
2816 } else {
2817 /* Clone generic attribute */
2818 const pj_stun_binary_attr *bin_attr = (const pj_stun_binary_attr*)
2819 attr;
2820 PJ_ASSERT_RETURN(bin_attr->magic == PJ_STUN_MAGIC, NULL);
2821 if (bin_attr->magic == PJ_STUN_MAGIC) {
2822 return (pj_stun_attr_hdr*) clone_binary_attr(pool, attr);
2823 } else {
2824 return NULL;
2825 }
2826 }
2827}
2828
2829