michael@0: /* michael@0: Copyright (c) 2007, Adobe Systems, Incorporated michael@0: All rights reserved. michael@0: michael@0: Redistribution and use in source and binary forms, with or without michael@0: modification, are permitted provided that the following conditions are michael@0: met: michael@0: michael@0: * Redistributions of source code must retain the above copyright michael@0: notice, this list of conditions and the following disclaimer. michael@0: michael@0: * Redistributions in binary form must reproduce the above copyright michael@0: notice, this list of conditions and the following disclaimer in the michael@0: documentation and/or other materials provided with the distribution. michael@0: michael@0: * Neither the name of Adobe Systems, Network Resonance nor the names of its michael@0: contributors may be used to endorse or promote products derived from michael@0: this software without specific prior written permission. michael@0: michael@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: michael@0: michael@0: static char *RCSSTRING __UNUSED__="$Id: stun_msg.c,v 1.2 2008/04/28 18:21:30 ekr Exp $"; michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #ifdef WIN32 michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #else /* UNIX */ michael@0: #include michael@0: #endif /* end UNIX */ michael@0: #include michael@0: michael@0: #include "stun.h" michael@0: michael@0: michael@0: int michael@0: nr_stun_message_create(nr_stun_message **msg) michael@0: { michael@0: int _status; michael@0: nr_stun_message *m = 0; michael@0: michael@0: m = RCALLOC(sizeof(*m)); michael@0: if (!m) michael@0: ABORT(R_NO_MEMORY); michael@0: michael@0: TAILQ_INIT(&m->attributes); michael@0: michael@0: *msg = m; michael@0: michael@0: _status=0; michael@0: abort: michael@0: return(_status); michael@0: } michael@0: michael@0: int michael@0: nr_stun_message_create2(nr_stun_message **msg, UCHAR *buffer, int length) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *m = 0; michael@0: michael@0: if (length > sizeof(m->buffer)) { michael@0: ABORT(R_BAD_DATA); michael@0: } michael@0: michael@0: if ((r=nr_stun_message_create(&m))) michael@0: ABORT(r); michael@0: michael@0: memcpy(m->buffer, buffer, length); michael@0: m->length = length; michael@0: michael@0: *msg = m; michael@0: michael@0: _status=0; michael@0: abort: michael@0: return(_status); michael@0: } michael@0: michael@0: int michael@0: nr_stun_message_destroy(nr_stun_message **msg) michael@0: { michael@0: int _status; michael@0: nr_stun_message_attribute_head *attrs; michael@0: nr_stun_message_attribute *attr; michael@0: michael@0: if (msg && *msg) { michael@0: attrs = &(*msg)->attributes; michael@0: while (!TAILQ_EMPTY(attrs)) { michael@0: attr = TAILQ_FIRST(attrs); michael@0: nr_stun_message_attribute_destroy(*msg, &attr); michael@0: } michael@0: michael@0: RFREE(*msg); michael@0: michael@0: *msg = 0; michael@0: } michael@0: michael@0: _status=0; michael@0: /* abort: */ michael@0: return(_status); michael@0: } michael@0: michael@0: int michael@0: nr_stun_message_attribute_create(nr_stun_message *msg, nr_stun_message_attribute **attr) michael@0: { michael@0: int _status; michael@0: nr_stun_message_attribute *a = 0; michael@0: michael@0: a = RCALLOC(sizeof(*a)); michael@0: if (!a) michael@0: ABORT(R_NO_MEMORY); michael@0: michael@0: TAILQ_INSERT_TAIL(&msg->attributes, a, entry); michael@0: michael@0: *attr = a; michael@0: michael@0: _status=0; michael@0: abort: michael@0: return(_status); michael@0: } michael@0: michael@0: int michael@0: nr_stun_message_attribute_destroy(nr_stun_message *msg, nr_stun_message_attribute **attr) michael@0: { michael@0: int _status; michael@0: nr_stun_message_attribute *a = 0; michael@0: michael@0: if (attr && *attr) { michael@0: a = *attr; michael@0: TAILQ_REMOVE(&msg->attributes, a, entry); michael@0: michael@0: RFREE(a); michael@0: michael@0: *attr = 0; michael@0: } michael@0: michael@0: _status=0; michael@0: /* abort: */ michael@0: return(_status); michael@0: } michael@0: michael@0: int michael@0: nr_stun_message_has_attribute(nr_stun_message *msg, UINT2 type, nr_stun_message_attribute **attribute) michael@0: { michael@0: nr_stun_message_attribute *attr = 0; michael@0: michael@0: if (attribute) michael@0: *attribute = 0; michael@0: michael@0: TAILQ_FOREACH(attr, &msg->attributes, entry) { michael@0: if (attr->type == type) michael@0: break; michael@0: } michael@0: michael@0: if (!attr || attr->invalid) michael@0: return 0; /* does not have */ michael@0: michael@0: if (attribute) michael@0: *attribute = attr; michael@0: michael@0: return 1; /* has */ michael@0: } michael@0: michael@0: #define NR_STUN_MESSAGE_ADD_ATTRIBUTE(__type, __code) \ michael@0: { \ michael@0: int r,_status; \ michael@0: nr_stun_message_attribute *attr = 0; \ michael@0: if ((r=nr_stun_message_attribute_create(msg, &attr))) \ michael@0: ABORT(r); \ michael@0: attr->type = (__type); \ michael@0: { __code } \ michael@0: _status=0; \ michael@0: abort: \ michael@0: if (_status) RFREE(attr); \ michael@0: return(_status); \ michael@0: } michael@0: michael@0: michael@0: int michael@0: nr_stun_message_add_alternate_server_attribute(nr_stun_message *msg, nr_transport_addr *alternate_server) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_ALTERNATE_SERVER, michael@0: { michael@0: if ((r=nr_transport_addr_copy(&attr->u.alternate_server, alternate_server))) michael@0: ABORT(r); michael@0: } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_error_code_attribute(nr_stun_message *msg, UINT2 number, char *reason) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_ERROR_CODE, michael@0: { michael@0: attr->u.error_code.number = number; michael@0: strlcpy(attr->u.error_code.reason, reason, sizeof(attr->u.error_code.reason)); michael@0: } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_fingerprint_attribute(nr_stun_message *msg) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_FINGERPRINT, michael@0: {} michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_message_integrity_attribute(nr_stun_message *msg, Data *password) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_MESSAGE_INTEGRITY, michael@0: { michael@0: if (sizeof(attr->u.message_integrity.password) < password->len) michael@0: ABORT(R_BAD_DATA); michael@0: michael@0: memcpy(attr->u.message_integrity.password, password->data, password->len); michael@0: attr->u.message_integrity.passwordlen = password->len; michael@0: } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_nonce_attribute(nr_stun_message *msg, char *nonce) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_NONCE, michael@0: { strlcpy(attr->u.nonce, nonce, sizeof(attr->u.nonce)); } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_realm_attribute(nr_stun_message *msg, char *realm) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_REALM, michael@0: { strlcpy(attr->u.realm, realm, sizeof(attr->u.realm)); } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_server_attribute(nr_stun_message *msg, char *server_name) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_SERVER, michael@0: { strlcpy(attr->u.server_name, server_name, sizeof(attr->u.server_name)); } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_unknown_attributes_attribute(nr_stun_message *msg, nr_stun_attr_unknown_attributes *unknown_attributes) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_UNKNOWN_ATTRIBUTES, michael@0: { memcpy(&attr->u.unknown_attributes, unknown_attributes, sizeof(attr->u.unknown_attributes)); } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_username_attribute(nr_stun_message *msg, char *username) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_USERNAME, michael@0: { strlcpy(attr->u.username, username, sizeof(attr->u.username)); } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_requested_transport_attribute(nr_stun_message *msg, UCHAR protocol) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_REQUESTED_TRANSPORT, michael@0: { attr->u.requested_transport = protocol; } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_xor_mapped_address_attribute(nr_stun_message *msg, nr_transport_addr *mapped_address) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_XOR_MAPPED_ADDRESS, michael@0: { michael@0: if ((r=nr_transport_addr_copy(&attr->u.xor_mapped_address.unmasked, mapped_address))) michael@0: ABORT(r); michael@0: } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_xor_peer_address_attribute(nr_stun_message *msg, nr_transport_addr *peer_address) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_XOR_PEER_ADDRESS, michael@0: { michael@0: if ((r=nr_transport_addr_copy(&attr->u.xor_mapped_address.unmasked, peer_address))) michael@0: ABORT(r); michael@0: } michael@0: ) michael@0: michael@0: #ifdef USE_ICE michael@0: int michael@0: nr_stun_message_add_ice_controlled_attribute(nr_stun_message *msg, UINT8 ice_controlled) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_ICE_CONTROLLED, michael@0: { attr->u.ice_controlled = ice_controlled; } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_ice_controlling_attribute(nr_stun_message *msg, UINT8 ice_controlling) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_ICE_CONTROLLING, michael@0: { attr->u.ice_controlling = ice_controlling; } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_priority_attribute(nr_stun_message *msg, UINT4 priority) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_PRIORITY, michael@0: { attr->u.priority = priority; } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_use_candidate_attribute(nr_stun_message *msg) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_USE_CANDIDATE, michael@0: {} michael@0: ) michael@0: #endif /* USE_ICE */ michael@0: michael@0: #ifdef USE_TURN michael@0: int michael@0: nr_stun_message_add_data_attribute(nr_stun_message *msg, UCHAR *data, int length) michael@0: michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_DATA, michael@0: { michael@0: if (length > NR_STUN_MAX_MESSAGE_SIZE) michael@0: ABORT(R_BAD_ARGS); michael@0: michael@0: memcpy(attr->u.data.data, data, length); michael@0: attr->u.data.length=length; michael@0: } michael@0: ) michael@0: michael@0: int michael@0: nr_stun_message_add_lifetime_attribute(nr_stun_message *msg, UINT4 lifetime_secs) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_LIFETIME, michael@0: { attr->u.lifetime_secs = lifetime_secs; } michael@0: ) michael@0: michael@0: #endif /* USE_TURN */ michael@0: michael@0: #ifdef USE_STUND_0_96 michael@0: int michael@0: nr_stun_message_add_change_request_attribute(nr_stun_message *msg, UINT4 change_request) michael@0: NR_STUN_MESSAGE_ADD_ATTRIBUTE( michael@0: NR_STUN_ATTR_OLD_CHANGE_REQUEST, michael@0: { attr->u.change_request = change_request; } michael@0: ) michael@0: #endif /* USE_STUND_0_96 */ michael@0: