📄 stun_common.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//** * @file stun_common.c * @brief * * @author Tat Chan <Tat.Chan@nokia.com> * @author Kai Vehmanen <kai.vehmanen@nokia.com> * * @date Created: Fri Oct 3 13:40:41 2003 ppessi * */#ifndef WIN32#include "config.h"#endif#ifdef USE_TURN#include "../turn/turn_common.h"#undef LARGEST_ATTRIBUTE#define LARGEST_ATTRIBUTE TURN_LARGEST_ATTRIBUTE#endif#include "stun_internal.h"#include <assert.h>const char stun_400_Bad_request[] = "Bad Request", stun_401_Unauthorized[] = "Unauthorized", stun_420_Unknown_attribute[] = "Unknown Attribute", stun_430_Stale_credentials[] = "Stale Credentials", stun_431_Integrity_check_failure[] = "Integrity Check Failure", stun_432_Missing_username[] = "Missing Username", stun_433_Use_tls[] = "Use TLS",#ifdef USE_TURN turn_434_Missing_realm[] = "Missing Realm", turn_435_Missing_nonce[] = "Missing Nonce", turn_436_Unknown_username[] = "Unknown Username", turn_437_No_binding[] = "No Binding", turn_439_Illegal_port[] = "Illegal Port",#endif stun_500_Server_error[] = "Server Error", stun_600_Global_failure[] = "Global Failure";int stun_parse_message(stun_msg_t *msg) { unsigned len; int i; unsigned char *p; uint16_t tmp16; /* parse header first */ p = msg->enc_buf.data; memcpy(&tmp16, p, 2); p+=2; msg->stun_hdr.msg_type = ntohs(tmp16); memcpy(&tmp16, p, 2); p+=2; msg->stun_hdr.msg_len = ntohs(tmp16); for (i = 0; i < 8; i++) { memcpy(&tmp16, p, 2); p+=2; msg->stun_hdr.tran_id[i] = ntohs(tmp16); } SU_DEBUG_5(("%s: Parse STUN message: Length = %d\n", __func__, msg->stun_hdr.msg_len)); /* parse attributes */ len = msg->stun_hdr.msg_len; p = msg->enc_buf.data + 20; msg->stun_attr = NULL; while (len > 0) { i = stun_parse_attribute(msg, p); if (i <= 0) { SU_DEBUG_3(("%s: Error parsing attribute.\n", __func__)); return -1; } p += i; len -= i; } return 0;}int stun_parse_attribute(stun_msg_t *msg, unsigned char *p) { int len; uint16_t tmp16; stun_attr_t *attr, *next; attr = (stun_attr_t *) malloc(sizeof(stun_attr_t)); attr->next = NULL; memcpy(&tmp16, p, 2); p+=2; attr->attr_type = ntohs(tmp16); if (attr->attr_type > LARGEST_ATTRIBUTE && attr->attr_type < OPTIONAL_ATTRIBUTE) { free(attr); return -1; } memcpy(&tmp16, p, 2); p+=2; len = ntohs(tmp16); SU_DEBUG_5(("%s: received attribute: Type %02X, Length %d - %s\n", __func__, attr->attr_type, len, stun_attr_phrase(attr->attr_type))); switch (attr->attr_type) { case MAPPED_ADDRESS: case RESPONSE_ADDRESS: case SOURCE_ADDRESS: case CHANGED_ADDRESS: case REFLECTED_FROM:#ifdef USE_TURN case TURN_ALTERNATE_SERVER: case TURN_DESTINATION_ADDRESS: case TURN_SOURCE_ADDRESS:#endif if (stun_parse_attr_address(attr, p, len) < 0) { free(attr); return -1; } break; case ERROR_CODE: if(stun_parse_attr_error_code(attr, p, len) <0) { free(attr); return -1; } break; case UNKNOWN_ATTRIBUTES: if(stun_parse_attr_unknown_attributes(attr, p, len) <0) { free(attr); return -1; } break; case CHANGE_REQUEST:#ifdef USE_TURN case TURN_LIFETIME: case TURN_MAGIC_COOKIE: case TURN_BANDWIDTH:#endif if(stun_parse_attr_uint32(attr, p, len) <0) { free(attr); return -1; } break; case USERNAME: case PASSWORD:#ifdef USE_TURN case TURN_DATA: case TURN_NONCE:#endif if(stun_parse_attr_buffer(attr, p, len) <0) { free(attr); return -1; } break; default: /* just copy as is */ attr->pattr = NULL; attr->enc_buf.size = len; attr->enc_buf.data = (unsigned char *) malloc(len); memcpy(attr->enc_buf.data, p, len); break; } /* skip to end of list */ if(msg->stun_attr==NULL) { msg->stun_attr = attr; } else { next = msg->stun_attr; while(next->next!=NULL) { next = next->next; } next->next = attr; } return len+4;}int stun_parse_attr_address(stun_attr_t *attr, const unsigned char *p, unsigned len){ stun_attr_sockaddr_t *addr; int addrlen; if (len != 8) { return -1; } addrlen = sizeof(stun_attr_sockaddr_t); addr = (stun_attr_sockaddr_t *)malloc(addrlen); if (*(p+1) == 1) { /* expected value for IPv4 */ addr->sin_family = AF_INET; } else { free(addr); return -1; } memcpy(&addr->sin_port, p + 2, 2); memcpy(&addr->sin_addr.s_addr, p + 4, 4); SU_DEBUG_5(("%s: address attribute: %s:%d\n", __func__, inet_ntoa(addr->sin_addr), ntohs(addr->sin_port))); attr->pattr = addr; stun_init_buffer(&attr->enc_buf); return 0;}int stun_parse_attr_error_code(stun_attr_t *attr, const unsigned char *p, unsigned len) { uint32_t tmp; stun_attr_errorcode_t *error; memcpy(&tmp, p, sizeof(uint32_t)); tmp = ntohl(tmp); error = (stun_attr_errorcode_t *) malloc(sizeof(*error)); error->code = (tmp & STUN_EC_CLASS)*100 + (tmp & STUN_EC_NUM); error->phrase = (char *) malloc(len-4); strncpy(error->phrase, (char*)p+4, len-4); attr->pattr = error; stun_init_buffer(&attr->enc_buf); return 0;}int stun_parse_attr_uint32(stun_attr_t *attr, const unsigned char *p, unsigned len){ uint32_t tmp; stun_attr_changerequest_t *cr; cr = (stun_attr_changerequest_t *) malloc(sizeof(*cr)); memcpy(&tmp, p, sizeof(uint32_t)); cr->value = ntohl(tmp); attr->pattr = cr; stun_init_buffer(&attr->enc_buf); return 0;}int stun_parse_attr_buffer(stun_attr_t *attr, const unsigned char *p, unsigned len){ stun_buffer_t *buf; buf = (stun_buffer_t *) malloc(sizeof(stun_buffer_t)); buf->size = len; buf->data = (unsigned char *) malloc(len); memcpy(buf->data, p, len); attr->pattr = buf; stun_init_buffer(&attr->enc_buf); return 0;}int stun_parse_attr_unknown_attributes(stun_attr_t *attr, const unsigned char *p, unsigned len){ return 0;}/** scan thru attribute list and return the requested attr */stun_attr_t *stun_get_attr(stun_attr_t *attr, uint16_t attr_type) { stun_attr_t *p; for (p = attr; p != NULL; p = p->next) { if (p->attr_type == attr_type) break; } return p;}void stun_init_buffer(stun_buffer_t *p) { p->data = NULL; p->size = 0;}int stun_free_buffer(stun_buffer_t *p) { if (p->data) free(p->data); p->size = 0; return 0;}int stun_copy_buffer(stun_buffer_t *p, stun_buffer_t *p2) { stun_free_buffer(p); /* clean up existing data */ p->size = p2->size; p->data = (unsigned char *) malloc(p->size); memcpy(p->data, p2->data, p->size); return p->size;}const char *stun_response_phrase(int status) { if (status <100 || status >600) return NULL; switch (status) { case STUN_400_BAD_REQUEST: return stun_400_Bad_request; case STUN_401_UNAUTHORIZED: return stun_401_Unauthorized; case STUN_420_UNKNOWN_ATTRIBUTE: return stun_420_Unknown_attribute; case STUN_430_STALE_CREDENTIALS: return stun_430_Stale_credentials; case STUN_431_INTEGRITY_CHECK_FAILURE: return stun_431_Integrity_check_failure; case STUN_432_MISSING_USERNAME: return stun_432_Missing_username; case STUN_433_USE_TLS: return stun_433_Use_tls;#ifdef USE_TURN case TURN_MISSING_REALM: return turn_434_Missing_realm; case TURN_MISSING_NONCE: return turn_435_Missing_nonce; case TURN_UNKNOWN_USERNAME: return turn_436_Unknown_username; case TURN_NO_BINDING: return turn_437_No_binding; case TURN_ILLEGAL_PORT: return turn_439_Illegal_port;#endif case STUN_500_SERVER_ERROR: return stun_500_Server_error; case STUN_600_GLOBAL_FAILURE: return stun_600_Global_failure; } return "Response";}/** The set of functions encodes the corresponding attribute to * network format, and save the result to the enc_buf. Return the * size of the buffer. *//* This function is used to encode any attribute of the form ADDRESS */int stun_encode_address(stun_attr_t *attr) { stun_attr_sockaddr_t *a; uint16_t tmp; a = (stun_attr_sockaddr_t *)attr->pattr; if (stun_encode_type_len(attr, 2*sizeof(uint32_t)) < 0) { return -1; } tmp = htons(0x01); /* FAMILY = 0x01 */ memcpy(attr->enc_buf.data+4, &tmp, sizeof(tmp)); memcpy(attr->enc_buf.data+6, &a->sin_port, sizeof(uint32_t)); memcpy(attr->enc_buf.data+8, &a->sin_addr.s_addr, sizeof(uint32_t)); return attr->enc_buf.size;}int stun_encode_uint32(stun_attr_t *attr) { uint32_t tmp; if(stun_encode_type_len(attr, sizeof(tmp))<0) { return -1; } tmp = htonl(((stun_attr_changerequest_t *) attr->pattr)->value); memcpy(attr->enc_buf.data+4, &tmp, sizeof(tmp)); return attr->enc_buf.size;}int stun_encode_error_code(stun_attr_t *attr) { short int class, num; char *reason; int len; stun_attr_errorcode_t *error; error = (stun_attr_errorcode_t *) attr->pattr; class = error->code / 100; num = error->code % 100; len = strlen(error->phrase); attr->enc_buf.size = len + (len % 4 == 0? 0 : 4 - (len % 4)); reason = malloc(attr->enc_buf.size); memset(reason, 0, attr->enc_buf.size); memcpy(reason, error->phrase, len); attr->enc_buf.size +=4; if (stun_encode_type_len(attr, attr->enc_buf.size) < 0) { return -1; } memset(attr->enc_buf.data+4, 0, 2); memcpy(attr->enc_buf.data+6, &class, 1); memcpy(attr->enc_buf.data+7, &num, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -