Part of ticket #780 (work in progress): added IPv6 support to various STUN attributes and added the test from draft-ietf-behave-stun-test-vectors
git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@2580 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
ad4bb0aa3d
commit
0fc2c6bb34
|
@ -114,12 +114,17 @@
|
|||
* STUN IPv6 attribute not supported
|
||||
*/
|
||||
#define PJNATH_ESTUNIPV6NOTSUPP (PJNATH_ERRNO_START+41) /* 370041 */
|
||||
/**
|
||||
* @hideinitializer
|
||||
* Invalid address family value in STUN message.
|
||||
*/
|
||||
#define PJNATH_EINVAF (PJNATH_ERRNO_START+42) /* 370042 */
|
||||
|
||||
/**
|
||||
* @hideinitializer
|
||||
* Invalid STUN server or server not configured.
|
||||
*/
|
||||
#define PJNATH_ESTUNINSERVER (PJNATH_ERRNO_START+42) /* 370042 */
|
||||
#define PJNATH_ESTUNINSERVER (PJNATH_ERRNO_START+50) /* 370050 */
|
||||
|
||||
|
||||
/************************************************************
|
||||
|
|
|
@ -97,10 +97,9 @@ application protocols in dealing with NAT traversal. It allows a client
|
|||
to determine the IP address and port allocated to them by a NAT and to
|
||||
keep NAT bindings open.
|
||||
|
||||
This version of PJNATH implements the following STUN-bis draft:
|
||||
- <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-rfc3489bis-18.txt">
|
||||
<B>draft-ietf-behave-rfc3489bis-18</b></A>: Session Traversal
|
||||
Utilities for (NAT) (STUN),
|
||||
This version of PJNATH implements the following STUN RFC:
|
||||
- <A HREF="http://www.ietf.org/rfc/rfc5389.txt"><B>RFC 5389</b></A>:
|
||||
Session Traversal Utilities for (NAT) (STUN),
|
||||
|
||||
|
||||
\subsection comp_turn TURN
|
||||
|
|
|
@ -430,10 +430,15 @@ static int decode_verify(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test vectors, from:
|
||||
* http://tools.ietf.org/html/draft-denis-behave-rfc3489bis-test-vectors-02
|
||||
*/
|
||||
typedef struct test_vector test_vector;
|
||||
|
||||
static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v);
|
||||
static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v);
|
||||
static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v);
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -441,7 +446,7 @@ enum
|
|||
USE_FINGERPRINT = 2
|
||||
};
|
||||
|
||||
struct test_vector
|
||||
static struct test_vector
|
||||
{
|
||||
unsigned msg_type;
|
||||
char *tsx_id;
|
||||
|
@ -450,6 +455,8 @@ struct test_vector
|
|||
unsigned options;
|
||||
char *username;
|
||||
char *password;
|
||||
char *realm;
|
||||
char *nonce;
|
||||
pj_stun_msg* (*create)(pj_pool_t*, test_vector*);
|
||||
} test_vectors[] =
|
||||
{
|
||||
|
@ -469,24 +476,68 @@ struct test_vector
|
|||
USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
|
||||
"evtj:h6vY",
|
||||
"VOkJxbRl1RmTxUk/WvJxBt",
|
||||
"",
|
||||
"",
|
||||
&create_msgint1
|
||||
},
|
||||
{
|
||||
PJ_STUN_BINDING_RESPONSE,
|
||||
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
|
||||
"\x01\x01\x00\x3c\x21\x12\xa4\x42\xb7\xe7"
|
||||
"\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
|
||||
"\x80\x22\x00\x0b\x74\x65\x73\x74\x20\x76"
|
||||
"\x65\x63\x74\x6f\x72\x20\x00\x20\x00\x08"
|
||||
"\x00\x01\xa1\x47\x5e\x12\xa4\x43\x00\x08"
|
||||
"\x00\x14\xab\x4e\x53\x29\x61\x00\x08\x4c"
|
||||
"\x89\xf2\x7c\x69\x30\x33\x5c\xa3\x58\x14"
|
||||
"\xea\x90\x80\x28\x00\x04\xae\x25\x8d\xf2",
|
||||
"\x01\x01\x00\x3c"
|
||||
"\x21\x12\xa4\x42"
|
||||
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
|
||||
"\x80\x22\x00\x0b"
|
||||
"\x74\x65\x73\x74\x20\x76\x65\x63\x74\x6f\x72\x20"
|
||||
"\x00\x20\x00\x08"
|
||||
"\x00\x01\xa1\x47\xe1\x12\xa6\x43"
|
||||
"\x00\x08\x00\x14"
|
||||
"\x2b\x91\xf5\x99\xfd\x9e\x90\xc3\x8c\x74\x89\xf9"
|
||||
"\x2a\xf9\xba\x53\xf0\x6b\xe7\xd7"
|
||||
"\x80\x28\x00\x04"
|
||||
"\xc0\x7d\x4c\x96",
|
||||
80,
|
||||
USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
|
||||
"evtj:h6vY",
|
||||
"VOkJxbRl1RmTxUk/WvJxBt",
|
||||
"",
|
||||
"",
|
||||
&create_msgint2
|
||||
},
|
||||
{
|
||||
PJ_STUN_BINDING_RESPONSE,
|
||||
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
|
||||
"\x01\x01\x00\x48" // Response type and message length
|
||||
"\x21\x12\xa4\x42" // Message cookie
|
||||
"\xb7\xe7\xa7\x01" // }
|
||||
"\xbc\x34\xd6\x86" // } Transaction ID
|
||||
"\xfa\x87\xdf\xae" // }
|
||||
|
||||
"\x80\x22\x00\x0b" // SOFTWARE, length=11
|
||||
"\x74\x65\x73\x74"
|
||||
"\x20\x76\x65\x63"
|
||||
"\x74\x6f\x72\x20"
|
||||
"\x00\x20\x00\x14" // XOR-MAPPED-ADDRESS
|
||||
"\x00\x02\xa1\x47"
|
||||
"\x01\x13\xa9\xfa"
|
||||
"\xa5\xd3\xf1\x79"
|
||||
"\xbc\x25\xf4\xb5"
|
||||
"\xbe\xd2\xb9\xd9"
|
||||
"\x00\x08\x00\x14" // MESSAGE-INTEGRITY attribute header
|
||||
"\xa3\x82\x95\x4e" // }
|
||||
"\x4b\xe6\x7b\xf1" // }
|
||||
"\x17\x84\xc9\x7c" // } HMAC-SHA1 fingerprint
|
||||
"\x82\x92\xc2\x75" // }
|
||||
"\xbf\xe3\xed\x41" // }
|
||||
"\x80\x28\x00\x04" // FINGERPRINT attribute header
|
||||
"\xc8\xfb\x0b\x4c" // CRC32 fingerprint
|
||||
,
|
||||
92,
|
||||
USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
|
||||
"evtj:h6vY",
|
||||
"VOkJxbRl1RmTxUk/WvJxBt",
|
||||
"",
|
||||
"",
|
||||
&create_msgint3
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -537,7 +588,7 @@ static int fingerprint_test_vector()
|
|||
unsigned i;
|
||||
int rc = 0;
|
||||
|
||||
PJ_LOG(3,(THIS_FILE, " STUN message test vectors"));
|
||||
PJ_LOG(3,(THIS_FILE, " draft-denis-behave-rfc3489bis-test-vectors-02"));
|
||||
|
||||
pool = pj_pool_create(mem, "fingerprint", 1024, 1024, NULL);
|
||||
|
||||
|
@ -585,10 +636,12 @@ static int fingerprint_test_vector()
|
|||
|
||||
/* Encode message */
|
||||
if (v->options & USE_MESSAGE_INTEGRITY) {
|
||||
pj_str_t s1, s2;
|
||||
pj_str_t s1, s2, r;
|
||||
|
||||
pj_stun_create_key(pool, &key, NULL, pj_cstr(&s1, v->username),
|
||||
PJ_STUN_PASSWD_PLAIN, pj_cstr(&s2, v->password));
|
||||
pj_stun_create_key(pool, &key, pj_cstr(&r, v->realm),
|
||||
pj_cstr(&s1, v->username),
|
||||
PJ_STUN_PASSWD_PLAIN,
|
||||
pj_cstr(&s2, v->password));
|
||||
pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
|
||||
|
||||
} else {
|
||||
|
@ -625,8 +678,10 @@ static int fingerprint_test_vector()
|
|||
|
||||
pj_bzero(&cred, sizeof(cred));
|
||||
cred.type = PJ_STUN_AUTH_CRED_STATIC;
|
||||
cred.data.static_cred.realm = pj_str(v->realm);
|
||||
cred.data.static_cred.username = pj_str(v->username);
|
||||
cred.data.static_cred.data = pj_str(v->password);
|
||||
cred.data.static_cred.nonce = pj_str(v->nonce);
|
||||
|
||||
status = pj_stun_authenticate_request(buf, len, msg,
|
||||
&cred, pool, NULL, NULL);
|
||||
|
@ -699,7 +754,7 @@ static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v)
|
|||
pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
|
||||
pj_cstr(&s1, "test vector"));
|
||||
|
||||
pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "127.0.0.1"), 32853);
|
||||
pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "192.0.2.1"), 32853);
|
||||
pj_stun_msg_add_sockaddr_attr(pool, msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR,
|
||||
PJ_TRUE, &mapped_addr,
|
||||
sizeof(pj_sockaddr_in));
|
||||
|
@ -711,6 +766,33 @@ static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v)
|
|||
}
|
||||
|
||||
|
||||
static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v)
|
||||
{
|
||||
pj_stun_msg *msg;
|
||||
pj_sockaddr mapped_addr;
|
||||
pj_str_t s1;
|
||||
|
||||
pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
|
||||
(pj_uint8_t*)v->tsx_id, &msg);
|
||||
|
||||
pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
|
||||
pj_cstr(&s1, "test vector"));
|
||||
|
||||
pj_sockaddr_init(pj_AF_INET6(), &mapped_addr,
|
||||
pj_cstr(&s1, "2001:db8:1234:5678:11:2233:4455:6677"),
|
||||
32853);
|
||||
|
||||
pj_stun_msg_add_sockaddr_attr(pool, msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR,
|
||||
PJ_TRUE, &mapped_addr,
|
||||
sizeof(pj_sockaddr));
|
||||
|
||||
pj_stun_msg_add_msgint_attr(pool, msg);
|
||||
pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
/* Compare two messages */
|
||||
static int cmp_msg(const pj_stun_msg *msg1, const pj_stun_msg *msg2)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,7 @@ static const struct
|
|||
|
||||
PJ_BUILD_ERR( PJNATH_ESTUNNOMAPPEDADDR, "STUN (XOR-)MAPPED-ADDRESS attribute not found"),
|
||||
PJ_BUILD_ERR( PJNATH_ESTUNIPV6NOTSUPP, "STUN IPv6 attribute not supported"),
|
||||
PJ_BUILD_ERR( PJNATH_EINVAF, "Invalid STUN address family value"),
|
||||
PJ_BUILD_ERR( PJNATH_ESTUNINSERVER, "Invalid STUN server or server not configured"),
|
||||
|
||||
PJ_BUILD_ERR( PJNATH_ESTUNDESTROYED, "STUN object has been destoyed"),
|
||||
|
|
|
@ -88,69 +88,97 @@ struct attr_desc
|
|||
{
|
||||
const char *name;
|
||||
pj_status_t (*decode_attr)(pj_pool_t *pool, const pj_uint8_t *buf,
|
||||
void **p_attr);
|
||||
const pj_stun_msg_hdr *msghdr, void **p_attr);
|
||||
pj_status_t (*encode_attr)(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed);
|
||||
unsigned len, const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed);
|
||||
void* (*clone_attr)(pj_pool_t *pool, const void *src);
|
||||
};
|
||||
|
||||
static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
void **p_attr);
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr);
|
||||
static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr);
|
||||
static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len,
|
||||
unsigned *printed);
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed);
|
||||
static void* clone_sockaddr_attr(pj_pool_t *pool, const void *src);
|
||||
static pj_status_t decode_string_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr);
|
||||
static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed);
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed);
|
||||
static void* clone_string_attr(pj_pool_t *pool, const void *src);
|
||||
static pj_status_t decode_msgint_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr);
|
||||
static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed);
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed);
|
||||
static void* clone_msgint_attr(pj_pool_t *pool, const void *src);
|
||||
static pj_status_t decode_errcode_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr);
|
||||
static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed);
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed);
|
||||
static void* clone_errcode_attr(pj_pool_t *pool, const void *src);
|
||||
static pj_status_t decode_unknown_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr);
|
||||
static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed);
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed);
|
||||
static void* clone_unknown_attr(pj_pool_t *pool, const void *src);
|
||||
static pj_status_t decode_uint_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr);
|
||||
static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed);
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed);
|
||||
static void* clone_uint_attr(pj_pool_t *pool, const void *src);
|
||||
static pj_status_t decode_uint64_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr);
|
||||
static pj_status_t encode_uint64_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed);
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed);
|
||||
static void* clone_uint64_attr(pj_pool_t *pool, const void *src);
|
||||
static pj_status_t decode_binary_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr);
|
||||
static pj_status_t encode_binary_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed);
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed);
|
||||
static void* clone_binary_attr(pj_pool_t *pool, const void *src);
|
||||
static pj_status_t decode_empty_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr);
|
||||
static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed);
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed);
|
||||
static void* clone_empty_attr(pj_pool_t *pool, const void *src);
|
||||
|
||||
static struct attr_desc mandatory_attr_desc[] =
|
||||
|
@ -726,7 +754,7 @@ static pj_uint16_t GETVAL16H(const pj_uint8_t *buf, unsigned pos)
|
|||
(buf[pos + 1] << 0));
|
||||
}
|
||||
|
||||
static pj_uint16_t GETVAL16N(const pj_uint8_t *buf, unsigned pos)
|
||||
PJ_INLINE(pj_uint16_t) GETVAL16N(const pj_uint8_t *buf, unsigned pos)
|
||||
{
|
||||
return pj_htons(GETVAL16H(buf,pos));
|
||||
}
|
||||
|
@ -737,7 +765,7 @@ static void PUTVAL16H(pj_uint8_t *buf, unsigned pos, pj_uint16_t hval)
|
|||
buf[pos+1] = (pj_uint8_t) ((hval & 0x00FF) >> 0);
|
||||
}
|
||||
|
||||
static pj_uint32_t GETVAL32H(const pj_uint8_t *buf, unsigned pos)
|
||||
PJ_INLINE(pj_uint32_t) GETVAL32H(const pj_uint8_t *buf, unsigned pos)
|
||||
{
|
||||
return (pj_uint32_t) ((buf[pos + 0] << 24UL) | \
|
||||
(buf[pos + 1] << 16UL) | \
|
||||
|
@ -745,7 +773,7 @@ static pj_uint32_t GETVAL32H(const pj_uint8_t *buf, unsigned pos)
|
|||
(buf[pos + 3] << 0UL));
|
||||
}
|
||||
|
||||
static pj_uint32_t GETVAL32N(const pj_uint8_t *buf, unsigned pos)
|
||||
PJ_INLINE(pj_uint32_t) GETVAL32N(const pj_uint8_t *buf, unsigned pos)
|
||||
{
|
||||
return pj_htonl(GETVAL32H(buf,pos));
|
||||
}
|
||||
|
@ -781,7 +809,8 @@ static void GETATTRHDR(const pj_uint8_t *buf, pj_stun_attr_hdr *hdr)
|
|||
/*
|
||||
* STUN generic IP address container
|
||||
*/
|
||||
#define STUN_GENERIC_IP_ADDR_LEN 8
|
||||
#define STUN_GENERIC_IPV4_ADDR_LEN 8
|
||||
#define STUN_GENERIC_IPV6_ADDR_LEN 20
|
||||
|
||||
/*
|
||||
* Init sockaddr attr
|
||||
|
@ -792,11 +821,14 @@ PJ_DEF(pj_status_t) pj_stun_sockaddr_attr_init( pj_stun_sockaddr_attr *attr,
|
|||
const pj_sockaddr_t *addr,
|
||||
unsigned addr_len)
|
||||
{
|
||||
unsigned attr_len;
|
||||
|
||||
PJ_ASSERT_RETURN(attr && addr_len && addr, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(addr_len == sizeof(pj_sockaddr_in) ||
|
||||
addr_len == sizeof(pj_sockaddr_in6), PJ_EINVAL);
|
||||
|
||||
INIT_ATTR(attr, attr_type, STUN_GENERIC_IP_ADDR_LEN);
|
||||
attr_len = pj_sockaddr_get_addr_len(addr) + 4;
|
||||
INIT_ATTR(attr, attr_type, attr_len);
|
||||
|
||||
pj_memcpy(&attr->sockaddr, addr, addr_len);
|
||||
attr->xor_ed = xor_ed;
|
||||
|
@ -848,32 +880,55 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_sockaddr_attr(pj_pool_t *pool,
|
|||
|
||||
static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr)
|
||||
{
|
||||
pj_stun_sockaddr_attr *attr;
|
||||
int af;
|
||||
unsigned addr_len;
|
||||
pj_uint32_t val;
|
||||
|
||||
PJ_CHECK_STACK();
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
/* Create the attribute */
|
||||
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
|
||||
GETATTRHDR(buf, &attr->hdr);
|
||||
|
||||
/* Check that the attribute length is valid */
|
||||
if (attr->hdr.length != STUN_GENERIC_IP_ADDR_LEN)
|
||||
if (attr->hdr.length != STUN_GENERIC_IPV4_ADDR_LEN &&
|
||||
attr->hdr.length != STUN_GENERIC_IPV6_ADDR_LEN)
|
||||
{
|
||||
return PJNATH_ESTUNINATTRLEN;
|
||||
}
|
||||
|
||||
/* Check address family */
|
||||
val = *(pj_uint8_t*)(buf + ATTR_HDR_LEN + 1);
|
||||
|
||||
/* Check address family is valid (only supports ipv4 for now) */
|
||||
if (val != 1)
|
||||
return PJNATH_ESTUNIPV6NOTSUPP;
|
||||
/* Check address family is valid */
|
||||
if (val == 1) {
|
||||
if (attr->hdr.length != STUN_GENERIC_IPV4_ADDR_LEN)
|
||||
return PJNATH_ESTUNINATTRLEN;
|
||||
af = pj_AF_INET();
|
||||
addr_len = 4;
|
||||
} else if (val == 2) {
|
||||
if (attr->hdr.length != STUN_GENERIC_IPV6_ADDR_LEN)
|
||||
return PJNATH_ESTUNINATTRLEN;
|
||||
af = pj_AF_INET6();
|
||||
addr_len = 16;
|
||||
} else {
|
||||
/* Invalid address family */
|
||||
return PJNATH_EINVAF;
|
||||
}
|
||||
|
||||
/* Get port and address */
|
||||
pj_sockaddr_in_init(&attr->sockaddr.ipv4, NULL, 0);
|
||||
attr->sockaddr.ipv4.sin_port = GETVAL16N(buf, ATTR_HDR_LEN+2);
|
||||
attr->sockaddr.ipv4.sin_addr.s_addr = GETVAL32N(buf, ATTR_HDR_LEN+4);
|
||||
pj_sockaddr_init(af, &attr->sockaddr, NULL, 0);
|
||||
pj_sockaddr_set_port(&attr->sockaddr,
|
||||
GETVAL16H(buf, ATTR_HDR_LEN+2));
|
||||
pj_memcpy(pj_sockaddr_get_addr(&attr->sockaddr),
|
||||
buf+ATTR_HDR_LEN+4,
|
||||
addr_len);
|
||||
|
||||
/* Done */
|
||||
*p_attr = (void*)attr;
|
||||
|
@ -884,20 +939,47 @@ static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
|
|||
|
||||
static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr)
|
||||
{
|
||||
pj_stun_sockaddr_attr *attr;
|
||||
pj_status_t status;
|
||||
|
||||
status = decode_sockaddr_attr(pool, buf, p_attr);
|
||||
status = decode_sockaddr_attr(pool, buf, msghdr, p_attr);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
attr = *(pj_stun_sockaddr_attr**)p_attr;
|
||||
|
||||
attr->xor_ed = PJ_TRUE;
|
||||
attr->sockaddr.ipv4.sin_port ^= pj_htons(0x2112);
|
||||
attr->sockaddr.ipv4.sin_addr.s_addr ^= pj_htonl(0x2112A442);
|
||||
|
||||
if (attr->sockaddr.addr.sa_family == pj_AF_INET()) {
|
||||
attr->sockaddr.ipv4.sin_port ^= pj_htons(PJ_STUN_MAGIC >> 16);
|
||||
attr->sockaddr.ipv4.sin_addr.s_addr ^= pj_htonl(PJ_STUN_MAGIC);
|
||||
} else if (attr->sockaddr.addr.sa_family == pj_AF_INET6()) {
|
||||
unsigned i;
|
||||
pj_uint8_t *dst = (pj_uint8_t*) &attr->sockaddr.ipv6.sin6_addr;
|
||||
pj_uint32_t magic = pj_htonl(PJ_STUN_MAGIC);
|
||||
|
||||
attr->sockaddr.ipv6.sin6_port ^= pj_htons(PJ_STUN_MAGIC >> 16);
|
||||
|
||||
/* If the IP address family is IPv6, X-Address is computed by
|
||||
* taking the mapped IP address in host byte order, XOR'ing it
|
||||
* with the concatenation of the magic cookie and the 96-bit
|
||||
* transaction ID, and converting the result to network byte
|
||||
* order.
|
||||
*/
|
||||
for (i=0; i<4; ++i) {
|
||||
dst[i] ^= ((const pj_uint8_t*)&magic)[i];
|
||||
}
|
||||
pj_assert(sizeof(msghdr->tsx_id[0]) == 1);
|
||||
for (i=0; i<12; ++i) {
|
||||
dst[i+4] ^= msghdr->tsx_id[i];
|
||||
}
|
||||
|
||||
} else {
|
||||
return PJNATH_EINVAF;
|
||||
}
|
||||
|
||||
/* Done */
|
||||
*p_attr = attr;
|
||||
|
@ -907,62 +989,129 @@ static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
|
|||
|
||||
|
||||
static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed)
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed)
|
||||
{
|
||||
enum {
|
||||
ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IP_ADDR_LEN
|
||||
};
|
||||
pj_uint8_t *start_buf = buf;
|
||||
const pj_stun_sockaddr_attr *ca =
|
||||
(const pj_stun_sockaddr_attr *)a;
|
||||
|
||||
if (len < ATTR_LEN)
|
||||
return PJ_ETOOSMALL;
|
||||
|
||||
PJ_CHECK_STACK();
|
||||
|
||||
/* Copy and convert headers to network byte order */
|
||||
/* Common: attribute type */
|
||||
PUTVAL16H(buf, 0, ca->hdr.type);
|
||||
PUTVAL16H(buf, 2, STUN_GENERIC_IP_ADDR_LEN);
|
||||
buf += ATTR_HDR_LEN;
|
||||
|
||||
if (ca->sockaddr.addr.sa_family == pj_AF_INET()) {
|
||||
enum {
|
||||
ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IPV4_ADDR_LEN
|
||||
};
|
||||
|
||||
if (len < ATTR_LEN)
|
||||
return PJ_ETOOSMALL;
|
||||
|
||||
/* attribute len */
|
||||
PUTVAL16H(buf, 2, STUN_GENERIC_IPV4_ADDR_LEN);
|
||||
buf += ATTR_HDR_LEN;
|
||||
|
||||
/* Ignored */
|
||||
*buf++ = '\0';
|
||||
/* Ignored */
|
||||
*buf++ = '\0';
|
||||
|
||||
/* Family (IPv4 only for now) */
|
||||
PJ_ASSERT_RETURN(ca->sockaddr.addr.sa_family == pj_AF_INET(), PJ_EINVAL);
|
||||
*buf++ = 1;
|
||||
/* Address family, 1 for IPv4 */
|
||||
*buf++ = 1;
|
||||
|
||||
if (ca->xor_ed) {
|
||||
pj_uint32_t addr;
|
||||
pj_uint16_t port;
|
||||
/* IPv4 address */
|
||||
if (ca->xor_ed) {
|
||||
pj_uint32_t addr;
|
||||
pj_uint16_t port;
|
||||
|
||||
addr = ca->sockaddr.ipv4.sin_addr.s_addr;
|
||||
port = ca->sockaddr.ipv4.sin_port;
|
||||
addr = ca->sockaddr.ipv4.sin_addr.s_addr;
|
||||
port = ca->sockaddr.ipv4.sin_port;
|
||||
|
||||
port ^= pj_htons(0x2112);
|
||||
addr ^= pj_htonl(0x2112A442);
|
||||
port ^= pj_htons(PJ_STUN_MAGIC >> 16);
|
||||
addr ^= pj_htonl(PJ_STUN_MAGIC);
|
||||
|
||||
/* Port */
|
||||
pj_memcpy(buf, &port, 2);
|
||||
buf += 2;
|
||||
/* Port */
|
||||
pj_memcpy(buf, &port, 2);
|
||||
buf += 2;
|
||||
|
||||
/* Address */
|
||||
pj_memcpy(buf, &addr, 4);
|
||||
buf += 4;
|
||||
/* Address */
|
||||
pj_memcpy(buf, &addr, 4);
|
||||
buf += 4;
|
||||
|
||||
} else {
|
||||
/* Port */
|
||||
pj_memcpy(buf, &ca->sockaddr.ipv4.sin_port, 2);
|
||||
buf += 2;
|
||||
|
||||
/* Address */
|
||||
pj_memcpy(buf, &ca->sockaddr.ipv4.sin_addr, 4);
|
||||
buf += 4;
|
||||
}
|
||||
|
||||
pj_assert(buf - start_buf == ATTR_LEN);
|
||||
|
||||
} else if (ca->sockaddr.addr.sa_family == pj_AF_INET6()) {
|
||||
/* IPv6 address */
|
||||
enum {
|
||||
ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IPV6_ADDR_LEN
|
||||
};
|
||||
|
||||
if (len < ATTR_LEN)
|
||||
return PJ_ETOOSMALL;
|
||||
|
||||
/* attribute len */
|
||||
PUTVAL16H(buf, 2, STUN_GENERIC_IPV6_ADDR_LEN);
|
||||
buf += ATTR_HDR_LEN;
|
||||
|
||||
/* Ignored */
|
||||
*buf++ = '\0';
|
||||
|
||||
/* Address family, 2 for IPv6 */
|
||||
*buf++ = 2;
|
||||
|
||||
/* IPv6 address */
|
||||
if (ca->xor_ed) {
|
||||
unsigned i;
|
||||
pj_uint8_t *dst;
|
||||
const pj_uint8_t *src;
|
||||
pj_uint32_t magic = pj_htonl(PJ_STUN_MAGIC);
|
||||
pj_uint16_t port = ca->sockaddr.ipv6.sin6_port;
|
||||
|
||||
/* Port */
|
||||
port ^= pj_htons(PJ_STUN_MAGIC >> 16);
|
||||
pj_memcpy(buf, &port, 2);
|
||||
buf += 2;
|
||||
|
||||
/* Address */
|
||||
dst = buf;
|
||||
src = (const pj_uint8_t*) &ca->sockaddr.ipv6.sin6_addr;
|
||||
for (i=0; i<4; ++i) {
|
||||
dst[i] = (pj_uint8_t)(src[i] ^ ((const pj_uint8_t*)&magic)[i]);
|
||||
}
|
||||
pj_assert(sizeof(msghdr->tsx_id[0]) == 1);
|
||||
for (i=0; i<12; ++i) {
|
||||
dst[i+4] = (pj_uint8_t)(src[i+4] ^ msghdr->tsx_id[i]);
|
||||
}
|
||||
|
||||
buf += 16;
|
||||
|
||||
} else {
|
||||
/* Port */
|
||||
pj_memcpy(buf, &ca->sockaddr.ipv6.sin6_port, 2);
|
||||
buf += 2;
|
||||
|
||||
/* Address */
|
||||
pj_memcpy(buf, &ca->sockaddr.ipv6.sin6_addr, 16);
|
||||
buf += 16;
|
||||
}
|
||||
|
||||
pj_assert(buf - start_buf == ATTR_LEN);
|
||||
|
||||
} else {
|
||||
/* Port */
|
||||
pj_memcpy(buf, &ca->sockaddr.ipv4.sin_port, 2);
|
||||
buf += 2;
|
||||
|
||||
/* Address */
|
||||
pj_memcpy(buf, &ca->sockaddr.ipv4.sin_addr, 4);
|
||||
buf += 4;
|
||||
return PJNATH_EINVAF;
|
||||
}
|
||||
|
||||
pj_assert(buf - start_buf == ATTR_LEN);
|
||||
|
||||
/* Done */
|
||||
*printed = buf - start_buf;
|
||||
|
||||
|
@ -1040,11 +1189,14 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_string_attr(pj_pool_t *pool,
|
|||
|
||||
static pj_status_t decode_string_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr)
|
||||
{
|
||||
pj_stun_string_attr *attr;
|
||||
pj_str_t value;
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
/* Create the attribute */
|
||||
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_string_attr);
|
||||
GETATTRHDR(buf, &attr->hdr);
|
||||
|
@ -1065,13 +1217,17 @@ static pj_status_t decode_string_attr(pj_pool_t *pool,
|
|||
|
||||
|
||||
static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed)
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed)
|
||||
{
|
||||
const pj_stun_string_attr *ca =
|
||||
(const pj_stun_string_attr*)a;
|
||||
|
||||
PJ_CHECK_STACK();
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
/* Calculated total attr_len (add padding if necessary) */
|
||||
*printed = (ca->value.slen + ATTR_HDR_LEN + 3) & (~3);
|
||||
if (len < *printed) {
|
||||
|
@ -1154,10 +1310,13 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_empty_attr( pj_pool_t *pool,
|
|||
|
||||
static pj_status_t decode_empty_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr)
|
||||
{
|
||||
pj_stun_empty_attr *attr;
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
/* Check that the struct address is valid */
|
||||
pj_assert(sizeof(pj_stun_empty_attr) == ATTR_HDR_LEN);
|
||||
|
||||
|
@ -1177,10 +1336,14 @@ static pj_status_t decode_empty_attr(pj_pool_t *pool,
|
|||
|
||||
|
||||
static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed)
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed)
|
||||
{
|
||||
const pj_stun_empty_attr *ca = (pj_stun_empty_attr*)a;
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
if (len < ATTR_HDR_LEN)
|
||||
return PJ_ETOOSMALL;
|
||||
|
||||
|
@ -1247,10 +1410,13 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_uint_attr(pj_pool_t *pool,
|
|||
|
||||
static pj_status_t decode_uint_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr)
|
||||
{
|
||||
pj_stun_uint_attr *attr;
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
/* Create the attribute */
|
||||
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint_attr);
|
||||
GETATTRHDR(buf, &attr->hdr);
|
||||
|
@ -1269,11 +1435,15 @@ static pj_status_t decode_uint_attr(pj_pool_t *pool,
|
|||
|
||||
|
||||
static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed)
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed)
|
||||
{
|
||||
const pj_stun_uint_attr *ca = (const pj_stun_uint_attr*)a;
|
||||
|
||||
PJ_CHECK_STACK();
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
if (len < 8)
|
||||
return PJ_ETOOSMALL;
|
||||
|
@ -1343,10 +1513,13 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_uint64_attr(pj_pool_t *pool,
|
|||
|
||||
static pj_status_t decode_uint64_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr)
|
||||
{
|
||||
pj_stun_uint64_attr *attr;
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
/* Create the attribute */
|
||||
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint64_attr);
|
||||
GETATTRHDR(buf, &attr->hdr);
|
||||
|
@ -1364,11 +1537,15 @@ static pj_status_t decode_uint64_attr(pj_pool_t *pool,
|
|||
|
||||
|
||||
static pj_status_t encode_uint64_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed)
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed)
|
||||
{
|
||||
const pj_stun_uint64_attr *ca = (const pj_stun_uint64_attr*)a;
|
||||
|
||||
PJ_CHECK_STACK();
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
if (len < 12)
|
||||
return PJ_ETOOSMALL;
|
||||
|
@ -1433,10 +1610,13 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_msgint_attr(pj_pool_t *pool,
|
|||
|
||||
static pj_status_t decode_msgint_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr)
|
||||
{
|
||||
pj_stun_msgint_attr *attr;
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
/* Create attribute */
|
||||
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_msgint_attr);
|
||||
GETATTRHDR(buf, &attr->hdr);
|
||||
|
@ -1455,12 +1635,16 @@ static pj_status_t decode_msgint_attr(pj_pool_t *pool,
|
|||
|
||||
|
||||
static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed)
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed)
|
||||
{
|
||||
const pj_stun_msgint_attr *ca = (const pj_stun_msgint_attr*)a;
|
||||
|
||||
PJ_CHECK_STACK();
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
if (len < 24)
|
||||
return PJ_ETOOSMALL;
|
||||
|
||||
|
@ -1544,11 +1728,14 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_errcode_attr(pj_pool_t *pool,
|
|||
|
||||
static pj_status_t decode_errcode_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr)
|
||||
{
|
||||
pj_stun_errcode_attr *attr;
|
||||
pj_str_t value;
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
/* Create the attribute */
|
||||
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_errcode_attr);
|
||||
GETATTRHDR(buf, &attr->hdr);
|
||||
|
@ -1570,13 +1757,17 @@ static pj_status_t decode_errcode_attr(pj_pool_t *pool,
|
|||
|
||||
|
||||
static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed)
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed)
|
||||
{
|
||||
const pj_stun_errcode_attr *ca =
|
||||
(const pj_stun_errcode_attr*)a;
|
||||
|
||||
PJ_CHECK_STACK();
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
if (len < ATTR_HDR_LEN + 4 + (unsigned)ca->reason.slen)
|
||||
return PJ_ETOOSMALL;
|
||||
|
||||
|
@ -1672,12 +1863,15 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_unknown_attr(pj_pool_t *pool,
|
|||
|
||||
static pj_status_t decode_unknown_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr)
|
||||
{
|
||||
pj_stun_unknown_attr *attr;
|
||||
const pj_uint16_t *punk_attr;
|
||||
unsigned i;
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_unknown_attr);
|
||||
GETATTRHDR(buf, &attr->hdr);
|
||||
|
||||
|
@ -1698,7 +1892,9 @@ static pj_status_t decode_unknown_attr(pj_pool_t *pool,
|
|||
|
||||
|
||||
static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed)
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed)
|
||||
{
|
||||
const pj_stun_unknown_attr *ca = (const pj_stun_unknown_attr*) a;
|
||||
pj_uint16_t *dst_unk_attr;
|
||||
|
@ -1706,6 +1902,8 @@ static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
|
|||
|
||||
PJ_CHECK_STACK();
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
/* Check that buffer is enough */
|
||||
if (len < ATTR_HDR_LEN + (ca->attr_count << 1))
|
||||
return PJ_ETOOSMALL;
|
||||
|
@ -1807,10 +2005,13 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_binary_attr(pj_pool_t *pool,
|
|||
|
||||
static pj_status_t decode_binary_attr(pj_pool_t *pool,
|
||||
const pj_uint8_t *buf,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
void **p_attr)
|
||||
{
|
||||
pj_stun_binary_attr *attr;
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
/* Create the attribute */
|
||||
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_binary_attr);
|
||||
GETATTRHDR(buf, &attr->hdr);
|
||||
|
@ -1829,12 +2030,16 @@ static pj_status_t decode_binary_attr(pj_pool_t *pool,
|
|||
|
||||
|
||||
static pj_status_t encode_binary_attr(const void *a, pj_uint8_t *buf,
|
||||
unsigned len, unsigned *printed)
|
||||
unsigned len,
|
||||
const pj_stun_msg_hdr *msghdr,
|
||||
unsigned *printed)
|
||||
{
|
||||
const pj_stun_binary_attr *ca = (const pj_stun_binary_attr*)a;
|
||||
|
||||
PJ_CHECK_STACK();
|
||||
|
||||
PJ_UNUSED_ARG(msghdr);
|
||||
|
||||
/* Calculated total attr_len (add padding if necessary) */
|
||||
*printed = (ca->length + ATTR_HDR_LEN + 3) & (~3);
|
||||
if (len < *printed)
|
||||
|
@ -2220,7 +2425,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
|
|||
err_msg2[PJ_ERR_MSG_SIZE];
|
||||
|
||||
/* Parse the attribute */
|
||||
status = (adesc->decode_attr)(pool, pdu, &attr);
|
||||
status = (adesc->decode_attr)(pool, pdu, &msg->hdr, &attr);
|
||||
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_strerror(status, err_msg1, sizeof(err_msg1));
|
||||
|
@ -2408,13 +2613,15 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
|
|||
|
||||
adesc = find_attr_desc(attr_hdr->type);
|
||||
if (adesc) {
|
||||
status = adesc->encode_attr(attr_hdr, buf, buf_size, &printed);
|
||||
status = adesc->encode_attr(attr_hdr, buf, buf_size, &msg->hdr,
|
||||
&printed);
|
||||
} else {
|
||||
/* This may be a generic attribute */
|
||||
const pj_stun_binary_attr *bin_attr = (const pj_stun_binary_attr*)
|
||||
attr_hdr;
|
||||
PJ_ASSERT_RETURN(bin_attr->magic == PJ_STUN_MAGIC, PJ_EBUG);
|
||||
status = encode_binary_attr(bin_attr, buf, buf_size, &printed);
|
||||
status = encode_binary_attr(bin_attr, buf, buf_size, &msg->hdr,
|
||||
&printed);
|
||||
}
|
||||
|
||||
if (status != PJ_SUCCESS)
|
||||
|
@ -2519,7 +2726,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
|
|||
|
||||
/* Put this attribute in the message */
|
||||
status = encode_msgint_attr(amsgint, buf, buf_size,
|
||||
&printed);
|
||||
&msg->hdr, &printed);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
|
@ -2541,7 +2748,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
|
|||
|
||||
/* Put this attribute in the message */
|
||||
status = encode_uint_attr(afingerprint, buf, buf_size,
|
||||
&printed);
|
||||
&msg->hdr, &printed);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
|
|
Loading…
Reference in New Issue