// Test1 - just do a basic binding request
HRESULT CTestMessageHandler::Test1()
{
    HRESULT hr=S_OK;
    CStunMessageBuilder builder;
    CSocketAddress clientaddr(0x12345678, 9876);
    CRefCountedBuffer spBuffer;
    CStunThreadMessageHandler handler;
    CStunMessageReader reader;
    CStunMessageReader::ReaderParseState state;
    StunMessageEnvelope message;

    _spTransport->Reset();
    _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234));

    InitBindingRequest(builder);

    builder.GetStream().GetBuffer(&spBuffer);

    handler.SetResponder(_spTransport);
    
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));
    
    handler.ProcessRequest(message);


    spBuffer.reset();
    _spTransport->GetOutputStream().GetBuffer(&spBuffer);

    state = reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize());

    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);

    // validate that the binding response matches our expectations
    ChkA(ValidateMappedAddress(reader, clientaddr));
    
    // validate that it came from the server port we expected
    ChkA(ValidateOriginAddress(reader, RolePP));

    // did we get back the binding request we expected
    ChkA(ValidateResponseAddress(clientaddr));
    
Cleanup:

    return hr;
}
// test long-credential authentication
HRESULT CTestMessageHandler::Test4()
{
    HRESULT hr=S_OK;
    CStunMessageBuilder builder1, builder2;
    CStunMessageReader reader1, reader2;
    CSocketAddress clientaddr(0x12345678, 9876);
    CSocketAddress addrMapped;
    CRefCountedBuffer spBuffer;
    CStunThreadMessageHandler handler;
    uint16_t errorcode = 0;
    char szNonce[MAX_STUN_AUTH_STRING_SIZE+1];
    char szRealm[MAX_STUN_AUTH_STRING_SIZE+1];
    
    CStunMessageReader::ReaderParseState state;
    StunMessageEnvelope message;
    
    _spTransport->Reset();
    _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234));
    
    handler.SetAuth(_spAuthLong);
    handler.SetResponder(_spTransport);

    // -----------------------------------------------------------------------
    // simulate a user making a request with no message integrity attribute (or username, or realm)
    InitBindingRequest(builder1);
    builder1.GetResult(&spBuffer);
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));
    
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    state = reader1.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    // we expect the response back will be a 401 with a provided nonce and realm
    Chk(reader1.GetErrorCode(&errorcode));
    
    ChkIfA(reader1.GetMessageClass() != ::StunMsgClassFailureResponse, E_UNEXPECTED);
    ChkIf(errorcode != ::STUN_ERROR_UNAUTHORIZED, E_UNEXPECTED);

    reader1.GetStringAttributeByType(STUN_ATTRIBUTE_REALM, szRealm, ARRAYSIZE(szRealm));
    reader1.GetStringAttributeByType(STUN_ATTRIBUTE_NONCE, szNonce, ARRAYSIZE(szNonce));
    
    
    // --------------------------------------------------------------------------------
    // now simulate the follow-up request
    _spTransport->ClearStream();
    spBuffer.reset();
    InitBindingRequest(builder2);
    builder2.AddNonce(szNonce);
    builder2.AddRealm(szRealm);
    builder2.AddUserName("AuthorizedUser");
    builder2.AddMessageIntegrityLongTerm("AuthorizedUser", szRealm, "password");
    builder2.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));
    
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    state = reader2.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    ChkIfA(reader2.GetMessageClass() != ::StunMsgClassSuccessResponse, E_UNEXPECTED);
    
    // should have a mapped address
    ChkA(reader2.GetMappedAddress(&addrMapped));
    
    // and the message integrity field should be valid
    ChkA(reader2.ValidateMessageIntegrityLong("AuthorizedUser", szRealm, "password"));
    
    
Cleanup:
    return hr;
}
// test simple authentication
HRESULT CTestMessageHandler::Test3()
{
    HRESULT hr=S_OK;
    CStunMessageBuilder builder1, builder2, builder3;
    CStunMessageReader reader1, reader2, reader3;
    CSocketAddress clientaddr(0x12345678, 9876);
    CRefCountedBuffer spBuffer;
    CStunThreadMessageHandler handler;
    uint16_t errorcode = 0;
    
    CStunMessageReader::ReaderParseState state;
    StunMessageEnvelope message;
    
    _spTransport->Reset();
    _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234));
    
    handler.SetAuth(_spAuthShort);
    handler.SetResponder(_spTransport);

    // -----------------------------------------------------------------------
    // simulate an authorized user making a request with a valid password
    InitBindingRequest(builder1);
    builder1.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "AuthorizedUser");
    builder1.AddMessageIntegrityShortTerm("password");
    builder1.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));
    
    handler.ProcessRequest(message);
    
    // we expect back a response with a valid message integrity field
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    state = reader1.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    ChkA(reader1.ValidateMessageIntegrityShort("password"));
    

    // -----------------------------------------------------------------------
    // simulate a user with a bad password
    spBuffer.reset();
    InitBindingRequest(builder2);
    builder2.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "WrongUser");
    builder2.AddMessageIntegrityShortTerm("wrongpassword");
    builder2.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));

    _spTransport->ClearStream();
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    state = reader2.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    errorcode = 0;
    ChkA(reader2.GetErrorCode(&errorcode));
    ChkIfA(errorcode != ::STUN_ERROR_UNAUTHORIZED, E_FAIL);
    
    // -----------------------------------------------------------------------
    // simulate a client sending no credentials - we expect it to fire back with a 400/bad-request
    spBuffer.reset();
    InitBindingRequest(builder3);
    builder3.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));

    _spTransport->ClearStream();
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    
    state = reader3.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    errorcode = 0;
    ChkA(reader3.GetErrorCode(&errorcode));
    ChkIfA(errorcode != ::STUN_ERROR_BADREQUEST, E_FAIL);
    
    
Cleanup:

    return hr;
    
}