libfreerdp-core: restructure RPC connection sequence

This commit is contained in:
Marc-André Moreau 2015-02-01 18:50:21 -05:00
parent 90a429e43c
commit 4eeabba933
10 changed files with 113 additions and 138 deletions

View File

@ -502,6 +502,7 @@ HttpResponse* http_response_recv(rdpTls* tls)
char* content;
char* header_end;
HttpResponse* http_response;
nbytes = 0;
length = 10000;
content = NULL;
@ -545,17 +546,18 @@ HttpResponse* http_response_recv(rdpTls* tls)
if (!header_end)
{
WLog_ERR(TAG, "invalid response:");
WLog_ERR(TAG, "invalid response");
winpr_HexDump(TAG, WLOG_ERROR, buffer, status);
goto out_error;
}
header_end += 2;
if (header_end != NULL)
if (header_end)
{
int count;
char* line;
header_end[0] = '\0';
header_end[1] = '\0';
content = header_end + 2;
@ -581,7 +583,7 @@ HttpResponse* http_response_recv(rdpTls* tls)
count = 0;
line = strtok((char*) buffer, "\r\n");
while ((line != NULL) && http_response->lines)
while (line && http_response->lines)
{
http_response->lines[count] = _strdup(line);

View File

@ -387,6 +387,7 @@ int rpc_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum)
request_pdu->alloc_hint = length;
request_pdu->p_cont_id = 0x0000;
request_pdu->opnum = opnum;
clientCall = rpc_client_call_new(request_pdu->call_id, request_pdu->opnum);
if (!clientCall)
@ -465,7 +466,56 @@ out_free_pdu:
return -1;
}
BOOL rpc_connect(rdpRpc* rpc)
int rpc_check(rdpRpc* rpc)
{
RPC_PDU* pdu;
if (rpc->State == RPC_CLIENT_STATE_ESTABLISHED)
{
if (rpc_send_bind_pdu(rpc) < 0)
{
WLog_ERR(TAG, "rpc_send_bind_pdu failure");
return -1;
}
rpc->State = RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK;
}
else if (rpc->State == RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK)
{
pdu = rpc_recv_dequeue_pdu(rpc, TRUE);
if (!pdu)
{
WLog_ERR(TAG, "rpc_recv_dequeue_pdu failure");
return -1;
}
if (rpc_recv_bind_ack_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)) <= 0)
{
WLog_ERR(TAG, "rpc_recv_bind_ack_pdu failure");
return -1;
}
rpc_client_receive_pool_return(rpc, pdu);
if (rpc_send_rpc_auth_3_pdu(rpc) <= 0)
{
WLog_ERR(TAG, "rpc_secure_bind: error sending rpc_auth_3 pdu!");
return -1;
}
rpc->State = RPC_CLIENT_STATE_CONTEXT_NEGOTIATED;
}
else
{
WLog_ERR(TAG, "rpc_check: invalid state: %d", rpc->State);
return -1;
}
return 1;
}
int rpc_connect(rdpRpc* rpc)
{
rpc->TlsIn = rpc->transport->TlsIn;
rpc->TlsOut = rpc->transport->TlsOut;
@ -473,18 +523,19 @@ BOOL rpc_connect(rdpRpc* rpc)
if (!rts_connect(rpc))
{
WLog_ERR(TAG, "rts_connect error!");
return FALSE;
return -1;
}
rpc->State = RPC_CLIENT_STATE_ESTABLISHED;
if (rpc_secure_bind(rpc) != 0)
while (rpc->State != RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
{
WLog_ERR(TAG, "rpc_secure_bind error!");
return FALSE;
if (rpc_check(rpc) < 0)
{
WLog_ERR(TAG, "rpc_check failure");
return -1;
}
}
return TRUE;
return 1;
}
void rpc_client_virtual_connection_init(rdpRpc* rpc, RpcVirtualConnection* connection)
@ -494,7 +545,6 @@ void rpc_client_virtual_connection_init(rdpRpc* rpc, RpcVirtualConnection* conne
connection->DefaultInChannel->SenderAvailableWindow = rpc->ReceiveWindow;
connection->DefaultInChannel->PingOriginator.ConnectionTimeout = 30;
connection->DefaultInChannel->PingOriginator.KeepAliveInterval = 0;
connection->DefaultInChannel->Mutex = CreateMutex(NULL, FALSE, NULL);
connection->DefaultOutChannel->State = CLIENT_OUT_CHANNEL_STATE_INITIAL;
connection->DefaultOutChannel->BytesReceived = 0;
@ -502,7 +552,6 @@ void rpc_client_virtual_connection_init(rdpRpc* rpc, RpcVirtualConnection* conne
connection->DefaultOutChannel->ReceiveWindow = rpc->ReceiveWindow;
connection->DefaultOutChannel->ReceiveWindowSize = rpc->ReceiveWindow;
connection->DefaultOutChannel->AvailableWindowAdvertised = rpc->ReceiveWindow;
connection->DefaultOutChannel->Mutex = CreateMutex(NULL, FALSE, NULL);
}
RpcVirtualConnection* rpc_client_virtual_connection_new(rdpRpc* rpc)
@ -536,8 +585,6 @@ void rpc_client_virtual_connection_free(RpcVirtualConnection* virtualConnection)
{
if (virtualConnection)
{
CloseHandle(virtualConnection->DefaultInChannel->Mutex);
CloseHandle(virtualConnection->DefaultOutChannel->Mutex);
free(virtualConnection->DefaultInChannel);
free(virtualConnection->DefaultOutChannel);
free(virtualConnection);

View File

@ -618,8 +618,6 @@ struct rpc_in_channel
CLIENT_IN_CHANNEL_STATE State;
HANDLE Mutex;
UINT32 PlugState;
void* SendQueue;
UINT32 BytesSent;
@ -651,8 +649,6 @@ struct rpc_out_channel
CLIENT_OUT_CHANNEL_STATE State;
HANDLE Mutex;
UINT32 ReceiveWindow;
UINT32 ReceiveWindowSize;
UINT32 ReceiverAvailableWindow;
@ -778,7 +774,7 @@ struct rdp_rpc
wArrayList* VirtualConnectionCookieTable;
};
BOOL rpc_connect(rdpRpc* rpc);
int rpc_connect(rdpRpc* rpc);
void rpc_pdu_header_print(rpcconn_hdr_t* header);
void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_hdr_t* header);

View File

@ -68,6 +68,29 @@ const p_uuid_t BTFN_UUID =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } /* node[6] */
};
/**
* Secure Connection-Oriented RPC Packet Sequence
*
* Client Server
* | |
* |-------------------SECURE_BIND-------------------->|
* | |
* |<----------------SECURE_BIND_ACK-------------------|
* | |
* |--------------------RPC_AUTH_3-------------------->|
* | |
* | |
* |------------------REQUEST_PDU_#1------------------>|
* |------------------REQUEST_PDU_#2------------------>|
* | |
* | ... |
* | |
* |<-----------------RESPONSE_PDU_#1------------------|
* |<-----------------RESPONSE_PDU_#2------------------|
* | |
* | ... |
*/
/**
* SECURE_BIND: RPC bind PDU with sec_trailer and auth_token. Auth_token is generated by calling
* the implementation equivalent of the abstract GSS_Init_sec_context call. Upon receiving that, the
@ -375,87 +398,3 @@ int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc)
return status;
}
/**
* Secure Connection-Oriented RPC Packet Sequence
*
* Client Server
* | |
* |-------------------SECURE_BIND-------------------->|
* | |
* |<----------------SECURE_BIND_ACK-------------------|
* | |
* |--------------------RPC_AUTH_3-------------------->|
* | |
* | |
* |------------------REQUEST_PDU_#1------------------>|
* |------------------REQUEST_PDU_#2------------------>|
* | |
* | ... |
* | |
* |<-----------------RESPONSE_PDU_#1------------------|
* |<-----------------RESPONSE_PDU_#2------------------|
* | |
* | ... |
*/
int rpc_secure_bind(rdpRpc* rpc)
{
int status;
RPC_PDU* pdu;
rpc->client->SynchronousSend = TRUE;
rpc->client->SynchronousReceive = TRUE;
while (rpc->State != RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
{
if (rpc->State == RPC_CLIENT_STATE_ESTABLISHED)
{
status = rpc_send_bind_pdu(rpc);
if (status <= 0)
{
WLog_ERR(TAG, "rpc_secure_bind: error sending bind pdu!");
return -1;
}
rpc->State = RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK;
}
else if (rpc->State == RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK)
{
pdu = rpc_recv_dequeue_pdu(rpc);
if (!pdu)
{
WLog_ERR(TAG, "rpc_secure_bind: error receiving bind ack pdu!");
return -1;
}
if (rpc_recv_bind_ack_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)) <= 0)
{
WLog_ERR(TAG, "rpc_secure_bind: error receiving bind ack pdu!");
return -1;
}
rpc_client_receive_pool_return(rpc, pdu);
if (rpc_send_rpc_auth_3_pdu(rpc) <= 0)
{
WLog_ERR(TAG, "rpc_secure_bind: error sending rpc_auth_3 pdu!");
return -1;
}
rpc->State = RPC_CLIENT_STATE_CONTEXT_NEGOTIATED;
}
else
{
WLog_ERR(TAG, "rpc_secure_bind: invalid state: %d", rpc->State);
return -1;
}
}
rpc->client->SynchronousSend = TRUE;
rpc->client->SynchronousReceive = TRUE;
return 0;
}

View File

@ -37,6 +37,4 @@ int rpc_send_bind_pdu(rdpRpc* rpc);
int rpc_recv_bind_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length);
int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc);
int rpc_secure_bind(rdpRpc* rpc);
#endif /* FREERDP_CORE_RPC_BIND_H */

View File

@ -119,13 +119,13 @@ int rpc_client_receive_pipe_read(rdpRpc* rpc, BYTE* buffer, size_t length)
return status;
}
int rpc_client_on_pdu_received_event(rdpRpc* rpc, RPC_PDU* pdu)
int rpc_client_on_pdu_received(rdpRpc* rpc, RPC_PDU* pdu)
{
Queue_Enqueue(rpc->client->ReceiveQueue, pdu);
return 1;
}
int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment)
int rpc_client_on_fragment_received(rdpRpc* rpc, wStream* fragment)
{
BYTE* buffer;
RPC_PDU* pdu;
@ -203,7 +203,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment)
pdu->Type = PTYPE_RESPONSE;
pdu->CallId = rpc->StubCallId;
Stream_SealLength(pdu->s);
rpc_client_on_pdu_received_event(rpc, pdu);
rpc_client_on_pdu_received(rpc, pdu);
rpc->client->pdu = NULL;
rpc->StubFragCount = 0;
rpc->StubCallId = 0;
@ -238,7 +238,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment)
Stream_EnsureCapacity(pdu->s, Stream_Length(fragment));
Stream_Write(pdu->s, buffer, Stream_Length(fragment));
Stream_SealLength(pdu->s);
rpc_client_on_pdu_received_event(rpc, pdu);
rpc_client_on_pdu_received(rpc, pdu);
rpc->client->pdu = NULL;
return 0;
}
@ -264,7 +264,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment)
Stream_EnsureCapacity(pdu->s, Stream_Length(fragment));
Stream_Write(pdu->s, buffer, Stream_Length(fragment));
Stream_SealLength(pdu->s);
rpc_client_on_pdu_received_event(rpc, pdu);
rpc_client_on_pdu_received(rpc, pdu);
rpc->client->pdu = NULL;
return 0;
}
@ -281,7 +281,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment)
return 0;
}
int rpc_client_on_read_event(rdpRpc* rpc)
int rpc_client_on_read(rdpRpc* rpc)
{
int position;
int status = -1;
@ -347,7 +347,7 @@ int rpc_client_on_read_event(rdpRpc* rpc)
Stream_SealLength(rpc->client->ReceiveFragment);
Stream_SetPosition(rpc->client->ReceiveFragment, 0);
status = rpc_client_on_fragment_received_event(rpc, rpc->client->ReceiveFragment);
status = rpc_client_on_fragment_received(rpc, rpc->client->ReceiveFragment);
if (status < 0)
return status;
@ -468,12 +468,10 @@ int rpc_send_dequeue_pdu(rdpRpc* rpc)
return 0;
inChannel = rpc->VirtualConnection->DefaultInChannel;
WaitForSingleObject(inChannel->Mutex, INFINITE);
status = rpc_in_write(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s));
header = (rpcconn_common_hdr_t*) Stream_Buffer(pdu->s);
clientCall = rpc_client_call_find_by_id(rpc, header->call_id);
clientCall->State = RPC_CLIENT_CALL_STATE_DISPATCHED;
ReleaseMutex(inChannel->Mutex);
/*
* This protocol specifies that only RPC PDUs are subject to the flow control abstract
@ -497,13 +495,13 @@ int rpc_send_dequeue_pdu(rdpRpc* rpc)
return status;
}
RPC_PDU* rpc_recv_dequeue_pdu(rdpRpc* rpc)
RPC_PDU* rpc_recv_dequeue_pdu(rdpRpc* rpc, BOOL blocking)
{
RPC_PDU* pdu;
DWORD timeout;
DWORD waitStatus;
timeout = rpc->client->SynchronousReceive ? SYNCHRONOUS_TIMEOUT * 4 : 0;
timeout = blocking ? SYNCHRONOUS_TIMEOUT * 4 : 0;
waitStatus = WaitForSingleObject(Queue_Event(rpc->client->ReceiveQueue), timeout);
@ -543,7 +541,7 @@ static void* rpc_client_thread(void* arg)
* the problem for now.
*/
if (rpc_client_on_read_event(rpc) < 0)
if (rpc_client_on_read(rpc) < 0)
{
rpc->transport->layer = TRANSPORT_LAYER_CLOSED;
return NULL;
@ -558,7 +556,7 @@ static void* rpc_client_thread(void* arg)
if (WaitForSingleObject(ReadEvent, 0) == WAIT_OBJECT_0)
{
if (rpc_client_on_read_event(rpc) < 0)
if (rpc_client_on_read(rpc) < 0)
{
rpc->transport->layer = TRANSPORT_LAYER_CLOSED;
break;

View File

@ -39,7 +39,7 @@ int rpc_send_enqueue_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length);
int rpc_send_dequeue_pdu(rdpRpc* rpc);
int rpc_recv_enqueue_pdu(rdpRpc* rpc);
RPC_PDU* rpc_recv_dequeue_pdu(rdpRpc* rpc);
RPC_PDU* rpc_recv_dequeue_pdu(rdpRpc* rpc, BOOL blocking);
int rpc_client_receive_pipe_read(rdpRpc* rpc, BYTE* buffer, size_t length);

View File

@ -94,9 +94,6 @@ BOOL rts_connect(rdpRpc* rpc)
rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_INITIAL;
WLog_DBG(TAG, "VIRTUAL_CONNECTION_STATE_INITIAL");
rpc->client->SynchronousSend = TRUE;
rpc->client->SynchronousReceive = TRUE;
if (!rpc_ntlm_http_out_connect(rpc))
{
WLog_ERR(TAG, "rpc_out_connect_http error!");
@ -184,8 +181,6 @@ BOOL rts_connect(rdpRpc* rpc)
http_response_free(httpResponse);
rpc_client_start(rpc);
rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_WAIT_A3W;
WLog_DBG(TAG, "VIRTUAL_CONNECTION_STATE_WAIT_A3W");
@ -205,7 +200,9 @@ BOOL rts_connect(rdpRpc* rpc)
*
*/
pdu = rpc_recv_dequeue_pdu(rpc);
rpc_client_start(rpc);
pdu = rpc_recv_dequeue_pdu(rpc, TRUE);
if (!pdu)
return FALSE;
@ -246,7 +243,7 @@ BOOL rts_connect(rdpRpc* rpc)
*
*/
pdu = rpc_recv_dequeue_pdu(rpc);
pdu = rpc_recv_dequeue_pdu(rpc, TRUE);
if (!pdu)
return FALSE;
@ -266,8 +263,7 @@ BOOL rts_connect(rdpRpc* rpc)
rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_OPENED;
WLog_DBG(TAG, "VIRTUAL_CONNECTION_STATE_OPENED");
rpc->client->SynchronousSend = TRUE;
rpc->client->SynchronousReceive = TRUE;
rpc->State = RPC_CLIENT_STATE_ESTABLISHED;
return TRUE;
}

View File

@ -177,8 +177,6 @@ BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg)
*((UINT32*) &buffer[44]) = NapCapabilities; /* capabilities */
//CopyMemory(&buffer[48], TsProxyCreateTunnelUnknownTrailerBytes, 60);
/**
* The following 60-byte structure is apparently undocumented,
* but parts of it can be matched to known C706 data structures.
@ -223,6 +221,7 @@ BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg)
return FALSE;
free(buffer);
return TRUE;
}
@ -1093,7 +1092,7 @@ HRESULT TsProxyCloseChannel(rdpTsg* tsg, PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE* co
return FALSE;
}
pdu = rpc_recv_dequeue_pdu(tsg->rpc);
pdu = rpc_recv_dequeue_pdu(tsg->rpc, TRUE);
if (!TsProxyCloseChannelReadResponse(tsg, pdu))
{
@ -1169,7 +1168,7 @@ HRESULT TsProxyCloseTunnel(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_SERIALIZE* contex
return FALSE;
}
pdu = rpc_recv_dequeue_pdu(tsg->rpc);
pdu = rpc_recv_dequeue_pdu(tsg->rpc, TRUE);
if (!TsProxyCloseTunnelReadResponse(tsg, pdu))
{
@ -1250,7 +1249,7 @@ int tsg_check(rdpTsg* tsg)
return -1;
}
pdu = rpc_recv_dequeue_pdu(rpc);
pdu = rpc_recv_dequeue_pdu(rpc, TRUE);
if (!TsProxyCreateTunnelReadResponse(tsg, pdu))
{
@ -1271,7 +1270,7 @@ int tsg_check(rdpTsg* tsg)
return -1;
}
pdu = rpc_recv_dequeue_pdu(rpc);
pdu = rpc_recv_dequeue_pdu(rpc, TRUE);
if (!TsProxyAuthorizeTunnelReadResponse(tsg, pdu))
{
@ -1297,7 +1296,7 @@ int tsg_check(rdpTsg* tsg)
return -1;
}
pdu = rpc_recv_dequeue_pdu(rpc);
pdu = rpc_recv_dequeue_pdu(rpc, TRUE);
if (!pdu)
{
@ -1315,7 +1314,7 @@ int tsg_check(rdpTsg* tsg)
return -1;
}
pdu = rpc_recv_dequeue_pdu(rpc);
pdu = rpc_recv_dequeue_pdu(rpc, TRUE);
}
if (!TsProxyCreateChannelReadResponse(tsg, pdu))

View File

@ -351,7 +351,7 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16
return FALSE;
}
if (!rpc_connect(tsg->rpc))
if (rpc_connect(tsg->rpc) < 0)
{
WLog_ERR(TAG, "rpc_connect failed!");
return FALSE;