com.tigervnc.rdr.FdInStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sikulix2tigervnc Show documentation
Show all versions of sikulix2tigervnc Show documentation
... for visual testing and automation (TigerVNC support)
The newest version!
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2012,2014 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package com.tigervnc.rdr;
import com.tigervnc.network.*;
import java.nio.channels.Selector;
import java.nio.channels.SelectionKey;
import java.util.Set;
import java.util.Iterator;
public class FdInStream extends InStream {
static final int DEFAULT_BUF_SIZE = 16384;
static final int minBulkSize = 1024;
public FdInStream(FileDescriptor fd_, int timeoutms_, int bufSize_,
boolean closeWhenDone_)
{
fd = fd_; closeWhenDone = closeWhenDone_;
timeoutms = timeoutms_; blockCallback = null;
timing = false; timeWaitedIn100us = 5; timedKbits = 0;
bufSize = ((bufSize_ > 0) ? bufSize_ : DEFAULT_BUF_SIZE);
b = new byte[bufSize];
ptr = end = offset = 0;
}
public FdInStream(FileDescriptor fd_) { this(fd_, -1, 0, false); }
public FdInStream(FileDescriptor fd_, FdInStreamBlockCallback blockCallback_,
int bufSize_)
{
fd = fd_; timeoutms = 0; blockCallback = blockCallback_;
timing = false; timeWaitedIn100us = 5; timedKbits = 0;
bufSize = ((bufSize_ > 0) ? bufSize_ : DEFAULT_BUF_SIZE);
b = new byte[bufSize];
ptr = end = offset = 0;
}
public FdInStream(FileDescriptor fd_,
FdInStreamBlockCallback blockCallback_) {
this(fd_, blockCallback_, 0);
}
public final void readBytes(byte[] data, int dataPtr, int length) {
if (length < minBulkSize) {
super.readBytes(data, dataPtr, length);
return;
}
int n = end - ptr;
if (n > length) n = length;
System.arraycopy(b, ptr, data, dataPtr, n);
dataPtr += n;
length -= n;
ptr += n;
while (length > 0) {
n = readWithTimeoutOrCallback(data, dataPtr, length);
dataPtr += n;
length -= n;
offset += n;
}
}
public void setTimeout(int timeoutms_) {
timeoutms = timeoutms_;
}
public void setBlockCallback(FdInStreamBlockCallback blockCallback_)
{
blockCallback = blockCallback_;
timeoutms = 0;
}
public final int pos() { return offset + ptr; }
public final void startTiming() {
timing = true;
// Carry over up to 1s worth of previous rate for smoothing.
if (timeWaitedIn100us > 10000) {
timedKbits = timedKbits * 10000 / timeWaitedIn100us;
timeWaitedIn100us = 10000;
}
}
public final void stopTiming() {
timing = false;
if (timeWaitedIn100us < timedKbits/2)
timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s
}
public final long kbitsPerSecond() {
return timedKbits * 10000 / timeWaitedIn100us;
}
public final long timeWaited() { return timeWaitedIn100us; }
protected int overrun(int itemSize, int nItems, boolean wait)
{
if (itemSize > bufSize)
throw new Exception("FdInStream overrun: max itemSize exceeded");
if (end - ptr != 0)
System.arraycopy(b, ptr, b, 0, end - ptr);
offset += ptr;
end -= ptr;
ptr = 0;
int bytes_to_read;
while (end < itemSize) {
bytes_to_read = bufSize - end;
if (!timing) {
// When not timing, we must be careful not to read too much
// extra data into the buffer. Otherwise, the line speed
// estimation might stay at zero for a long time: All reads
// during timing=1 can be satisfied without calling
// readWithTimeoutOrCallback. However, reading only 1 or 2 bytes
// bytes is ineffecient.
bytes_to_read = Math.min(bytes_to_read, Math.max(itemSize*nItems, 8));
}
int n = readWithTimeoutOrCallback(b, end, bytes_to_read, wait);
if (n == 0) return 0;
end += n;
}
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}
protected int readWithTimeoutOrCallback(byte[] buf, int bufPtr, int len, boolean wait) {
long before = 0;
if (timing)
before = System.nanoTime();
int n;
while (true) {
do {
Integer tv;
if (!wait) {
tv = new Integer(0);
} else if (timeoutms != -1) {
tv = new Integer(timeoutms);
} else {
tv = null;
}
try {
n = fd.select(SelectionKey.OP_READ, tv);
} catch (Exception e) {
throw new SystemException("select:"+e.toString());
}
} while (n < 0);
if (n > 0) break;
if (!wait) return 0;
if (blockCallback == null) throw new TimedOut();
blockCallback.blockCallback();
}
try {
n = fd.read(buf, bufPtr, len);
} catch (Exception e) {
throw new SystemException("read:"+e.toString());
}
if (n == 0) throw new EndOfStream();
if (timing) {
long after = System.nanoTime();
long newTimeWaited = (after - before) / 100000;
int newKbits = n * 8 / 1000;
// limit rate to between 10kbit/s and 40Mbit/s
if (newTimeWaited > newKbits*1000) {
newTimeWaited = newKbits*1000;
} else if (newTimeWaited < newKbits/4) {
newTimeWaited = newKbits/4;
}
timeWaitedIn100us += newTimeWaited;
timedKbits += newKbits;
}
return n;
}
private int readWithTimeoutOrCallback(byte[] buf, int bufPtr, int len) {
return readWithTimeoutOrCallback(buf, bufPtr, len, true);
}
public FileDescriptor getFd() {
return fd;
}
public void setFd(FileDescriptor fd_) {
fd = fd_;
}
public int getBufSize() {
return bufSize;
}
private FileDescriptor fd;
boolean closeWhenDone;
protected int timeoutms;
private FdInStreamBlockCallback blockCallback;
private int offset;
private int bufSize;
protected boolean timing;
protected long timeWaitedIn100us;
protected long timedKbits;
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy