HRESULT CTestReader::Test1() { HRESULT hr = S_OK; StunAttribute attrib; const char* pszExpectedSoftwareAttribute = "STUN test client"; const char* pszExpectedUserName = "******"; CRefCountedBuffer spBuffer; char szStringValue[100]; const unsigned char *req = c_requestbytes; size_t requestsize = sizeof(c_requestbytes)-1; // -1 to get rid of the trailing null CStunMessageReader reader; CStunMessageReader::ReaderParseState state; // reader is expecting at least enough bytes to fill the header ChkIfA(reader.AddBytes(NULL, 0) != CStunMessageReader::HeaderNotRead, E_FAIL); ChkIfA(reader.HowManyBytesNeeded() != STUN_HEADER_SIZE, E_FAIL); state = reader.AddBytes(req, requestsize); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); ChkIfA(reader.HowManyBytesNeeded() != 0, E_FAIL); ChkA(reader.GetBuffer(&spBuffer)); ChkIfA(reader.GetMessageClass() != StunMsgClassRequest, E_FAIL); ChkIfA(reader.GetMessageType() != StunMsgTypeBinding, E_FAIL); ChkA(reader.GetAttributeByType(STUN_ATTRIBUTE_SOFTWARE, &attrib)); ChkIfA(attrib.attributeType != STUN_ATTRIBUTE_SOFTWARE, E_FAIL); ChkIfA(0 != ::strncmp(pszExpectedSoftwareAttribute, (const char*)(spBuffer->GetData() + attrib.offset), attrib.size), E_FAIL); ChkA(reader.GetAttributeByType(STUN_ATTRIBUTE_USERNAME, &attrib)); ChkIfA(attrib.attributeType != STUN_ATTRIBUTE_USERNAME, E_FAIL); ChkIfA(0 != ::strncmp(pszExpectedUserName, (const char*)(spBuffer->GetData() + attrib.offset), attrib.size), E_FAIL); ChkA(reader.GetStringAttributeByType(STUN_ATTRIBUTE_SOFTWARE, szStringValue, ARRAYSIZE(szStringValue))); ChkIfA(0 != ::strcmp(pszExpectedSoftwareAttribute, szStringValue), E_FAIL); ChkIfA(reader.HasFingerprintAttribute() == false, E_FAIL); ChkIfA(reader.IsFingerprintAttributeValid() == false, E_FAIL); ChkIfA(reader.HasMessageIntegrityAttribute() == false, E_FAIL); ChkA(reader.ValidateMessageIntegrityShort(c_password)); Cleanup: return hr; }
void TcpClientLoop(StunClientLogicConfig& config, ClientSocketConfig& socketconfig) { HRESULT hr = S_OK; CStunSocket stunsocket; CStunClientLogic clientlogic; int sock; CRefCountedBuffer spMsg(new CBuffer(1500)); CRefCountedBuffer spMsgReader(new CBuffer(1500)); CSocketAddress addrDest, addrLocal; HRESULT hrRet, hrResult; int ret; size_t bytes_sent, bytes_recv; size_t bytes_to_send, max_bytes_recv, remaining; uint8_t* pData=NULL; size_t readsize; CStunMessageReader reader; StunClientResults results; hr= clientlogic.Initialize(config); if (FAILED(hr)) { Logging::LogMsg(LL_ALWAYS, "clientlogic.Initialize failed (hr == %x)", hr); Chk(hr); } while (true) { stunsocket.Close(); hr = stunsocket.TCPInit(socketconfig.addrLocal, RolePP, true); if (FAILED(hr)) { Logging::LogMsg(LL_ALWAYS, "Unable to create local socket for TCP connection (hr == %x)", hr); Chk(hr); } hrRet = clientlogic.GetNextMessage(spMsg, &addrDest, ::GetMillisecondCounter()); if (hrRet == E_STUNCLIENT_RESULTS_READY) { // clean exit break; } // we should never get a "still waiting" return with TCP, because config.timeout is 0 ASSERT(hrRet != E_STUNCLIENT_STILL_WAITING); if (FAILED(hrRet)) { Chk(hrRet); } // connect to server sock = stunsocket.GetSocketHandle(); ret = ::connect(sock, addrDest.GetSockAddr(), addrDest.GetSockAddrLength()); if (ret == -1) { hrResult = ERRNOHR; Logging::LogMsg(LL_ALWAYS, "Can't connect to server (hr == %x)", hrResult); Chk(hrResult); } Logging::LogMsg(LL_DEBUG, "Connected to server"); bytes_to_send = (int)(spMsg->GetSize()); bytes_sent = 0; pData = spMsg->GetData(); while (bytes_sent < bytes_to_send) { ret = ::send(sock, pData+bytes_sent, bytes_to_send-bytes_sent, 0); if (ret < 0) { hrResult = ERRNOHR; Logging::LogMsg(LL_ALWAYS, "Send failed (hr == %x)", hrResult); Chk(hrResult); } bytes_sent += ret; } Logging::LogMsg(LL_DEBUG, "Request sent - waiting for response"); // consume the response reader.Reset(); reader.GetStream().Attach(spMsgReader, true); pData = spMsg->GetData(); bytes_recv = 0; max_bytes_recv = spMsg->GetAllocatedSize(); remaining = max_bytes_recv; while (remaining > 0) { readsize = reader.HowManyBytesNeeded(); if (readsize == 0) { break; } if (readsize > remaining) { // technically an error, but the client logic will figure it out ASSERT(false); break; } ret = ::recv(sock, pData+bytes_recv, readsize, 0); if (ret == 0) { // server cut us off before we got all the bytes we thought we were supposed to get? ASSERT(false); break; } if (ret < 0) { hrResult = ERRNOHR; Logging::LogMsg(LL_ALWAYS, "Recv failed (hr == %x)", hrResult); Chk(hrResult); } reader.AddBytes(pData+bytes_recv, ret); bytes_recv += ret; remaining = max_bytes_recv - bytes_recv; spMsg->SetSize(bytes_recv); } // now feed the response into the client logic stunsocket.UpdateAddresses(); addrLocal = stunsocket.GetLocalAddress(); clientlogic.ProcessResponse(spMsg, addrDest, addrLocal); } stunsocket.Close(); results.Init(); clientlogic.GetResults(&results); ::DumpResults(config, results); Cleanup: return; }