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_build.c,v 1.2 2008/04/28 18:21:30 ekr Exp $"; michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "nr_api.h" michael@0: #include "stun.h" michael@0: #include "registry.h" michael@0: #include "stun_reg.h" michael@0: #include "nr_crypto.h" michael@0: michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 7.1 */ michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 10.1.1 */ michael@0: /* note that S 10.1.1 states the message MUST include MESSAGE-INTEGRITY michael@0: * and USERNAME, but that's not correct -- for instance ICE keepalive michael@0: * messages don't include these (See draft-ietf-mmusic-ice-18.txt S 10: michael@0: * "If STUN is being used for keepalives, a STUN Binding Indication is michael@0: * used. The Indication MUST NOT utilize any authentication mechanism") michael@0: */ michael@0: int michael@0: nr_stun_form_request_or_indication(int mode, int msg_type, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *req = 0; michael@0: michael@0: assert(NR_STUN_GET_TYPE_CLASS(msg_type) == NR_CLASS_REQUEST michael@0: || NR_STUN_GET_TYPE_CLASS(msg_type) == NR_CLASS_INDICATION); michael@0: michael@0: *msg = 0; michael@0: michael@0: if ((r=nr_stun_message_create(&req))) michael@0: ABORT(r); michael@0: michael@0: req->header.type = msg_type; michael@0: michael@0: nr_crypto_random_bytes((UCHAR*)&req->header.id,sizeof(req->header.id)); michael@0: michael@0: switch (mode) { michael@0: default: michael@0: req->header.magic_cookie = NR_STUN_MAGIC_COOKIE; michael@0: michael@0: if ((r=nr_stun_message_add_fingerprint_attribute(req))) michael@0: ABORT(r); michael@0: michael@0: break; michael@0: michael@0: #ifdef USE_STUND_0_96 michael@0: case NR_STUN_MODE_STUND_0_96: michael@0: req->header.magic_cookie = NR_STUN_MAGIC_COOKIE2; michael@0: michael@0: /* actually, stund 0.96 just ignores the fingerprint michael@0: * attribute, but don't bother to send it */ michael@0: michael@0: break; michael@0: #endif /* USE_STUND_0_96 */ michael@0: michael@0: } michael@0: michael@0: *msg = req; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) RFREE(req); michael@0: return _status; michael@0: } michael@0: michael@0: int michael@0: nr_stun_build_req_lt_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *req = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_username_attribute(req, params->username))) michael@0: ABORT(r); michael@0: michael@0: if (params->realm && params->nonce) { michael@0: if ((r=nr_stun_message_add_realm_attribute(req, params->realm))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_nonce_attribute(req, params->nonce))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_message_integrity_attribute(req, params->password))) michael@0: ABORT(r); michael@0: } michael@0: michael@0: *msg = req; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&req); michael@0: return _status; michael@0: } michael@0: michael@0: int michael@0: nr_stun_build_req_st_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *req = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_username_attribute(req, params->username))) michael@0: ABORT(r); michael@0: michael@0: if (params->password) { michael@0: if ((r=nr_stun_message_add_message_integrity_attribute(req, params->password))) michael@0: ABORT(r); michael@0: } michael@0: michael@0: *msg = req; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&req); michael@0: return _status; michael@0: } michael@0: michael@0: int michael@0: nr_stun_build_req_no_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *req = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req))) michael@0: ABORT(r); michael@0: michael@0: *msg = req; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&req); michael@0: return _status; michael@0: } michael@0: michael@0: int michael@0: nr_stun_build_keepalive(nr_stun_client_stun_keepalive_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *ind = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_INDICATION, &ind))) michael@0: ABORT(r); michael@0: michael@0: *msg = ind; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&ind); michael@0: return _status; michael@0: } michael@0: michael@0: #ifdef USE_STUND_0_96 michael@0: int michael@0: nr_stun_build_req_stund_0_96(nr_stun_client_stun_binding_request_stund_0_96_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *req = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUND_0_96, NR_STUN_MSG_BINDING_REQUEST, &req))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_change_request_attribute(req, 0))) michael@0: ABORT(r); michael@0: michael@0: assert(! nr_stun_message_has_attribute(req, NR_STUN_ATTR_USERNAME, 0)); michael@0: assert(! nr_stun_message_has_attribute(req, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)); michael@0: michael@0: *msg = req; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&req); michael@0: return _status; michael@0: } michael@0: #endif /* USE_STUND_0_96 */ michael@0: michael@0: #ifdef USE_ICE michael@0: int michael@0: nr_stun_build_use_candidate(nr_stun_client_ice_use_candidate_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *req = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_username_attribute(req, params->username))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_message_integrity_attribute(req, ¶ms->password))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_use_candidate_attribute(req))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_priority_attribute(req, params->priority))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_ice_controlling_attribute(req, params->tiebreaker))) michael@0: ABORT(r); michael@0: michael@0: *msg = req; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&req); michael@0: return _status; michael@0: } michael@0: michael@0: int michael@0: nr_stun_build_req_ice(nr_stun_client_ice_binding_request_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *req = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_username_attribute(req, params->username))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_message_integrity_attribute(req, ¶ms->password))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_priority_attribute(req, params->priority))) michael@0: ABORT(r); michael@0: michael@0: switch (params->control) { michael@0: case NR_ICE_CONTROLLING: michael@0: if ((r=nr_stun_message_add_ice_controlling_attribute(req, params->tiebreaker))) michael@0: ABORT(r); michael@0: break; michael@0: case NR_ICE_CONTROLLED: michael@0: if ((r=nr_stun_message_add_ice_controlled_attribute(req, params->tiebreaker))) michael@0: ABORT(r); michael@0: break; michael@0: default: michael@0: assert(0); michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: michael@0: *msg = req; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&req); michael@0: return _status; michael@0: } michael@0: #endif /* USE_ICE */ michael@0: michael@0: #ifdef USE_TURN michael@0: michael@0: #ifndef __isascii michael@0: #define __isascii(c) (((c) & ~0x7F) == 0) michael@0: #endif michael@0: michael@0: /* Long-term passwords are computed over the key: michael@0: michael@0: key = MD5(username ":" realm ":" SASLprep(password)) michael@0: michael@0: Per RFC 5389 S 15.4 michael@0: */ michael@0: int michael@0: nr_stun_compute_lt_message_integrity_password(const char *username, const char *realm, michael@0: Data *password, Data *hmac_key) michael@0: { michael@0: char digest_input[1000]; michael@0: int i; michael@0: int r, _status; michael@0: size_t len; michael@0: michael@0: /* First check that the password is ASCII. We are supposed to michael@0: SASLprep but we don't support this yet michael@0: TODO(ekr@rtfm.com): Add SASLprep for password. michael@0: */ michael@0: for (i=0; ilen; i++) { michael@0: if (!__isascii(password->data[i])) michael@0: ABORT(R_BAD_DATA); michael@0: } michael@0: michael@0: if (hmac_key->len < 16) michael@0: ABORT(R_BAD_ARGS); michael@0: michael@0: snprintf(digest_input, sizeof(digest_input), "%s:%s:", username, realm); michael@0: if ((sizeof(digest_input) - strlen(digest_input)) < password->len) michael@0: ABORT(R_BAD_DATA); michael@0: michael@0: len = strlen(digest_input); michael@0: memcpy(digest_input + len, password->data, password->len); michael@0: michael@0: michael@0: if (r=nr_crypto_md5((UCHAR *)digest_input, len + password->len, hmac_key->data)) michael@0: ABORT(r); michael@0: hmac_key->len=16; michael@0: michael@0: _status=0; michael@0: abort: michael@0: return(_status); michael@0: } michael@0: michael@0: static int michael@0: nr_stun_build_auth_params(nr_stun_client_auth_params *auth, nr_stun_message *req) michael@0: { michael@0: int r, _status; michael@0: UCHAR hmac_key_d[16]; michael@0: Data hmac_key; michael@0: michael@0: ATTACH_DATA(hmac_key, hmac_key_d); michael@0: michael@0: if (!auth->authenticate) michael@0: goto done; michael@0: michael@0: assert(auth->username); michael@0: assert(auth->password.len); michael@0: assert(auth->realm); michael@0: assert(auth->nonce); michael@0: michael@0: if (r=nr_stun_compute_lt_message_integrity_password(auth->username, michael@0: auth->realm, michael@0: &auth->password, michael@0: &hmac_key)) michael@0: ABORT(r); michael@0: michael@0: if (!auth->username) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no username provided"); michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: michael@0: if (!auth->password.len) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no password provided"); michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: michael@0: if (!auth->realm) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no realm provided"); michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: michael@0: if (!auth->nonce) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no nonce provided"); michael@0: ABORT(R_INTERNAL); michael@0: } michael@0: michael@0: if ((r=nr_stun_message_add_username_attribute(req, auth->username))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_realm_attribute(req, auth->realm))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_nonce_attribute(req, auth->nonce))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_message_integrity_attribute(req, &hmac_key))) michael@0: ABORT(r); michael@0: michael@0: done: michael@0: _status=0; michael@0: abort: michael@0: return(_status); michael@0: } michael@0: michael@0: int michael@0: nr_stun_build_allocate_request(nr_stun_client_auth_params *auth, nr_stun_client_allocate_request_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *req = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_ALLOCATE_REQUEST, &req))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_requested_transport_attribute(req, NR_STUN_ATTR_REQUESTED_TRANSPORT_UDP))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_lifetime_attribute(req, params->lifetime_secs))) michael@0: ABORT(r); michael@0: michael@0: /* TODO(ekr@rtfm.com): Add the SOFTWARE attribute (Firefox bug 857666) */ michael@0: michael@0: if ((r=nr_stun_build_auth_params(auth, req))) michael@0: ABORT(r); michael@0: michael@0: *msg = req; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&req); michael@0: return _status; michael@0: } michael@0: michael@0: michael@0: int nr_stun_build_refresh_request(nr_stun_client_auth_params *auth, nr_stun_client_refresh_request_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *req = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_REFRESH_REQUEST, &req))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_lifetime_attribute(req, params->lifetime_secs))) michael@0: ABORT(r); michael@0: michael@0: michael@0: /* TODO(ekr@rtfm.com): Add the SOFTWARE attribute (Firefox bug 857666) */ michael@0: michael@0: if ((r=nr_stun_build_auth_params(auth, req))) michael@0: ABORT(r); michael@0: michael@0: *msg = req; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&req); michael@0: return _status; michael@0: } michael@0: michael@0: michael@0: int nr_stun_build_permission_request(nr_stun_client_auth_params *auth, nr_stun_client_permission_request_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *req = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_PERMISSION_REQUEST, &req))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_xor_peer_address_attribute(req, ¶ms->remote_addr))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_build_auth_params(auth, req))) michael@0: ABORT(r); michael@0: michael@0: *msg = req; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&req); michael@0: return _status; michael@0: } michael@0: michael@0: int michael@0: nr_stun_build_send_indication(nr_stun_client_send_indication_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *ind = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_SEND_INDICATION, &ind))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_xor_peer_address_attribute(ind, ¶ms->remote_addr))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_data_attribute(ind, params->data.data, params->data.len))) michael@0: ABORT(r); michael@0: michael@0: *msg = ind; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&ind); michael@0: return _status; michael@0: } michael@0: michael@0: int michael@0: nr_stun_build_data_indication(nr_stun_client_data_indication_params *params, nr_stun_message **msg) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message *ind = 0; michael@0: michael@0: if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_DATA_INDICATION, &ind))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_xor_peer_address_attribute(ind, ¶ms->remote_addr))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_data_attribute(ind, params->data.data, params->data.len))) michael@0: ABORT(r); michael@0: michael@0: *msg = ind; michael@0: michael@0: _status=0; michael@0: abort: michael@0: if (_status) nr_stun_message_destroy(&ind); michael@0: return _status; michael@0: } michael@0: michael@0: #endif /* USE_TURN */ michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1.1 */ michael@0: int michael@0: nr_stun_form_success_response(nr_stun_message *req, nr_transport_addr *from, Data *password, nr_stun_message *res) michael@0: { michael@0: int r,_status; michael@0: int request_method; michael@0: char server_name[NR_STUN_MAX_SERVER_BYTES+1]; /* +1 for \0 */ michael@0: michael@0: /* set up information for default response */ michael@0: michael@0: request_method = NR_STUN_GET_TYPE_METHOD(req->header.type); michael@0: res->header.type = NR_STUN_TYPE(request_method, NR_CLASS_RESPONSE); michael@0: res->header.magic_cookie = req->header.magic_cookie; michael@0: memcpy(&res->header.id, &req->header.id, sizeof(res->header.id)); michael@0: michael@0: r_log(NR_LOG_STUN, LOG_DEBUG, "Mapped Address = %s", from->as_string); michael@0: michael@0: if ((r=nr_stun_message_add_xor_mapped_address_attribute(res, from))) michael@0: ABORT(r); michael@0: michael@0: if (!NR_reg_get_string(NR_STUN_REG_PREF_SERVER_NAME, server_name, sizeof(server_name))) { michael@0: if ((r=nr_stun_message_add_server_attribute(res, server_name))) michael@0: ABORT(r); michael@0: } michael@0: michael@0: if (res->header.magic_cookie == NR_STUN_MAGIC_COOKIE) { michael@0: if (password != 0) { michael@0: if ((r=nr_stun_message_add_message_integrity_attribute(res, password))) michael@0: ABORT(r); michael@0: } michael@0: michael@0: if ((r=nr_stun_message_add_fingerprint_attribute(res))) michael@0: ABORT(r); michael@0: } michael@0: michael@0: _status=0; michael@0: abort: michael@0: return _status; michael@0: } michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1.1 */ michael@0: void michael@0: nr_stun_form_error_response(nr_stun_message *req, nr_stun_message* res, int number, char* msg) michael@0: { michael@0: char *str; michael@0: int request_method; michael@0: char server_name[NR_STUN_MAX_SERVER_BYTES+1]; /* +1 for \0 */ michael@0: michael@0: if (number < 300 || number > 699) michael@0: number = 500; michael@0: michael@0: r_log(NR_LOG_STUN, LOG_INFO, "Responding with error %d: %s", number, msg); michael@0: michael@0: request_method = NR_STUN_GET_TYPE_METHOD(req->header.type); michael@0: res->header.type = NR_STUN_TYPE(request_method, NR_CLASS_ERROR_RESPONSE); michael@0: res->header.magic_cookie = req->header.magic_cookie; michael@0: memcpy(&res->header.id, &req->header.id, sizeof(res->header.id)); michael@0: michael@0: /* during development we should never see 500s (hopefully not in deployment either) */ michael@0: michael@0: str = 0; michael@0: switch (number) { michael@0: case 300: str = "Try Alternate"; break; michael@0: case 400: str = "Bad Request"; break; michael@0: case 401: str = "Unauthorized"; break; michael@0: case 420: str = "Unknown Attribute"; break; michael@0: case 438: str = "Stale Nonce"; break; michael@0: #ifdef USE_ICE michael@0: case 487: str = "Role Conflict"; break; michael@0: #endif michael@0: case 500: str = "Server Error"; break; michael@0: } michael@0: if (str == 0) { michael@0: str = "Unknown"; michael@0: } michael@0: michael@0: if (nr_stun_message_add_error_code_attribute(res, number, str)) { michael@0: assert(0); /* should never happen */ michael@0: } michael@0: michael@0: if (!NR_reg_get_string(NR_STUN_REG_PREF_SERVER_NAME, server_name, sizeof(server_name))) { michael@0: nr_stun_message_add_server_attribute(res, server_name); michael@0: } michael@0: } michael@0: