void StunClient::debugStunResponse(QByteArray resp) { u08bits rbuf[STUN_BUFFER_SIZE]; size_t rlen = 0; stun_buffer buf; u08bits addr_buff[STUN_BUFFER_SIZE] = {0}; rlen = resp.length(); memcpy(rbuf, resp.data(), resp.length()); buf.len = resp.length(); memcpy(buf.buf, resp.data(), resp.length()); if (!stun_is_command_message(&buf)) { qDebug()<<resp.length()<<("The response is not a STUN message\n"); return; } if (!stun_is_response(&buf)) { qDebug()<<resp.length()<<("The response is not a reponse message\n"); // return; } u16bits stun_method; u16bits stun_msg_type; stun_method = stun_get_method_str(buf.buf, buf.len); stun_msg_type = stun_get_msg_type_str(buf.buf, buf.len); qDebug()<<"method:"<<stun_method<<getMethodName(stun_method)<<",msg type:"<<stun_msg_type; int attr_type; const u08bits *attr_value; int attr_len; char relayed_addr_str[32] = {0}; char mapped_addr_str[32] = {0}; char addr_str[32] = {0}; ioa_addr relayed_addr; ioa_addr mapped_addr; ioa_addr stun_addr; uint32_t lifetime = 0; uint32_t bandwidth = 0; stun_attr_ref raw_attr = stun_attr_get_first_str(buf.buf, buf.len); for ( ; raw_attr ; raw_attr = stun_attr_get_next_str(buf.buf, buf.len, raw_attr)) { attr_type = stun_attr_get_type(raw_attr); attr_value = stun_attr_get_value(raw_attr); attr_len = stun_attr_get_len(raw_attr); switch (attr_type) { case STUN_ATTRIBUTE_SOFTWARE: qDebug()<<"attr software:"<<QByteArray((char*)attr_value, attr_len); break; case STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS: stun_attr_get_addr_str(buf.buf, buf.len, raw_attr, &mapped_addr, NULL); addr_to_string(&mapped_addr, (u08bits*)mapped_addr_str); qDebug()<<"mapped addr:"<<mapped_addr_str; break; case STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS: stun_attr_get_addr_str(buf.buf, buf.len, raw_attr, &relayed_addr, NULL); addr_to_string(&relayed_addr, (u08bits*)relayed_addr_str); qDebug()<<"relayed addr:"<<relayed_addr_str; break; case STUN_ATTRIBUTE_MESSAGE_INTEGRITY: qDebug()<<"message integrity:"<<attr_len<<QByteArray((char*)attr_value, attr_len).toHex(); break; case STUN_ATTRIBUTE_LIFETIME: memcpy(&lifetime, attr_value, attr_len); lifetime = nswap32(lifetime); qDebug()<<"lifetime:"<<lifetime; break; case STUN_ATTRIBUTE_BANDWIDTH: memcpy(&bandwidth, attr_value, attr_len); bandwidth = nswap32(bandwidth); qDebug()<<"bandwidth:"<<bandwidth; break; case STUN_ATTRIBUTE_XOR_PEER_ADDRESS: stun_attr_get_addr_str(buf.buf, buf.len, raw_attr, &stun_addr, NULL); addr_to_string(&stun_addr, (u08bits*)addr_str); qDebug()<<"xor peer addr:"<<addr_str; break; case STUN_ATTRIBUTE_DATA: qDebug()<<"attr data len:"<<attr_len<<QString(QByteArray((char*)attr_value + 4, attr_len - 4)).left(50)<<"..."; break; default: qDebug()<<"unkown attr:"<<attr_type<<attr_len; break; } } }
u16bits stun_get_method(const stun_buffer* buf) { return stun_get_method_str(buf->buf, (size_t)(buf->len)); }
void StunClient::processResponse(QByteArray resp, QString peer_addr) { u08bits rbuf[STUN_BUFFER_SIZE]; size_t rlen = 0; stun_buffer buf; QString mapped_addr; u08bits addr_buff[STUN_BUFFER_SIZE] = {0}; rlen = resp.length(); memcpy(rbuf, resp.data(), resp.length()); buf.len = resp.length(); memcpy(buf.buf, resp.data(), resp.length()); if (!stun_is_command_message(&buf)) { qDebug()<<resp.length()<<("The response is not a STUN message")<<peer_addr; // should be a relayed raw UDP packet to peerA emit packetReceived(resp, peer_addr); return; } u16bits stun_method; u16bits stun_msg_type; stun_method = stun_get_method_str(buf.buf, buf.len); stun_msg_type = stun_get_msg_type_str(buf.buf, buf.len); qDebug()<<"method:"<<stun_method<<getMethodName(stun_method)<<",msg type:"<<stun_msg_type; if (stun_method == STUN_METHOD_BINDING) { } else { this->debugStunResponse(resp); } // channel data if (stun_is_indication(&buf)) { u16bits chan_no; size_t blen = 0; qDebug()<<"indication data:"<<buf.len; stun_attr_ref t_attr = stun_attr_get_first_by_type(&buf, STUN_ATTRIBUTE_DATA); const u08bits *t_value = stun_attr_get_value(t_attr); blen = stun_attr_get_len(t_attr); QString xor_peer_addr = getStunAddress(resp, STUN_ATTRIBUTE_XOR_PEER_ADDRESS); qDebug()<<"is chan msg:"<<stun_is_channel_message_str(t_value, &blen, &chan_no, 0); qDebug()<<"chan no:"<<chan_no<<blen<<xor_peer_addr; emit this->packetReceived(QByteArray((char*)t_value + 4, blen - 4), xor_peer_addr); return; } if (!stun_is_response(&buf)) { qDebug()<<resp.length()<<("The response is not a reponse message\n"); return; } if (!stun_is_success_response(&buf)) { int err_code = 0; u08bits err_msg[1025] = "\0"; size_t err_msg_size = sizeof(err_msg); if (stun_is_error_response(&buf, &err_code, err_msg, err_msg_size)) { printf("The response is an error %d (%s)\n", err_code, (char*) err_msg); } else { printf("The response is an unrecognized error\n"); } // test unauth u08bits realm[128] = {0}; u08bits nonce[256] = {0}; if (stun_is_challenge_response_str(buf.buf, buf.len, &err_code, err_msg, err_msg_size, realm, nonce)) { qDebug()<<err_code; qDebug()<<err_code<<(char*)err_msg<<(char*)realm<<(char*)nonce; m_realm = QByteArray((char*)realm); m_nonce = QByteArray((char*)nonce); if (stun_method == STUN_METHOD_ALLOCATE) { this->allocate((char*)realm, (char*)nonce); } if (stun_method == STUN_METHOD_CHANNEL_BIND) { QThread::msleep(100); this->channelBind(m_peer_addr); } } if (err_code == 437) { assert(err_code != 437); // allocate mismatch } if (err_code == 438) { assert(err_code != 438); // stale nonce } if (err_code == 486) { assert(err_code != 486); // allocate quota reached } return; } if (stun_is_binding_response(&buf)) { ioa_addr reflexive_addr; addr_set_any(&reflexive_addr); if (stun_attr_get_first_addr(&buf, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &reflexive_addr, NULL) >= 0) { stun_attr_ref sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_OTHER_ADDRESS); if (sar) { // *rfc5780 = 1; printf("\n========================================\n"); // printf("RFC 5780 response %d\n",++counter); ioa_addr other_addr; stun_attr_get_addr_str((u08bits *) buf.buf, (size_t) buf.len, sar, &other_addr, NULL); sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_RESPONSE_ORIGIN); if (sar) { ioa_addr response_origin; stun_attr_get_addr_str((u08bits *) buf.buf, (size_t) buf.len, sar, &response_origin, NULL); addr_debug_print(1, &response_origin, "Response origin: "); } addr_debug_print(1, &other_addr, "Other addr: "); } addr_debug_print(1, &reflexive_addr, "UDP reflexive addr"); addr_to_string(&reflexive_addr, addr_buff); } else { printf("Cannot read the response\n"); } // emit got addr if (strlen((char*)addr_buff) > 0) { mapped_addr = QString((char*)addr_buff); emit this->mappedAddressRecieved(mapped_addr); } return; } // end bind resp if (stun_method == STUN_METHOD_ALLOCATE) { m_relayed_addr = this->getStunAddress(resp, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS); this->saveAllocatePuples(m_realm, m_nonce); emit this->allocateDone(m_relayed_addr); if (!m_channel_refresh_timer) { m_channel_refresh_timer = new QTimer(); QObject::connect(m_channel_refresh_timer, &QTimer::timeout, this, &StunClient::onRefreshTimeout); } if (!m_channel_refresh_timer->isActive()) { m_channel_refresh_timer->start(m_channel_refresh_timeout); } } if (stun_method == STUN_METHOD_CREATE_PERMISSION) { if (!m_permission_keepalive_timer) { emit this->createPermissionDone(); } if (!m_permission_keepalive_timer) { m_permission_keepalive_timer = new QTimer(); QObject::connect(m_permission_keepalive_timer, &QTimer::timeout, this, &StunClient::onPermKATimeout); } if (!m_permission_keepalive_timer->isActive()) { m_permission_keepalive_timer->start(m_permission_keepalive_timeout); } } if (stun_method == STUN_METHOD_CHANNEL_BIND) { emit this->channelBindDone(m_relayed_addr); } if (stun_method == STUN_METHOD_REFRESH) { qDebug()<<"refresh responsed."; } }