mirror of https://github.com/FreeRDP/FreeRDP
Modified transport_check_fds to deliver all available PDUs before returning to the caller. This prevents the caller from waiting indefinitely for a socket to get signalled that data is available. It fixes a problem with Microsoft mobile clients connecting to FreeRDS whereby the client places both the MCS Erect Domain and MCS Attach User PDUs into the same ethernet frame. As a result, FreeRDS was only processing the first PDU and then blocking indefinitely waiting for data to arrive on the socket.
This commit is contained in:
parent
b4b6a2171d
commit
1daea0d0dc
|
@ -853,115 +853,125 @@ int transport_check_fds(rdpTransport* transport)
|
|||
#endif
|
||||
ResetEvent(transport->ReceiveEvent);
|
||||
|
||||
status = transport_read_nonblocking(transport);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
while ((pos = Stream_GetPosition(transport->ReceiveBuffer)) > 0)
|
||||
/**
|
||||
* Loop through and read all available PDUs. Since multiple
|
||||
* PDUs can exist, it's important to deliver them all before
|
||||
* returning. Otherwise we run the risk of having a thread
|
||||
* wait for a socket to get signalled that data is available
|
||||
* (which may never happen).
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, 0);
|
||||
status = transport_read_nonblocking(transport);
|
||||
|
||||
if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */
|
||||
{
|
||||
/* Ensure the TPKT header is available. */
|
||||
if (pos <= 4)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = tpkt_read_header(transport->ReceiveBuffer);
|
||||
}
|
||||
else if (nla_verify_header(transport->ReceiveBuffer))
|
||||
{
|
||||
/* TSRequest */
|
||||
|
||||
/* Ensure the TSRequest header is available. */
|
||||
if (pos <= 4)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TSRequest header can be 2, 3 or 4 bytes long */
|
||||
length = nla_header_length(transport->ReceiveBuffer);
|
||||
|
||||
if (pos < length)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = nla_read_header(transport->ReceiveBuffer);
|
||||
}
|
||||
else /* Fast Path */
|
||||
{
|
||||
/* Ensure the Fast Path header is available. */
|
||||
if (pos <= 2)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fastpath header can be two or three bytes long. */
|
||||
length = fastpath_header_length(transport->ReceiveBuffer);
|
||||
|
||||
if (pos < length)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = fastpath_read_header(NULL, transport->ReceiveBuffer);
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
fprintf(stderr, "transport_check_fds: protocol error, not a TPKT or Fast Path header.\n");
|
||||
winpr_HexDump(Stream_Buffer(transport->ReceiveBuffer), pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pos < length)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0; /* Packet is not yet completely received. */
|
||||
}
|
||||
|
||||
received = transport->ReceiveBuffer;
|
||||
transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0);
|
||||
|
||||
Stream_SetPosition(received, length);
|
||||
Stream_SealLength(received);
|
||||
Stream_SetPosition(received, 0);
|
||||
|
||||
/**
|
||||
* status:
|
||||
* -1: error
|
||||
* 0: success
|
||||
* 1: redirection
|
||||
*/
|
||||
|
||||
recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra);
|
||||
|
||||
if (recv_status == 1)
|
||||
{
|
||||
/**
|
||||
* Last call to ReceiveCallback resulted in a session redirection,
|
||||
* which means the current rdpTransport* transport pointer has been freed.
|
||||
* Return 0 for success, the rest of this function is meant for non-redirected cases.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
Stream_Release(received);
|
||||
|
||||
if (recv_status < 0)
|
||||
status = -1;
|
||||
|
||||
if (status < 0)
|
||||
if (status <= 0)
|
||||
return status;
|
||||
|
||||
while ((pos = Stream_GetPosition(transport->ReceiveBuffer)) > 0)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, 0);
|
||||
|
||||
if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */
|
||||
{
|
||||
/* Ensure the TPKT header is available. */
|
||||
if (pos <= 4)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = tpkt_read_header(transport->ReceiveBuffer);
|
||||
}
|
||||
else if (nla_verify_header(transport->ReceiveBuffer))
|
||||
{
|
||||
/* TSRequest */
|
||||
|
||||
/* Ensure the TSRequest header is available. */
|
||||
if (pos <= 4)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TSRequest header can be 2, 3 or 4 bytes long */
|
||||
length = nla_header_length(transport->ReceiveBuffer);
|
||||
|
||||
if (pos < length)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = nla_read_header(transport->ReceiveBuffer);
|
||||
}
|
||||
else /* Fast Path */
|
||||
{
|
||||
/* Ensure the Fast Path header is available. */
|
||||
if (pos <= 2)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fastpath header can be two or three bytes long. */
|
||||
length = fastpath_header_length(transport->ReceiveBuffer);
|
||||
|
||||
if (pos < length)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = fastpath_read_header(NULL, transport->ReceiveBuffer);
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
fprintf(stderr, "transport_check_fds: protocol error, not a TPKT or Fast Path header.\n");
|
||||
winpr_HexDump(Stream_Buffer(transport->ReceiveBuffer), pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pos < length)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0; /* Packet is not yet completely received. */
|
||||
}
|
||||
|
||||
received = transport->ReceiveBuffer;
|
||||
transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0);
|
||||
|
||||
Stream_SetPosition(received, length);
|
||||
Stream_SealLength(received);
|
||||
Stream_SetPosition(received, 0);
|
||||
|
||||
/**
|
||||
* status:
|
||||
* -1: error
|
||||
* 0: success
|
||||
* 1: redirection
|
||||
*/
|
||||
|
||||
recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra);
|
||||
|
||||
if (recv_status == 1)
|
||||
{
|
||||
/**
|
||||
* Last call to ReceiveCallback resulted in a session redirection,
|
||||
* which means the current rdpTransport* transport pointer has been freed.
|
||||
* Return 0 for success, the rest of this function is meant for non-redirected cases.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
Stream_Release(received);
|
||||
|
||||
if (recv_status < 0)
|
||||
status = -1;
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue