
org.freedesktop.dbus.spi.message.AbstractInputStreamMessageReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dbus-java-osgi Show documentation
Show all versions of dbus-java-osgi Show documentation
Improved version of the DBus-Java library provided by freedesktop.org (https://dbus.freedesktop.org/doc/dbus-java/).
This is the OSGi compliant bundle of all required libraries in one bundle.
The newest version!
package org.freedesktop.dbus.spi.message;
import org.freedesktop.dbus.FileDescriptor;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.MessageProtocolVersionException;
import org.freedesktop.dbus.messages.Message;
import org.freedesktop.dbus.messages.MessageFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.EOFException;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.*;
/**
* Base class which can be used to implement a custom message reader.
*
* @since 4.3.1 - 2023-08-07
*/
public abstract class AbstractInputStreamMessageReader implements IMessageReader {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final int[] len;
private final byte[] buf;
private final byte[] tbuf;
private final SocketChannel inputChannel;
private byte[] header;
private byte[] body;
private final ISocketProvider socketProviderImpl;
protected AbstractInputStreamMessageReader(final SocketChannel _in, ISocketProvider _socketProviderImpl) {
socketProviderImpl = Objects.requireNonNull(_socketProviderImpl, "ISocketProvider implementation required");
inputChannel = Objects.requireNonNull(_in, "SocketChannel required");
len = new int[4];
tbuf = new byte[4];
buf = new byte[12];
len[1] = 0;
len[0] = 0;
}
@Override
public final Message readMessage() throws IOException, DBusException {
/* Read the 12 byte fixed header, retrying as necessary */
if (len[0] < 12) {
try {
final ByteBuffer wrapBuf = ByteBuffer.wrap(buf, len[0], 12 - len[0]);
final int rv = inputChannel.read(wrapBuf);
if (rv < 0) {
throw new EOFException("(1) Underlying transport returned " + rv);
}
len[0] += rv;
} catch (SocketTimeoutException _ex) {
return null;
}
}
if (len[0] == 0) {
return null;
}
if (len[0] < 12) {
logger.trace("Only got {} of 12 bytes of header", len[0]);
return null;
}
/* Ensure protocol version. */
final byte protoVer = buf[3];
if (protoVer > Message.PROTOCOL) {
throw new MessageProtocolVersionException(String.format("Protocol version %s is unsupported", protoVer));
}
if (len[1] < 4) {
try {
final int rv = inputChannel.read(ByteBuffer.wrap(tbuf, len[1], 4 - len[1]));
if (rv < 0) {
throw new EOFException("(2) Underlying transport returned " + rv);
}
len[1] += rv;
} catch (SocketTimeoutException _ex) {
return null;
}
}
if (len[1] < 4) {
logger.trace("Only got {} of 4 bytes of header", len[1]);
return null;
}
final byte endian = buf[0];
/* Parse the variable header length */
int headerlen;
if (header == null) {
headerlen = (int) Message.demarshallint(tbuf, 0, endian, 4);
/* n % 2^i = n & (2^i - 1) */
final int modlen = headerlen & 7;
if (modlen != 0) {
headerlen += 8 - modlen;
}
} else {
headerlen = header.length - 8;
}
/* Read the variable header */
if (header == null) {
header = new byte[headerlen + 8];
System.arraycopy(tbuf, 0, header, 0, 4);
len[2] = 0;
}
if (len[2] < headerlen) {
try {
final int rv = inputChannel.read(ByteBuffer.wrap(header, 8 + len[2], headerlen - len[2]));
if (rv < 0) {
throw new EOFException("(3) Underlying transport returned " + rv);
}
len[2] += rv;
} catch (SocketTimeoutException _ex) {
return null;
}
}
if (len[2] < headerlen) {
logger.trace("Only got {} of {} bytes of header", len[2], headerlen);
return null;
}
final byte type = buf[1];
/* Read the body */
if (body == null) {
body = new byte[(int) Message.demarshallint(buf, 4, endian, 4)];
len[3] = 0;
}
if (len[3] < body.length) {
try {
final int rv = inputChannel.read(ByteBuffer.wrap(body, len[3], body.length - len[3]));
if (rv < 0) {
throw new EOFException("(4) Underlying transport returned " + rv);
}
len[3] += rv;
} catch (SocketTimeoutException _ex) {
return null;
}
}
if (len[3] < body.length) {
logger.trace("Only got {} of {} bytes of body", len[3], body.length);
return null;
}
try {
List fds = null;
if (socketProviderImpl.isFileDescriptorPassingSupported()) {
fds = readFileDescriptors(inputChannel);
}
final Message m = MessageFactory.createMessage(type, buf, header, body, fds);
logger.debug("=> {}", m);
return m;
} catch (DBusException | RuntimeException _ex) {
logger.warn("Exception while creating message.", _ex);
throw _ex;
} finally {
Arrays.fill(tbuf, (byte) 0x00);
len[1] = 0;
body = null;
header = null;
Arrays.fill(buf, (byte) 0x00);
len[0] = 0;
}
}
/**
* Methods which will be called when file descriptor passing is enabled.
* The implementation should fetch all file descriptors which have been transmitted and return them
* as List.
* If no file descriptor is available or feature is not supported, return null.
*
* @param _inputChannel input channel to read
* @return List or null
*
* @throws DBusException when reading throws exceptions
*/
protected abstract List readFileDescriptors(SocketChannel _inputChannel) throws DBusException;
protected Logger getLogger() {
return logger;
}
protected ISocketProvider getSocketProviderImpl() {
return socketProviderImpl;
}
@Override
public void close() throws IOException {
if (inputChannel.isOpen()) {
logger.trace("Closing Message Reader");
inputChannel.close();
}
}
@Override
public boolean isClosed() {
return !inputChannel.isOpen();
}
@Override
public String toString() {
return getClass().getSimpleName() + " [inputChannel=" + inputChannel + ", socketProviderImpl=" + socketProviderImpl + "]";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy