int tls_write_all(rdpTls* tls, const BYTE* data, int length) { int status; int offset = 0; BIO* bio = tls->bio; while (offset < length) { status = BIO_write(bio, &data[offset], length - offset); if (status > 0) { offset += status; } else { if (!BIO_should_retry(bio)) return -1; if (BIO_write_blocked(bio)) status = BIO_wait_write(bio, 100); else if (BIO_read_blocked(bio)) status = BIO_wait_read(bio, 100); else USleep(100); if (status < 0) return -1; } } return length; }
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; }
static long rdg_bio_ctrl(BIO* bio, int cmd, long arg1, void* arg2) { int status = 0; rdpRdg* rdg = (rdpRdg*)bio->ptr; rdpTls* tlsOut = rdg->tlsOut; rdpTls* tlsIn = rdg->tlsIn; if (cmd == BIO_CTRL_FLUSH) { (void)BIO_flush(tlsOut->bio); (void)BIO_flush(tlsIn->bio); status = 1; } else if (cmd == BIO_C_GET_EVENT) { if (arg2) { BIO_get_event(rdg->tlsOut->bio, arg2); status = 1; } } else if (cmd == BIO_C_SET_NONBLOCK) { rdg->nonBlocking = arg1; status = 1; } else if (cmd == BIO_C_READ_BLOCKED) { status = 0; } else if (cmd == BIO_C_WRITE_BLOCKED) { status = 0; } else if (cmd == BIO_C_WAIT_READ) { int timeout = (int)arg1; return BIO_wait_read(tlsOut->bio, timeout); } else if (cmd == BIO_C_WAIT_WRITE) { status = 0; } return status; }
static long rdg_bio_ctrl(BIO* bio, int cmd, long arg1, void* arg2) { int status = -1; rdpRdg* rdg = (rdpRdg*) BIO_get_data(bio); rdpTls* tlsOut = rdg->tlsOut; rdpTls* tlsIn = rdg->tlsIn; if (cmd == BIO_CTRL_FLUSH) { (void)BIO_flush(tlsOut->bio); (void)BIO_flush(tlsIn->bio); status = 1; } else if (cmd == BIO_C_SET_NONBLOCK) { status = 1; } else if (cmd == BIO_C_READ_BLOCKED) { BIO* bio = tlsOut->bio; status = BIO_read_blocked(bio); } else if (cmd == BIO_C_WRITE_BLOCKED) { BIO* bio = tlsIn->bio; status = BIO_write_blocked(bio); } else if (cmd == BIO_C_WAIT_READ) { int timeout = (int) arg1; BIO* bio = tlsOut->bio; if (BIO_read_blocked(bio)) return BIO_wait_read(bio, timeout); else if (BIO_write_blocked(bio)) return BIO_wait_write(bio, timeout); else status = 1; } else if (cmd == BIO_C_WAIT_WRITE) { int timeout = (int) arg1; BIO* bio = tlsIn->bio; if (BIO_write_blocked(bio)) status = BIO_wait_write(bio, timeout); else if (BIO_read_blocked(bio)) status = BIO_wait_read(bio, timeout); else status = 1; } else if (cmd == BIO_C_GET_EVENT || cmd == BIO_C_GET_FD) { /* * A note about BIO_C_GET_FD: * Even if two FDs are part of RDG, only one FD can be returned here. * * In FreeRDP, BIO FDs are only used for polling, so it is safe to use the outgoing FD only * * See issue #3602 */ status = BIO_ctrl(tlsOut->bio, cmd, arg1, arg2); } return status; }
static int rdg_read_data_packet(rdpRdg* rdg, BYTE* buffer, int size) { RdgPacketHeader header; size_t readCount = 0; int readSize; int status; if (!rdg->packetRemainingCount) { while (readCount < sizeof(RdgPacketHeader)) { status = BIO_read(rdg->tlsOut->bio, (BYTE*)(&header) + readCount, sizeof(RdgPacketHeader) - readCount); if (status <= 0) { if (!BIO_should_retry(rdg->tlsOut->bio)) return -1; if (!readCount) return 0; BIO_wait_read(rdg->tlsOut->bio, 50); continue; } readCount += status; } if (header.type != PKT_TYPE_DATA) { status = rdg_process_control_packet(rdg, header.type, header.packetLength); if (!status) return -1; return 0; } readCount = 0; while (readCount < 2) { status = BIO_read(rdg->tlsOut->bio, (BYTE*)(&rdg->packetRemainingCount) + readCount, 2 - readCount); if (status < 0) { if (!BIO_should_retry(rdg->tlsOut->bio)) return -1; BIO_wait_read(rdg->tlsOut->bio, 50); continue; } readCount += status; } } readSize = (rdg->packetRemainingCount < size ? rdg->packetRemainingCount : size); status = BIO_read(rdg->tlsOut->bio, buffer, readSize); if (status <= 0) { if (!BIO_should_retry(rdg->tlsOut->bio)) { return -1; } return 0; } rdg->packetRemainingCount -= status; return status; }
static long rdg_bio_ctrl(BIO* bio, int cmd, long arg1, void* arg2) { int status = 0; rdpRdg* rdg = (rdpRdg*) BIO_get_data(bio); rdpTls* tlsOut = rdg->tlsOut; rdpTls* tlsIn = rdg->tlsIn; if (cmd == BIO_CTRL_FLUSH) { (void)BIO_flush(tlsOut->bio); (void)BIO_flush(tlsIn->bio); status = 1; } else if (cmd == BIO_C_GET_EVENT) { if (arg2) { BIO_get_event(rdg->tlsOut->bio, arg2); status = 1; } } else if (cmd == BIO_C_SET_NONBLOCK) { status = 1; } else if (cmd == BIO_C_READ_BLOCKED) { BIO* bio = tlsOut->bio; status = BIO_read_blocked(bio); } else if (cmd == BIO_C_WRITE_BLOCKED) { BIO* bio = tlsIn->bio; status = BIO_write_blocked(bio); } else if (cmd == BIO_C_WAIT_READ) { int timeout = (int) arg1; BIO* bio = tlsOut->bio; if (BIO_read_blocked(bio)) return BIO_wait_read(bio, timeout); else if (BIO_write_blocked(bio)) return BIO_wait_write(bio, timeout); else status = 1; } else if (cmd == BIO_C_WAIT_WRITE) { int timeout = (int) arg1; BIO* bio = tlsIn->bio; if (BIO_write_blocked(bio)) status = BIO_wait_write(bio, timeout); else if (BIO_read_blocked(bio)) status = BIO_wait_read(bio, timeout); else status = 1; } return status; }