int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes) { int read = 0; int status = -1; if (!transport->frontBio) { transport->layer = TRANSPORT_LAYER_CLOSED; return -1; } while (read < bytes) { status = BIO_read(transport->frontBio, data + read, bytes - read); if (status <= 0) { if (!transport->frontBio || !BIO_should_retry(transport->frontBio)) { /* something unexpected happened, let's close */ if (!transport->frontBio) { WLog_Print(transport->log, WLOG_ERROR, "BIO_read: transport->frontBio null"); return -1; } WLog_ERR_BIO(transport, "BIO_read", transport->frontBio); transport->layer = TRANSPORT_LAYER_CLOSED; return -1; } /* non blocking will survive a partial read */ if (!transport->blocking) return read; /* blocking means that we can't continue until we have read the number of requested bytes */ if (BIO_wait_read(transport->frontBio, 100) < 0) { WLog_ERR_BIO(transport, "BIO_wait_read", transport->frontBio); return -1; } continue; } #ifdef HAVE_VALGRIND_MEMCHECK_H VALGRIND_MAKE_MEM_DEFINED(data + read, bytes - read); #endif read += status; } return read; }
int transport_write(rdpTransport* transport, wStream* s) { int length; int status = -1; int writtenlength = 0; EnterCriticalSection(&(transport->WriteLock)); length = Stream_GetPosition(s); writtenlength = length; Stream_SetPosition(s, 0); if (length > 0) { WLog_Packet(WLog_Get(TAG), WLOG_TRACE, Stream_Buffer(s), length, WLOG_PACKET_OUTBOUND); } while (length > 0) { status = BIO_write(transport->frontBio, Stream_Pointer(s), length); if (status <= 0) { /* the buffered BIO that is at the end of the chain always says OK for writing, * so a retry means that for any reason we need to read. The most probable * is a SSL or TSG BIO in the chain. */ if (!BIO_should_retry(transport->frontBio)) { WLog_ERR_BIO(TAG, "BIO_should_retry", transport->frontBio); goto out_cleanup; } /* non-blocking can live with blocked IOs */ if (!transport->blocking) { WLog_ERR_BIO(TAG, "BIO_write", transport->frontBio); goto out_cleanup; } if (BIO_wait_write(transport->frontBio, 100) < 0) { WLog_ERR_BIO(TAG, "BIO_wait_write", transport->frontBio); status = -1; goto out_cleanup; } continue; } if (transport->blocking || transport->settings->WaitForOutputBufferFlush) { while (BIO_write_blocked(transport->frontBio)) { if (BIO_wait_write(transport->frontBio, 100) < 0) { WLog_ERR(TAG, "error when selecting for write"); status = -1; goto out_cleanup; } if (BIO_flush(transport->frontBio) < 1) { WLog_ERR(TAG, "error when flushing outputBuffer"); status = -1; goto out_cleanup; } } } length -= status; Stream_Seek(s, status); } transport->written += writtenlength; out_cleanup: if (status < 0) { /* A write error indicates that the peer has dropped the connection */ transport->layer = TRANSPORT_LAYER_CLOSED; } if (s->pool) Stream_Release(s); LeaveCriticalSection(&(transport->WriteLock)); return status; }