/* $Id$ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #if PJ_LOG_MAX_LEVEL > 0 #define APPLY() if (len < 1 || len >= (end-p)) \ goto on_return; \ p += len static int print_binary(char *buffer, unsigned length, const pj_uint8_t *data, unsigned data_len) { unsigned i; if (length < data_len * 2 + 8) return -1; pj_ansi_sprintf(buffer, ", data="); buffer += 7; for (i=0; itype); char attr_buf[32]; int len; if (*attr_name == '?') { pj_ansi_snprintf(attr_buf, sizeof(attr_buf), "Attr 0x%x", ahdr->type); attr_name = attr_buf; } len = pj_ansi_snprintf(p, end-p, " %s: length=%d", attr_name, (int)ahdr->length); APPLY(); switch (ahdr->type) { case PJ_STUN_ATTR_MAPPED_ADDR: case PJ_STUN_ATTR_RESPONSE_ADDR: case PJ_STUN_ATTR_SOURCE_ADDR: case PJ_STUN_ATTR_CHANGED_ADDR: case PJ_STUN_ATTR_REFLECTED_FROM: case PJ_STUN_ATTR_XOR_PEER_ADDR: case PJ_STUN_ATTR_XOR_RELAYED_ADDR: case PJ_STUN_ATTR_XOR_MAPPED_ADDR: case PJ_STUN_ATTR_XOR_REFLECTED_FROM: case PJ_STUN_ATTR_ALTERNATE_SERVER: { char addr[PJ_INET6_ADDRSTRLEN]; const pj_stun_sockaddr_attr *attr; pj_uint16_t af; attr = (const pj_stun_sockaddr_attr*)ahdr; af = attr->sockaddr.addr.sa_family; if ((af == pj_AF_INET()) || (af == pj_AF_INET6())) { len = pj_ansi_snprintf(p, end-p, ", %s addr=%s\n", (af == pj_AF_INET())?"IPv4":"IPv6", pj_sockaddr_print(&attr->sockaddr, addr, sizeof(addr),3)); } else { len = pj_ansi_snprintf(p, end-p, ", INVALID ADDRESS FAMILY!\n"); } APPLY(); } break; case PJ_STUN_ATTR_CHANNEL_NUMBER: { const pj_stun_uint_attr *attr; attr = (const pj_stun_uint_attr*)ahdr; len = pj_ansi_snprintf(p, end-p, ", chnum=%u (0x%x)\n", (int)PJ_STUN_GET_CH_NB(attr->value), (int)PJ_STUN_GET_CH_NB(attr->value)); APPLY(); } break; case PJ_STUN_ATTR_CHANGE_REQUEST: case PJ_STUN_ATTR_LIFETIME: case PJ_STUN_ATTR_BANDWIDTH: case PJ_STUN_ATTR_REQ_ADDR_TYPE: case PJ_STUN_ATTR_EVEN_PORT: case PJ_STUN_ATTR_REQ_TRANSPORT: case PJ_STUN_ATTR_TIMER_VAL: case PJ_STUN_ATTR_PRIORITY: case PJ_STUN_ATTR_FINGERPRINT: case PJ_STUN_ATTR_REFRESH_INTERVAL: case PJ_STUN_ATTR_ICMP: { const pj_stun_uint_attr *attr; attr = (const pj_stun_uint_attr*)ahdr; len = pj_ansi_snprintf(p, end-p, ", value=%u (0x%x)\n", (pj_uint32_t)attr->value, (pj_uint32_t)attr->value); APPLY(); } break; case PJ_STUN_ATTR_USERNAME: case PJ_STUN_ATTR_PASSWORD: case PJ_STUN_ATTR_REALM: case PJ_STUN_ATTR_NONCE: case PJ_STUN_ATTR_SOFTWARE: { const pj_stun_string_attr *attr; attr = (pj_stun_string_attr*)ahdr; len = pj_ansi_snprintf(p, end-p, ", value=\"%.*s\"\n", (int)attr->value.slen, attr->value.ptr); APPLY(); } break; case PJ_STUN_ATTR_ERROR_CODE: { const pj_stun_errcode_attr *attr; attr = (const pj_stun_errcode_attr*) ahdr; len = pj_ansi_snprintf(p, end-p, ", err_code=%d, reason=\"%.*s\"\n", attr->err_code, (int)attr->reason.slen, attr->reason.ptr); APPLY(); } break; case PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES: { const pj_stun_unknown_attr *attr; unsigned j; attr = (const pj_stun_unknown_attr*) ahdr; len = pj_ansi_snprintf(p, end-p, ", unknown list:"); APPLY(); for (j=0; jattr_count; ++j) { len = pj_ansi_snprintf(p, end-p, " %d", (int)attr->attrs[j]); APPLY(); } } break; case PJ_STUN_ATTR_MESSAGE_INTEGRITY: { const pj_stun_msgint_attr *attr; attr = (const pj_stun_msgint_attr*) ahdr; len = print_binary(p, (unsigned)(end-p), attr->hmac, 20); APPLY(); } break; case PJ_STUN_ATTR_DATA: { const pj_stun_binary_attr *attr; attr = (const pj_stun_binary_attr*) ahdr; len = print_binary(p, (unsigned)(end-p), attr->data, attr->length); APPLY(); } break; case PJ_STUN_ATTR_ICE_CONTROLLED: case PJ_STUN_ATTR_ICE_CONTROLLING: case PJ_STUN_ATTR_RESERVATION_TOKEN: { const pj_stun_uint64_attr *attr; pj_uint8_t data[8]; int i; attr = (const pj_stun_uint64_attr*) ahdr; for (i=0; i<8; ++i) data[i] = ((const pj_uint8_t*)&attr->value)[7-i]; len = print_binary(p, (unsigned)(end-p), data, 8); APPLY(); } break; case PJ_STUN_ATTR_USE_CANDIDATE: case PJ_STUN_ATTR_DONT_FRAGMENT: default: len = pj_ansi_snprintf(p, end-p, "\n"); APPLY(); break; } return (int)(p-buffer); on_return: return len; } /* * Dump STUN message to a printable string output. */ PJ_DEF(char*) pj_stun_msg_dump(const pj_stun_msg *msg, char *buffer, unsigned length, unsigned *printed_len) { char *p, *end; int len; unsigned i; pj_uint32_t tsx_id[3]; PJ_ASSERT_RETURN(msg && buffer && length, NULL); PJ_CHECK_STACK(); p = buffer; end = buffer + length; len = pj_ansi_snprintf(p, end-p, "STUN %s %s\n", pj_stun_get_method_name(msg->hdr.type), pj_stun_get_class_name(msg->hdr.type)); APPLY(); pj_memcpy(tsx_id, msg->hdr.tsx_id, sizeof(msg->hdr.tsx_id)); len = pj_ansi_snprintf(p, end-p, " Hdr: length=%d, magic=%08x, tsx_id=%08x%08x%08x\n" " Attributes:\n", msg->hdr.length, msg->hdr.magic, tsx_id[0], tsx_id[1], tsx_id[2]); APPLY(); for (i=0; iattr_count; ++i) { len = print_attr(p, (unsigned)(end-p), msg->attr[i]); APPLY(); } on_return: *p = '\0'; if (printed_len) *printed_len = (unsigned)(p-buffer); return buffer; #undef APPLY } #endif /* PJ_LOG_MAX_LEVEL > 0 */