static int transport_bio_buffered_write(BIO* bio, const char* buf, int num) { int i, ret; int status; int nchunks; int committedBytes; DataChunk chunks[2]; WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*) bio->ptr; ret = num; ptr->writeBlocked = FALSE; BIO_clear_flags(bio, BIO_FLAGS_WRITE); /* we directly append extra bytes in the xmit buffer, this could be prevented * but for now it makes the code more simple. */ if (buf && num && !ringbuffer_write(&ptr->xmitBuffer, (const BYTE*) buf, num)) { WLog_ERR(TAG, "an error occured when writing (num: %d)", num); return -1; } committedBytes = 0; nchunks = ringbuffer_peek(&ptr->xmitBuffer, chunks, ringbuffer_used(&ptr->xmitBuffer)); for (i = 0; i < nchunks; i++) { while (chunks[i].size) { status = BIO_write(bio->next_bio, chunks[i].data, chunks[i].size); if (status <= 0) { if (!BIO_should_retry(bio->next_bio)) { BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); ret = -1; /* fatal error */ goto out; } if (BIO_should_write(bio->next_bio)) { BIO_set_flags(bio, BIO_FLAGS_WRITE); ptr->writeBlocked = TRUE; goto out; /* EWOULDBLOCK */ } } committedBytes += status; chunks[i].size -= status; chunks[i].data += status; } } out: ringbuffer_commit_read_bytes(&ptr->xmitBuffer, committedBytes); return ret; }
static int transport_bio_buffered_write(BIO* bio, const char* buf, int num) { int status, ret; rdpTcp* tcp = (rdpTcp*) bio->ptr; int nchunks, committedBytes, i; DataChunk chunks[2]; ret = num; tcp->writeBlocked = FALSE; BIO_clear_flags(bio, BIO_FLAGS_WRITE); /* we directly append extra bytes in the xmit buffer, this could be prevented * but for now it makes the code more simple. */ if (buf && num && !ringbuffer_write(&tcp->xmitBuffer, (const BYTE*) buf, num)) { fprintf(stderr, "%s: an error occured when writing(toWrite=%d)\n", __FUNCTION__, num); return -1; } committedBytes = 0; nchunks = ringbuffer_peek(&tcp->xmitBuffer, chunks, ringbuffer_used(&tcp->xmitBuffer)); for (i = 0; i < nchunks; i++) { while (chunks[i].size) { status = BIO_write(bio->next_bio, chunks[i].data, chunks[i].size); if (status <= 0) { if (!BIO_should_retry(bio->next_bio)) { BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); ret = -1; /* fatal error */ goto out; } if (BIO_should_write(bio->next_bio)) { BIO_set_flags(bio, BIO_FLAGS_WRITE); tcp->writeBlocked = TRUE; goto out; /* EWOULDBLOCK */ } } committedBytes += status; chunks[i].size -= status; chunks[i].data += status; } } out: ringbuffer_commit_read_bytes(&tcp->xmitBuffer, committedBytes); return ret; }
int tcp_attach(rdpTcp* tcp, int sockfd) { tcp->sockfd = sockfd; SetEventFileDescriptor(tcp->event, tcp->sockfd); ringbuffer_commit_read_bytes(&tcp->xmitBuffer, ringbuffer_used(&tcp->xmitBuffer)); if (tcp->socketBio) { if (BIO_set_fd(tcp->socketBio, sockfd, 1) < 0) return -1; } else { tcp->socketBio = BIO_new(BIO_s_simple_socket()); if (!tcp->socketBio) return -1; BIO_set_fd(tcp->socketBio, sockfd, BIO_CLOSE); } if (!tcp->bufferedBio) { tcp->bufferedBio = BIO_new(BIO_s_buffered_socket()); if (!tcp->bufferedBio) return FALSE; tcp->bufferedBio->ptr = tcp; tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio); } return 0; }
int tls_write_all(rdpTls* tls, const BYTE* data, int length) { int status, nchunks, commitedBytes; rdpTcp *tcp; #ifdef HAVE_POLL_H struct pollfd pollfds; #else fd_set rset, wset; fd_set *rsetPtr, *wsetPtr; struct timeval tv; #endif BIO* bio = tls->bio; DataChunk chunks[2]; BIO* bufferedBio = findBufferedBio(bio); if (!bufferedBio) { DEBUG_WARN( "%s: error unable to retrieve the bufferedBio in the BIO chain\n", __FUNCTION__); return -1; } tcp = (rdpTcp*) bufferedBio->ptr; do { status = BIO_write(bio, data, length); if (status > 0) break; if (!BIO_should_retry(bio)) return -1; #ifdef HAVE_POLL_H pollfds.fd = tcp->sockfd; pollfds.revents = 0; pollfds.events = 0; if (tcp->writeBlocked) { pollfds.events |= POLLOUT; } else if (tcp->readBlocked) { pollfds.events |= POLLIN; } else { DEBUG_WARN( "%s: weird we're blocked but the underlying is not read or write blocked !\n", __FUNCTION__); USleep(10); continue; } do { status = poll(&pollfds, 1, 100); } while ((status < 0) && (errno == EINTR)); #else /* we try to handle SSL want_read and want_write nicely */ rsetPtr = wsetPtr = NULL; if (tcp->writeBlocked) { wsetPtr = &wset; FD_ZERO(&wset); FD_SET(tcp->sockfd, &wset); } else if (tcp->readBlocked) { rsetPtr = &rset; FD_ZERO(&rset); FD_SET(tcp->sockfd, &rset); } else { DEBUG_WARN( "%s: weird we're blocked but the underlying is not read or write blocked !\n", __FUNCTION__); USleep(10); continue; } tv.tv_sec = 0; tv.tv_usec = 100 * 1000; status = _select(tcp->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv); #endif if (status < 0) return -1; } while (TRUE); /* make sure the output buffer is empty */ commitedBytes = 0; while ((nchunks = ringbuffer_peek(&tcp->xmitBuffer, chunks, ringbuffer_used(&tcp->xmitBuffer)))) { int i; for (i = 0; i < nchunks; i++) { while (chunks[i].size) { status = BIO_write(tcp->socketBio, chunks[i].data, chunks[i].size); if (status > 0) { chunks[i].size -= status; chunks[i].data += status; commitedBytes += status; continue; } if (!BIO_should_retry(tcp->socketBio)) goto out_fail; #ifdef HAVE_POLL_H pollfds.fd = tcp->sockfd; pollfds.events = POLLIN; pollfds.revents = 0; do { status = poll(&pollfds, 1, 100); } while ((status < 0) && (errno == EINTR)); #else FD_ZERO(&rset); FD_SET(tcp->sockfd, &rset); tv.tv_sec = 0; tv.tv_usec = 100 * 1000; status = _select(tcp->sockfd + 1, &rset, NULL, NULL, &tv); #endif if (status < 0) goto out_fail; } } } ringbuffer_commit_read_bytes(&tcp->xmitBuffer, commitedBytes); return length; out_fail: ringbuffer_commit_read_bytes(&tcp->xmitBuffer, commitedBytes); return -1; }