parent
58131f1dcc
commit
50589d7657
4 changed files with 0 additions and 1463 deletions
|
@ -1,875 +0,0 @@
|
|||
package org.freedesktop.dbus.bin;
|
||||
|
||||
import org.freedesktop.dbus.Marshalling;
|
||||
import org.freedesktop.dbus.connections.BusAddress;
|
||||
import org.freedesktop.dbus.connections.transports.AbstractTransport;
|
||||
import org.freedesktop.dbus.connections.transports.TransportBuilder;
|
||||
import org.freedesktop.dbus.connections.transports.TransportBuilder.SaslAuthMode;
|
||||
import org.freedesktop.dbus.connections.transports.TransportConnection;
|
||||
import org.freedesktop.dbus.errors.AccessDenied;
|
||||
import org.freedesktop.dbus.errors.Error;
|
||||
import org.freedesktop.dbus.errors.MatchRuleInvalid;
|
||||
import org.freedesktop.dbus.exceptions.DBusException;
|
||||
import org.freedesktop.dbus.exceptions.DBusExecutionException;
|
||||
import org.freedesktop.dbus.interfaces.DBus;
|
||||
import org.freedesktop.dbus.interfaces.DBus.NameOwnerChanged;
|
||||
import org.freedesktop.dbus.interfaces.FatalException;
|
||||
import org.freedesktop.dbus.interfaces.Introspectable;
|
||||
import org.freedesktop.dbus.interfaces.Peer;
|
||||
import org.freedesktop.dbus.messages.DBusSignal;
|
||||
import org.freedesktop.dbus.messages.Message;
|
||||
import org.freedesktop.dbus.messages.MethodCall;
|
||||
import org.freedesktop.dbus.messages.MethodReturn;
|
||||
import org.freedesktop.dbus.types.UInt32;
|
||||
import org.freedesktop.dbus.types.Variant;
|
||||
import org.freedesktop.dbus.utils.Hexdump;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.BlockingDeque;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* A replacement DBusDaemon
|
||||
*/
|
||||
public class DBusDaemon extends Thread implements Closeable {
|
||||
public static final int QUEUE_POLL_WAIT = 500;
|
||||
|
||||
private static final Logger LOGGER =
|
||||
LoggerFactory.getLogger(DBusDaemon.class);
|
||||
|
||||
private final Map<ConnectionStruct, DBusDaemonReaderThread> conns =
|
||||
new ConcurrentHashMap<>();
|
||||
private final Map<String, ConnectionStruct> names =
|
||||
Collections.synchronizedMap(new HashMap<>()); // required because of "null" key
|
||||
|
||||
private final BlockingDeque<Pair<Message, WeakReference<ConnectionStruct>>> outqueue =
|
||||
new LinkedBlockingDeque<>();
|
||||
private final BlockingDeque<Pair<Message, WeakReference<ConnectionStruct>>> inqueue =
|
||||
new LinkedBlockingDeque<>();
|
||||
|
||||
private final List<ConnectionStruct> sigrecips = new ArrayList<>();
|
||||
private final DBusServer dbusServer = new DBusServer();
|
||||
|
||||
private final DBusDaemonSenderThread sender =
|
||||
new DBusDaemonSenderThread();
|
||||
private final AtomicBoolean run =
|
||||
new AtomicBoolean(false);
|
||||
private final AtomicInteger nextUnique = new AtomicInteger(0);
|
||||
|
||||
private final AbstractTransport transport;
|
||||
|
||||
public DBusDaemon(AbstractTransport _transport) {
|
||||
setName(getClass().getSimpleName() + "-Thread");
|
||||
transport = _transport;
|
||||
names.put("org.freedesktop.DBus", null);
|
||||
}
|
||||
|
||||
private void send(ConnectionStruct _connStruct, Message _msg) {
|
||||
send(_connStruct, _msg, false);
|
||||
}
|
||||
|
||||
private void send(ConnectionStruct _connStruct, Message _msg, boolean _head) {
|
||||
|
||||
// send to all connections
|
||||
if (null == _connStruct) {
|
||||
LOGGER.trace("Queuing message {} for all connections", _msg);
|
||||
synchronized (conns) {
|
||||
for (ConnectionStruct d : conns.keySet()) {
|
||||
if (_head) {
|
||||
outqueue.addFirst(new Pair<>(_msg, new WeakReference<>(d)));
|
||||
} else {
|
||||
outqueue.addLast(new Pair<>(_msg, new WeakReference<>(d)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOGGER.trace("Queuing message {} for {}", _msg, _connStruct.unique);
|
||||
if (_head) {
|
||||
outqueue.addFirst(new Pair<>(_msg, new WeakReference<>(_connStruct)));
|
||||
} else {
|
||||
outqueue.addLast(new Pair<>(_msg, new WeakReference<>(_connStruct)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
run.set(true);
|
||||
sender.start();
|
||||
|
||||
while (isRunning()) {
|
||||
try {
|
||||
Pair<Message, WeakReference<ConnectionStruct>> pollFirst = inqueue.take();
|
||||
ConnectionStruct connectionStruct = pollFirst.second.get();
|
||||
if (connectionStruct != null) {
|
||||
Message m = pollFirst.first;
|
||||
logMessage("<inqueue> Got message {} from {}", m, connectionStruct.unique);
|
||||
|
||||
// check if they have hello'd
|
||||
if (null == connectionStruct.unique && (!(m instanceof MethodCall) || !"org.freedesktop.DBus".equals(m.getDestination()) || !"Hello".equals(m.getName()))) {
|
||||
send(connectionStruct, new Error("org.freedesktop.DBus", null, "org.freedesktop.DBus.Error.AccessDenied", m.getSerial(), "s", "You must send a Hello message"));
|
||||
} else {
|
||||
try {
|
||||
if (null != connectionStruct.unique) {
|
||||
m.setSource(connectionStruct.unique);
|
||||
LOGGER.trace("Updated source to {}", connectionStruct.unique);
|
||||
}
|
||||
} catch (DBusException _ex) {
|
||||
LOGGER.debug("Error setting source", _ex);
|
||||
send(connectionStruct, new Error("org.freedesktop.DBus", null, "org.freedesktop.DBus.Error.GeneralError", m.getSerial(), "s", "Sending message failed"));
|
||||
}
|
||||
|
||||
if ("org.freedesktop.DBus".equals(m.getDestination())) {
|
||||
dbusServer.handleMessage(connectionStruct, pollFirst.first);
|
||||
} else {
|
||||
if (m instanceof DBusSignal) {
|
||||
List<ConnectionStruct> l;
|
||||
synchronized (sigrecips) {
|
||||
l = new ArrayList<>(sigrecips);
|
||||
}
|
||||
List<ConnectionStruct> list = l;
|
||||
for (ConnectionStruct d : list) {
|
||||
send(d, m);
|
||||
}
|
||||
} else {
|
||||
ConnectionStruct dest = names.get(m.getDestination());
|
||||
|
||||
if (null == dest) {
|
||||
send(connectionStruct, new Error("org.freedesktop.DBus", null,
|
||||
"org.freedesktop.DBus.Error.ServiceUnknown", m.getSerial(), "s",
|
||||
String.format("The name `%s' does not exist", m.getDestination())));
|
||||
} else {
|
||||
send(dest, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (DBusException _ex) {
|
||||
LOGGER.debug("Error processing connection", _ex);
|
||||
} catch (InterruptedException _ex) {
|
||||
LOGGER.debug("Interrupted");
|
||||
close();
|
||||
interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void logMessage(String _logStr, Message _m, String _connUniqueId) {
|
||||
Object logMsg = _m;
|
||||
if (_m != null && Introspectable.class.getName().equals(_m.getInterface()) && !LOGGER.isTraceEnabled()) {
|
||||
logMsg = "<Introspection data only visible in loglevel trace>";
|
||||
}
|
||||
|
||||
if (LOGGER.isTraceEnabled()) {
|
||||
LOGGER.trace(_logStr, logMsg, _connUniqueId);
|
||||
} else {
|
||||
LOGGER.debug(_logStr, _m, _connUniqueId);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean isRunning() {
|
||||
return run.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
run.set(false);
|
||||
if (!conns.isEmpty()) {
|
||||
// disconnect all remaining connection
|
||||
Set<ConnectionStruct> connections = new HashSet<>(conns.keySet());
|
||||
for (ConnectionStruct c : connections) {
|
||||
removeConnection(c);
|
||||
}
|
||||
}
|
||||
sender.terminate();
|
||||
if (transport != null && transport.isConnected()) {
|
||||
LOGGER.debug("Terminating transport {}", transport);
|
||||
try {
|
||||
// shutdown listener
|
||||
transport.close();
|
||||
} catch (IOException _ex) {
|
||||
LOGGER.debug("Error closing transport", _ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeConnection(ConnectionStruct _c) {
|
||||
|
||||
boolean exists = false;
|
||||
synchronized (conns) {
|
||||
if (conns.containsKey(_c)) {
|
||||
DBusDaemonReaderThread r = conns.get(_c);
|
||||
exists = true;
|
||||
r.terminate();
|
||||
conns.remove(_c);
|
||||
}
|
||||
}
|
||||
if (exists) {
|
||||
try {
|
||||
if (null != _c.connection) {
|
||||
_c.connection.close();
|
||||
}
|
||||
} catch (IOException _exIo) {
|
||||
LOGGER.trace("Error while closing socketchannel", _exIo);
|
||||
}
|
||||
|
||||
synchronized (names) {
|
||||
List<String> toRemove = new ArrayList<>();
|
||||
for (String name : names.keySet()) {
|
||||
if (names.get(name) == _c) {
|
||||
toRemove.add(name);
|
||||
try {
|
||||
send(null, new NameOwnerChanged("/org/freedesktop/DBus", name, _c.unique, ""));
|
||||
} catch (DBusException _ex) {
|
||||
LOGGER.debug("", _ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String name : toRemove) {
|
||||
names.remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void addSock(TransportConnection _s) throws IOException {
|
||||
LOGGER.debug("New Client");
|
||||
|
||||
ConnectionStruct c = new ConnectionStruct(_s);
|
||||
DBusDaemonReaderThread r = new DBusDaemonReaderThread(c);
|
||||
conns.put(c, r);
|
||||
r.start();
|
||||
}
|
||||
|
||||
public static void syntax() {
|
||||
System.out.println("Syntax: DBusDaemon [--version] [-v] [--help] [-h] [--listen address] "
|
||||
+ "[-l address] [--print-address] [-r] [--pidfile file] [-p file] [--addressfile file] "
|
||||
+ "[--auth-mode AUTH_ANONYMOUS|AUTH_COOKIE|AUTH_EXTERNAL] [-m AUTH_ANONYMOUS|AUTH_COOKIE|AUTH_EXTERNAL]"
|
||||
+ "[-a file] [--unix] [-u] [--tcp] [-t] ");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
public static void version() {
|
||||
System.out.println("D-Bus Java Version: " + System.getProperty("Version"));
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
public static void saveFile(String _data, String _file) throws IOException {
|
||||
try (PrintWriter w = new PrintWriter(new FileOutputStream(_file))) {
|
||||
w.println(_data);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] _args) throws Exception {
|
||||
|
||||
String addr = null;
|
||||
String pidfile = null;
|
||||
String addrfile = null;
|
||||
String authModeStr = null;
|
||||
boolean printaddress = false;
|
||||
boolean unix = true;
|
||||
boolean tcp = false;
|
||||
// parse options
|
||||
try {
|
||||
for (int i = 0; i < _args.length; i++) {
|
||||
if ("--help".equals(_args[i]) || "-h".equals(_args[i])) {
|
||||
syntax();
|
||||
} else if ("--version".equals(_args[i]) || "-v".equals(_args[i])) {
|
||||
version();
|
||||
} else if ("--listen".equals(_args[i]) || "-l".equals(_args[i])) {
|
||||
addr = _args[++i];
|
||||
} else if ("--pidfile".equals(_args[i]) || "-p".equals(_args[i])) {
|
||||
pidfile = _args[++i];
|
||||
} else if ("--addressfile".equals(_args[i]) || "-a".equals(_args[i])) {
|
||||
addrfile = _args[++i];
|
||||
} else if ("--print-address".equals(_args[i]) || "-r".equals(_args[i])) {
|
||||
printaddress = true;
|
||||
} else if ("--unix".equals(_args[i]) || "-u".equals(_args[i])) {
|
||||
unix = true;
|
||||
tcp = false;
|
||||
} else if ("--tcp".equals(_args[i]) || "-t".equals(_args[i])) {
|
||||
tcp = true;
|
||||
unix = false;
|
||||
} else if ("--auth-mode".equals(_args[i]) || "-m".equals(_args[i])) {
|
||||
authModeStr = _args[++i];
|
||||
} else {
|
||||
syntax();
|
||||
}
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException _ex) {
|
||||
syntax();
|
||||
}
|
||||
|
||||
// generate a random address if none specified
|
||||
if (null == addr && unix) {
|
||||
addr = TransportBuilder.createDynamicSession("UNIX", true);
|
||||
} else if (null == addr && tcp) {
|
||||
addr = TransportBuilder.createDynamicSession("TCP", true);
|
||||
}
|
||||
|
||||
BusAddress address = BusAddress.of(addr);
|
||||
|
||||
// print address to stdout
|
||||
if (printaddress) {
|
||||
System.out.println(addr);
|
||||
}
|
||||
|
||||
SaslAuthMode saslAuthMode = null;
|
||||
if (authModeStr != null) {
|
||||
String selectedMode = authModeStr;
|
||||
saslAuthMode = Arrays.stream(SaslAuthMode.values())
|
||||
.filter(e -> e.name().toLowerCase().matches(selectedMode.toLowerCase()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Auth mode '" + selectedMode + "' unsupported"));
|
||||
}
|
||||
|
||||
// print address to file
|
||||
if (null != addrfile) {
|
||||
saveFile(addr, addrfile);
|
||||
}
|
||||
|
||||
// print PID to file
|
||||
if (null != pidfile) {
|
||||
saveFile(System.getProperty("Pid"), pidfile);
|
||||
}
|
||||
|
||||
// start the daemon
|
||||
LOGGER.info("Binding to {}", addr);
|
||||
try (EmbeddedDBusDaemon daemon = new EmbeddedDBusDaemon(address)) {
|
||||
daemon.setSaslAuthMode(saslAuthMode);
|
||||
daemon.startInForeground();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a 'NameAcquired' signal manually.
|
||||
* This is required because the implementation in DBusNameAquired is for receiving of this signal only.
|
||||
*
|
||||
* @param _name name to announce
|
||||
*
|
||||
* @return signal
|
||||
* @throws DBusException if signal creation fails
|
||||
*/
|
||||
private DBusSignal generateNameAcquiredSignal(String _name) throws DBusException {
|
||||
return new DBusSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameAcquired", "s", _name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a 'NameOwnerChanged' signal manually.
|
||||
* This is required because the implementation in DBusNameAquired is for receiving of this signal only.
|
||||
*
|
||||
* @param _name name to announce
|
||||
* @param _oldOwner previous owner
|
||||
* @param _newOwner new owner
|
||||
*
|
||||
* @return signal
|
||||
* @throws DBusException if signal creation fails
|
||||
*/
|
||||
private DBusSignal generatedNameOwnerChangedSignal(String _name, String _oldOwner, String _newOwner) throws DBusException {
|
||||
return new DBusSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", "sss", _name, _oldOwner, _newOwner);
|
||||
}
|
||||
|
||||
public static class ConnectionStruct {
|
||||
private final TransportConnection connection;
|
||||
private String unique;
|
||||
|
||||
ConnectionStruct(TransportConnection _c) throws IOException {
|
||||
connection = _c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return null == unique ? ":?-?" : unique;
|
||||
}
|
||||
}
|
||||
|
||||
public class DBusServer implements DBus, Introspectable, Peer {
|
||||
|
||||
private final String machineId;
|
||||
private ConnectionStruct connStruct;
|
||||
|
||||
public DBusServer() {
|
||||
String ascii;
|
||||
try {
|
||||
ascii = Hexdump.toAscii(MessageDigest.getInstance("MD5").digest(InetAddress.getLocalHost().getHostName().getBytes()));
|
||||
} catch (NoSuchAlgorithmException | UnknownHostException _ex) {
|
||||
ascii = this.hashCode() + "";
|
||||
}
|
||||
|
||||
machineId = ascii;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRemote() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String Hello() {
|
||||
synchronized (connStruct) {
|
||||
if (null != connStruct.unique) {
|
||||
throw new AccessDenied("Connection has already sent a Hello message");
|
||||
}
|
||||
connStruct.unique = ":1." + nextUnique.incrementAndGet();
|
||||
}
|
||||
names.put(connStruct.unique, connStruct);
|
||||
|
||||
LOGGER.info("Client {} registered", connStruct.unique);
|
||||
|
||||
try {
|
||||
send(connStruct, generateNameAcquiredSignal(connStruct.unique));
|
||||
send(null, generatedNameOwnerChangedSignal(connStruct.unique, "", connStruct.unique));
|
||||
} catch (DBusException _ex) {
|
||||
LOGGER.debug("", _ex);
|
||||
}
|
||||
|
||||
return connStruct.unique;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] ListNames() {
|
||||
String[] ns;
|
||||
Set<String> nss = names.keySet();
|
||||
ns = nss.toArray(new String[0]);
|
||||
return ns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean NameHasOwner(String _name) {
|
||||
return names.containsKey(_name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String GetNameOwner(String _name) {
|
||||
|
||||
ConnectionStruct owner = names.get(_name);
|
||||
String o;
|
||||
if (null == owner) {
|
||||
o = "";
|
||||
} else {
|
||||
o = owner.unique;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UInt32 GetConnectionUnixUser(String _connectionName) {
|
||||
return new UInt32(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UInt32 StartServiceByName(String _name, UInt32 _flags) {
|
||||
return new UInt32(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("checkstyle:innerassignment")
|
||||
public UInt32 RequestName(String _name, UInt32 _flags) {
|
||||
boolean exists = false;
|
||||
synchronized (names) {
|
||||
if (!(exists = names.containsKey(_name))) {
|
||||
names.put(_name, connStruct);
|
||||
}
|
||||
}
|
||||
|
||||
int rv;
|
||||
if (exists) {
|
||||
rv = DBus.DBUS_REQUEST_NAME_REPLY_EXISTS;
|
||||
} else {
|
||||
|
||||
LOGGER.info("Client {} acquired name {}", connStruct.unique, _name);
|
||||
|
||||
rv = DBus.DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
|
||||
try {
|
||||
send(connStruct, generateNameAcquiredSignal(_name));
|
||||
send(null, generatedNameOwnerChangedSignal(_name, "", connStruct.unique));
|
||||
} catch (DBusException _ex) {
|
||||
LOGGER.debug("", _ex);
|
||||
}
|
||||
}
|
||||
return new UInt32(rv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UInt32 ReleaseName(String _name) {
|
||||
|
||||
boolean exists = false;
|
||||
synchronized (names) {
|
||||
if (names.containsKey(_name) && names.get(_name).equals(connStruct)) {
|
||||
exists = names.remove(_name) != null;
|
||||
}
|
||||
}
|
||||
|
||||
int rv;
|
||||
if (!exists) {
|
||||
rv = DBus.DBUS_RELEASE_NAME_REPLY_NON_EXISTANT;
|
||||
} else {
|
||||
LOGGER.info("Client {} acquired name {}", connStruct.unique, _name);
|
||||
rv = DBus.DBUS_RELEASE_NAME_REPLY_RELEASED;
|
||||
try {
|
||||
send(connStruct, new NameLost("/org/freedesktop/DBus", _name));
|
||||
send(null, new NameOwnerChanged("/org/freedesktop/DBus", _name, connStruct.unique, ""));
|
||||
} catch (DBusException _ex) {
|
||||
LOGGER.debug("", _ex);
|
||||
}
|
||||
}
|
||||
|
||||
return new UInt32(rv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void AddMatch(String _matchrule) throws MatchRuleInvalid {
|
||||
|
||||
LOGGER.trace("Adding match rule: {}", _matchrule);
|
||||
|
||||
synchronized (sigrecips) {
|
||||
if (!sigrecips.contains(connStruct)) {
|
||||
sigrecips.add(connStruct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void RemoveMatch(String _matchrule) throws MatchRuleInvalid {
|
||||
LOGGER.trace("Removing match rule: {}", _matchrule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] ListQueuedOwners(String _name) {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public UInt32 GetConnectionUnixProcessID(String _connectionName) {
|
||||
return new UInt32(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte[] GetConnectionSELinuxSecurityContext(String _args) {
|
||||
return new Byte[0];
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleMessage(ConnectionStruct _connStruct, Message _msg) throws DBusException {
|
||||
LOGGER.trace("Handling message {} from {}", _msg, _connStruct.unique);
|
||||
|
||||
if (!(_msg instanceof MethodCall)) {
|
||||
return;
|
||||
}
|
||||
Object[] args = _msg.getParameters();
|
||||
|
||||
Class<? extends Object>[] cs = new Class[args.length];
|
||||
|
||||
for (int i = 0; i < cs.length; i++) {
|
||||
cs[i] = args[i].getClass();
|
||||
}
|
||||
|
||||
java.lang.reflect.Method meth = null;
|
||||
Object rv = null;
|
||||
|
||||
try {
|
||||
meth = DBusServer.class.getMethod(_msg.getName(), cs);
|
||||
try {
|
||||
this.connStruct = _connStruct;
|
||||
rv = meth.invoke(dbusServer, args);
|
||||
if (null == rv) {
|
||||
|
||||
send(_connStruct, new MethodReturn("org.freedesktop.DBus", (MethodCall) _msg, null), true);
|
||||
} else {
|
||||
String sig = Marshalling.getDBusType(meth.getGenericReturnType())[0];
|
||||
send(_connStruct, new MethodReturn("org.freedesktop.DBus", (MethodCall) _msg, sig, rv), true);
|
||||
}
|
||||
} catch (InvocationTargetException _exIte) {
|
||||
LOGGER.debug("", _exIte);
|
||||
send(_connStruct, new Error("org.freedesktop.DBus", _msg, _exIte.getCause()));
|
||||
} catch (DBusExecutionException _exDnEe) {
|
||||
LOGGER.debug("", _exDnEe);
|
||||
send(_connStruct, new Error("org.freedesktop.DBus", _msg, _exDnEe));
|
||||
} catch (Exception _ex) {
|
||||
LOGGER.debug("", _ex);
|
||||
send(_connStruct, new Error("org.freedesktop.DBus", _connStruct.unique,
|
||||
"org.freedesktop.DBus.Error.GeneralError", _msg.getSerial(), "s", "An error occurred while calling " + _msg.getName()));
|
||||
}
|
||||
} catch (NoSuchMethodException _exNsm) {
|
||||
send(_connStruct, new Error("org.freedesktop.DBus", _connStruct.unique,
|
||||
"org.freedesktop.DBus.Error.UnknownMethod", _msg.getSerial(), "s", "This service does not support " + _msg.getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObjectPath() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String Introspect() {
|
||||
return "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
|
||||
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
|
||||
+ "<node>\n"
|
||||
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
|
||||
+ " <method name=\"Introspect\">\n"
|
||||
+ " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " </interface>\n"
|
||||
+ " <interface name=\"org.freedesktop.DBus\">\n"
|
||||
+ " <method name=\"RequestName\">\n"
|
||||
+ " <arg direction=\"in\" type=\"s\"/>\n"
|
||||
+ " <arg direction=\"in\" type=\"u\"/>\n"
|
||||
+ " <arg direction=\"out\" type=\"u\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"ReleaseName\">\n"
|
||||
+ " <arg direction=\"in\" type=\"s\"/>\n"
|
||||
+ " <arg direction=\"out\" type=\"u\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"StartServiceByName\">\n"
|
||||
+ " <arg direction=\"in\" type=\"s\"/>\n"
|
||||
+ " <arg direction=\"in\" type=\"u\"/>\n"
|
||||
+ " <arg direction=\"out\" type=\"u\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"Hello\">\n"
|
||||
+ " <arg direction=\"out\" type=\"s\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"NameHasOwner\">\n"
|
||||
+ " <arg direction=\"in\" type=\"s\"/>\n"
|
||||
+ " <arg direction=\"out\" type=\"b\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"ListNames\">\n"
|
||||
+ " <arg direction=\"out\" type=\"as\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"ListActivatableNames\">\n"
|
||||
+ " <arg direction=\"out\" type=\"as\"/>\n"
|
||||
+ " </method>\n" + " <method name=\"AddMatch\">\n"
|
||||
+ " <arg direction=\"in\" type=\"s\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"RemoveMatch\">\n"
|
||||
+ " <arg direction=\"in\" type=\"s\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"GetNameOwner\">\n"
|
||||
+ " <arg direction=\"in\" type=\"s\"/>\n"
|
||||
+ " <arg direction=\"out\" type=\"s\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"ListQueuedOwners\">\n"
|
||||
+ " <arg direction=\"in\" type=\"s\"/>\n"
|
||||
+ " <arg direction=\"out\" type=\"as\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"GetConnectionUnixUser\">\n"
|
||||
+ " <arg direction=\"in\" type=\"s\"/>\n"
|
||||
+ " <arg direction=\"out\" type=\"u\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"GetConnectionUnixProcessID\">\n"
|
||||
+ " <arg direction=\"in\" type=\"s\"/>\n"
|
||||
+ " <arg direction=\"out\" type=\"u\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
|
||||
+ " <arg direction=\"in\" type=\"s\"/>\n"
|
||||
+ " <arg direction=\"out\" type=\"ay\"/>\n"
|
||||
+ " </method>\n"
|
||||
+ " <method name=\"ReloadConfig\">\n"
|
||||
+ " </method>\n"
|
||||
+ " <signal name=\"NameOwnerChanged\">\n"
|
||||
+ " <arg type=\"s\"/>\n"
|
||||
+ " <arg type=\"s\"/>\n"
|
||||
+ " <arg type=\"s\"/>\n"
|
||||
+ " </signal>\n"
|
||||
+ " <signal name=\"NameLost\">\n"
|
||||
+ " <arg type=\"s\"/>\n"
|
||||
+ " </signal>\n"
|
||||
+ " <signal name=\"NameAcquired\">\n"
|
||||
+ " <arg type=\"s\"/>\n"
|
||||
+ " </signal>\n"
|
||||
+ " </interface>\n" + "</node>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void Ping() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] ListActivatableNames() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Variant<?>> GetConnectionCredentials(String _busName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte[] GetAdtAuditSessionData(String _busName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void UpdateActivationEnvironment(Map<String, String>[] _environment) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String GetId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String GetMachineId() {
|
||||
return machineId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class DBusDaemonSenderThread extends Thread {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private final AtomicBoolean running = new AtomicBoolean(false); // switch running status when thread begins
|
||||
|
||||
public DBusDaemonSenderThread() {
|
||||
setName(getClass().getSimpleName().replace('$', '-'));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
logger.debug(">>>> Sender thread started <<<<");
|
||||
running.set(true);
|
||||
while (isRunning() && running.get()) {
|
||||
|
||||
logger.trace("Acquiring lock on outqueue and blocking for data");
|
||||
|
||||
// block on outqueue
|
||||
try {
|
||||
Pair<Message, WeakReference<ConnectionStruct>> pollFirst = outqueue.take();
|
||||
if (pollFirst != null) {
|
||||
ConnectionStruct connectionStruct = pollFirst.second.get();
|
||||
if (connectionStruct != null) {
|
||||
if (connectionStruct.connection.getChannel().isConnected()) {
|
||||
logger.debug("<outqueue> Got message {} for {}", pollFirst.first, connectionStruct.unique);
|
||||
|
||||
try {
|
||||
connectionStruct.connection.getWriter().writeMessage(pollFirst.first);
|
||||
} catch (IOException _ex) {
|
||||
logger.debug("Disconnecting client due to previous exception", _ex);
|
||||
removeConnection(connectionStruct);
|
||||
}
|
||||
} else {
|
||||
logger.warn("Connection to {} broken", pollFirst.first.getDestination());
|
||||
removeConnection(connectionStruct);
|
||||
}
|
||||
|
||||
} else {
|
||||
logger.info("Discarding {} connection reaped", pollFirst.first);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException _ex) {
|
||||
logger.debug("Got interrupted", _ex);
|
||||
}
|
||||
}
|
||||
logger.debug(">>>> Sender Thread terminated <<<<");
|
||||
}
|
||||
|
||||
public synchronized void terminate() {
|
||||
running.set(false);
|
||||
interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public class DBusDaemonReaderThread extends Thread {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private ConnectionStruct conn;
|
||||
private final WeakReference<ConnectionStruct> weakconn;
|
||||
private final AtomicBoolean running = new AtomicBoolean(false);
|
||||
|
||||
public DBusDaemonReaderThread(ConnectionStruct _conn) {
|
||||
this.conn = _conn;
|
||||
weakconn = new WeakReference<>(_conn);
|
||||
setName(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
running.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
logger.debug(">>>> Reader Thread started <<<<");
|
||||
running.set(true);
|
||||
while (isRunning() && running.get()) {
|
||||
|
||||
Message m = null;
|
||||
try {
|
||||
m = conn.connection.getReader().readMessage();
|
||||
} catch (IOException _ex) {
|
||||
LOGGER.debug("", _ex);
|
||||
removeConnection(conn);
|
||||
} catch (DBusException _ex) {
|
||||
LOGGER.debug("", _ex);
|
||||
if (_ex instanceof FatalException) {
|
||||
removeConnection(conn);
|
||||
}
|
||||
}
|
||||
|
||||
if (null != m) {
|
||||
logMessage("Read {} from {}", m, conn.unique);
|
||||
|
||||
inqueue.add(new Pair<>(m, weakconn));
|
||||
}
|
||||
}
|
||||
conn = null;
|
||||
logger.debug(">>>> Reader Thread terminated <<<<");
|
||||
}
|
||||
}
|
||||
|
||||
static class Pair<A, B> {
|
||||
private final A first;
|
||||
private final B second;
|
||||
|
||||
Pair(A _first, B _second) {
|
||||
first = _first;
|
||||
second = _second;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(first, second);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object _obj) {
|
||||
if (this == _obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(_obj instanceof Pair)) {
|
||||
return false;
|
||||
}
|
||||
Pair<?, ?> other = (Pair<?, ?>) _obj;
|
||||
return Objects.equals(first, other.first) && Objects.equals(second, other.second);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,224 +0,0 @@
|
|||
package org.freedesktop.dbus.bin;
|
||||
|
||||
import org.freedesktop.dbus.connections.BusAddress;
|
||||
import org.freedesktop.dbus.connections.transports.AbstractTransport;
|
||||
import org.freedesktop.dbus.connections.transports.TransportBuilder;
|
||||
import org.freedesktop.dbus.connections.transports.TransportBuilder.SaslAuthMode;
|
||||
import org.freedesktop.dbus.connections.transports.TransportConnection;
|
||||
import org.freedesktop.dbus.exceptions.AuthenticationException;
|
||||
import org.freedesktop.dbus.exceptions.DBusException;
|
||||
import org.freedesktop.dbus.exceptions.SocketClosedException;
|
||||
import org.freedesktop.dbus.utils.Util;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Simple DBusDaemon implementation to use if no DBusDaemon is running on the OS level.
|
||||
*/
|
||||
public class EmbeddedDBusDaemon implements Closeable {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(EmbeddedDBusDaemon.class);
|
||||
|
||||
private final BusAddress address;
|
||||
|
||||
private DBusDaemon daemon;
|
||||
|
||||
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||
private final AtomicBoolean connectionReady = new AtomicBoolean(false);
|
||||
|
||||
private SaslAuthMode saslAuthMode;
|
||||
|
||||
private String unixSocketFileOwner;
|
||||
|
||||
private String unixSocketFileGroup;
|
||||
|
||||
private PosixFilePermission[] unixSocketFilePermissions;
|
||||
|
||||
public EmbeddedDBusDaemon(BusAddress _address) {
|
||||
// create copy of address so manipulation happens later does not interfere with our instance
|
||||
address = BusAddress.of(Objects.requireNonNull(_address, "Address required"));
|
||||
}
|
||||
|
||||
public EmbeddedDBusDaemon(String _address) throws DBusException {
|
||||
this(BusAddress.of(_address));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the running DBusDaemon instance.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
closed.set(true);
|
||||
connectionReady.set(false);
|
||||
if (daemon != null) {
|
||||
daemon.close();
|
||||
daemon = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the DBusDaemon in foreground.
|
||||
* <p>
|
||||
* This is a blocking operation.
|
||||
*/
|
||||
public void startInForeground() {
|
||||
try {
|
||||
startListening();
|
||||
} catch (IOException | DBusException _ex) {
|
||||
if (!closed.get()) {
|
||||
throw new RuntimeException(_ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the DBusDaemon in background and returns immediately.
|
||||
* <p>
|
||||
* This method may return before the background thread is ready.
|
||||
* To ensure the the background thread is running on return use {@link #startInBackgroundAndWait(long)}.
|
||||
*/
|
||||
public void startInBackground() {
|
||||
Thread thread = new Thread(this::startInForeground);
|
||||
String threadName = address.toString().replaceAll("^([^,]+),.+", "$1");
|
||||
|
||||
thread.setName("EmbeddedDBusDaemon-" + threadName);
|
||||
thread.setDaemon(true);
|
||||
thread.setUncaughtExceptionHandler((th, ex) -> LOGGER.error("Got uncaught exception", ex));
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the DBusDaemon in background.
|
||||
* <p>
|
||||
* Will wait up to the given period of milliseconds for the background thread to get ready.
|
||||
* If given wait time exceeded, a {@link RuntimeException} is thrown.
|
||||
*
|
||||
* @param _maxWaitMillis maximum wait time in milliseconds
|
||||
*/
|
||||
public void startInBackgroundAndWait(long _maxWaitMillis) {
|
||||
startInBackground();
|
||||
Util.waitFor("EmbeddedDbusDaemon", this::isRunning, _maxWaitMillis, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the DBusDaemon is still running.
|
||||
*
|
||||
* @return true if running, false otherwise
|
||||
*/
|
||||
public synchronized boolean isRunning() {
|
||||
return connectionReady.get() && daemon != null && daemon.isRunning();
|
||||
}
|
||||
|
||||
/**
|
||||
* The currently configured {@link SaslAuthMode}.
|
||||
* When null is returned, the {@link SaslAuthMode} of the transport provider is used.
|
||||
*
|
||||
* @return {@link SaslAuthMode} or null
|
||||
*/
|
||||
public SaslAuthMode getSaslAuthMode() {
|
||||
return saslAuthMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to override the default authentication mode which would
|
||||
* be used by the transport based on the {@link BusAddress}.
|
||||
*
|
||||
* @param _saslAuthMode auth mode, null to use default
|
||||
*/
|
||||
public void setSaslAuthMode(SaslAuthMode _saslAuthMode) {
|
||||
saslAuthMode = _saslAuthMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* The file owner for the created unix socket.<br>
|
||||
* Ignored if TCP is used.<br>
|
||||
* <br>
|
||||
* Will only work if currently running JVM process user
|
||||
* has suitable permissions to change the owner.
|
||||
*
|
||||
* @param _owner owner to set
|
||||
*/
|
||||
public void setUnixSocketOwner(String _owner) {
|
||||
unixSocketFileOwner = _owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* The file group for the created unix socket.<br>
|
||||
* Ignored if TCP is used.<br>
|
||||
* <br>
|
||||
* Will only work if currently running JVM process user
|
||||
* has suitable permissions to change the group.
|
||||
*
|
||||
* @param _group group to set
|
||||
*/
|
||||
public void setUnixSocketGroup(String _group) {
|
||||
unixSocketFileGroup = _group;
|
||||
}
|
||||
|
||||
/**
|
||||
* The file permissions for the created unix socket.<br>
|
||||
* Ignored if TCP is used or if the OS is Windows.<br>
|
||||
* <br>
|
||||
* Will only work if currently running JVM process user
|
||||
* has suitable permissions to change the permissions.
|
||||
*
|
||||
* @param _permissions permissions to set
|
||||
*/
|
||||
public void setUnixSocketPermissions(PosixFilePermission... _permissions) {
|
||||
unixSocketFilePermissions = _permissions;
|
||||
}
|
||||
|
||||
private synchronized void setDaemonAndStart(AbstractTransport _transport) {
|
||||
daemon = new DBusDaemon(_transport);
|
||||
daemon.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening for incoming connections.
|
||||
* <p>
|
||||
* Will throw {@link IllegalArgumentException} if a unsupported transport is used.
|
||||
*
|
||||
* @throws IOException when connection fails
|
||||
* @throws DBusException when the provided bus address is wrong
|
||||
*/
|
||||
private void startListening() throws IOException, DBusException {
|
||||
if (!TransportBuilder.getRegisteredBusTypes().contains(address.getBusType())) {
|
||||
throw new IllegalArgumentException("Unknown or unsupported address type: " + address.getType());
|
||||
}
|
||||
|
||||
LOGGER.debug("About to initialize transport on: {}", address);
|
||||
try (AbstractTransport transport = TransportBuilder.create(address).configure()
|
||||
.withUnixSocketFileOwner(unixSocketFileOwner)
|
||||
.withUnixSocketFileGroup(unixSocketFileGroup)
|
||||
.withUnixSocketFilePermissions(unixSocketFilePermissions)
|
||||
.withAutoConnect(false)
|
||||
.configureSasl().withAuthMode(getSaslAuthMode()).back()
|
||||
.back()
|
||||
.build()) {
|
||||
|
||||
setDaemonAndStart(transport);
|
||||
|
||||
// use tail-controlled loop so we at least try to get a client connection once
|
||||
do {
|
||||
try {
|
||||
LOGGER.debug("Begin listening to: {}", transport);
|
||||
connectionReady.set(true);
|
||||
TransportConnection s = transport.listen();
|
||||
daemon.addSock(s);
|
||||
} catch (AuthenticationException _ex) {
|
||||
LOGGER.error("Authentication failed", _ex);
|
||||
} catch (SocketClosedException _ex) {
|
||||
LOGGER.debug("Connection closed", _ex);
|
||||
}
|
||||
|
||||
} while (daemon.isRunning());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,300 +0,0 @@
|
|||
package org.freedesktop.dbus.connections.impl;
|
||||
|
||||
import static org.freedesktop.dbus.utils.CommonRegexPattern.IFACE_PATTERN;
|
||||
import static org.freedesktop.dbus.utils.CommonRegexPattern.PROXY_SPLIT_PATTERN;
|
||||
|
||||
import org.freedesktop.dbus.DBusMatchRule;
|
||||
import org.freedesktop.dbus.RemoteInvocationHandler;
|
||||
import org.freedesktop.dbus.RemoteObject;
|
||||
import org.freedesktop.dbus.connections.AbstractConnection;
|
||||
import org.freedesktop.dbus.connections.BusAddress;
|
||||
import org.freedesktop.dbus.connections.config.ReceivingServiceConfig;
|
||||
import org.freedesktop.dbus.connections.config.TransportConfig;
|
||||
import org.freedesktop.dbus.exceptions.DBusException;
|
||||
import org.freedesktop.dbus.interfaces.DBusInterface;
|
||||
import org.freedesktop.dbus.interfaces.DBusSigHandler;
|
||||
import org.freedesktop.dbus.interfaces.Introspectable;
|
||||
import org.freedesktop.dbus.messages.DBusSignal;
|
||||
import org.freedesktop.dbus.messages.ExportedObject;
|
||||
import org.freedesktop.dbus.utils.Hexdump;
|
||||
import org.freedesktop.dbus.utils.Util;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Handles a peer to peer connection between two applications without a bus daemon.
|
||||
* <p>
|
||||
* Signal Handlers and method calls from remote objects are run in their own threads, you MUST handle the concurrency issues.
|
||||
* </p>
|
||||
*/
|
||||
public class DirectConnection extends AbstractConnection {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private final String machineId;
|
||||
|
||||
/**
|
||||
* Create a direct connection to another application.
|
||||
* @param _address The address to connect to. This is a standard D-Bus address, except that the additional parameter 'listen=true' should be added in the application which is creating the socket.
|
||||
* @throws DBusException on error
|
||||
* @deprecated use {@link DirectConnectionBuilder}
|
||||
*/
|
||||
@Deprecated(since = "4.1.0", forRemoval = true)
|
||||
public DirectConnection(String _address) throws DBusException {
|
||||
this(_address, AbstractConnection.TCP_CONNECT_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a direct connection to another application.
|
||||
* @param _address The address to connect to. This is a standard D-Bus address, except that the additional parameter 'listen=true' should be added in the application which is creating the socket.
|
||||
* @param _timeout the timeout set for the underlying socket. 0 will block forever on the underlying socket.
|
||||
* @throws DBusException on error
|
||||
* @deprecated use {@link DirectConnectionBuilder}
|
||||
*/
|
||||
@Deprecated(since = "4.1.0", forRemoval = true)
|
||||
public DirectConnection(String _address, int _timeout) throws DBusException {
|
||||
this(createTransportConfig(_address, _timeout), null);
|
||||
}
|
||||
|
||||
DirectConnection(TransportConfig _transportCfg, ReceivingServiceConfig _rsCfg) throws DBusException {
|
||||
super(_transportCfg, _rsCfg);
|
||||
machineId = createMachineId();
|
||||
if (!getAddress().isServer()) {
|
||||
super.listen();
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(since = "4.2.0", forRemoval = true)
|
||||
static TransportConfig createTransportConfig(String _address, int _timeout) {
|
||||
TransportConfig cfg = new TransportConfig();
|
||||
cfg.setBusAddress(BusAddress.of(_address));
|
||||
cfg.getAdditionalConfig().put("TIMEOUT", _timeout);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method when running on server side.
|
||||
* Call will block.
|
||||
*/
|
||||
@Override
|
||||
public void listen() {
|
||||
if (getAddress().isServer()) {
|
||||
super.listen();
|
||||
}
|
||||
}
|
||||
|
||||
private String createMachineId() {
|
||||
String ascii;
|
||||
|
||||
try {
|
||||
ascii = Hexdump.toAscii(MessageDigest.getInstance("MD5").digest(InetAddress.getLocalHost().getHostName().getBytes()));
|
||||
return ascii;
|
||||
} catch (NoSuchAlgorithmException _ex) {
|
||||
logger.trace("MD5 algorithm not present", _ex);
|
||||
} catch (UnknownHostException _ex) {
|
||||
logger.trace("Unable to determine this machines hostname", _ex);
|
||||
}
|
||||
|
||||
return Util.randomString(32);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T extends DBusInterface> T dynamicProxy(String _path, Class<T> _type) throws DBusException {
|
||||
try {
|
||||
Introspectable intro = getRemoteObject(_path, Introspectable.class);
|
||||
String data = intro.Introspect();
|
||||
|
||||
String[] tags = PROXY_SPLIT_PATTERN.split(data);
|
||||
|
||||
List<String> ifaces = Arrays.stream(tags).filter(t -> t.startsWith("interface"))
|
||||
.map(t -> IFACE_PATTERN.matcher(t).replaceAll("$1"))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<Class<?>> ifcs = findMatchingTypes(_type, ifaces);
|
||||
|
||||
if (ifcs.isEmpty()) {
|
||||
throw new DBusException("Could not find an interface to cast to");
|
||||
}
|
||||
|
||||
RemoteObject ro = new RemoteObject(null, _path, _type, false);
|
||||
DBusInterface newi = (DBusInterface) Proxy.newProxyInstance(ifcs.get(0).getClassLoader(), ifcs.toArray(new Class[0]), new RemoteInvocationHandler(this, ro));
|
||||
getImportedObjects().put(newi, ro);
|
||||
return (T) newi;
|
||||
} catch (Exception _ex) {
|
||||
logger.debug("", _ex);
|
||||
throw new DBusException(String.format("Failed to create proxy object for %s; reason: %s.", _path, _ex.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T extends DBusInterface> T getExportedObject(String _path, Class<T> _type) throws DBusException {
|
||||
ExportedObject o = null;
|
||||
synchronized (getExportedObjects()) {
|
||||
o = getExportedObjects().get(_path);
|
||||
}
|
||||
if (null != o && null == o.getObject().get()) {
|
||||
unExportObject(_path);
|
||||
o = null;
|
||||
}
|
||||
if (null != o) {
|
||||
return (T) o.getObject().get();
|
||||
}
|
||||
return dynamicProxy(_path, _type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a reference to a remote object.
|
||||
* This method will always refer to the well known name (if given) rather than resolving it to a unique bus name.
|
||||
* In particular this means that if a process providing the well known name disappears and is taken over by another process
|
||||
* proxy objects gained by this method will make calls on the new proccess.
|
||||
*
|
||||
* This method will use bus introspection to determine the interfaces on a remote object and so
|
||||
* <b>may block</b> and <b>may fail</b>. The resulting proxy object will, however, be castable
|
||||
* to any interface it implements. It will also autostart the process if applicable. Also note
|
||||
* that the resulting proxy may fail to execute the correct method with overloaded methods
|
||||
* and that complex types may fail in interesting ways. Basically, if something odd happens,
|
||||
* try specifying the interface explicitly.
|
||||
*
|
||||
* @param _objectPath The path on which the process is exporting the object.
|
||||
* @return A reference to a remote object.
|
||||
* @throws ClassCastException If type is not a sub-type of DBusInterface
|
||||
* @throws DBusException If busname or objectpath are incorrectly formatted.
|
||||
*/
|
||||
public DBusInterface getRemoteObject(String _objectPath) throws DBusException {
|
||||
if (null == _objectPath) {
|
||||
throw new DBusException("Invalid object path: null");
|
||||
}
|
||||
|
||||
if (_objectPath.length() > MAX_NAME_LENGTH || !OBJECT_REGEX_PATTERN.matcher(_objectPath).matches()) {
|
||||
throw new DBusException("Invalid object path: " + _objectPath);
|
||||
}
|
||||
|
||||
return dynamicProxy(_objectPath, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a reference to a remote object.
|
||||
* This method will always refer to the well known name (if given) rather than resolving it to a unique bus name.
|
||||
* In particular this means that if a process providing the well known name disappears and is taken over by another process
|
||||
* proxy objects gained by this method will make calls on the new proccess.
|
||||
* @param _objectPath The path on which the process is exporting the object.
|
||||
* @param _type The interface they are exporting it on. This type must have the same full class name and exposed method signatures
|
||||
* as the interface the remote object is exporting.
|
||||
* @param <T> class which extends DBusInterface
|
||||
* @return A reference to a remote object.
|
||||
* @throws ClassCastException If type is not a sub-type of DBusInterface
|
||||
* @throws DBusException If busname or objectpath are incorrectly formatted or type is not in a package.
|
||||
*/
|
||||
public <T extends DBusInterface> T getRemoteObject(String _objectPath, Class<T> _type) throws DBusException {
|
||||
if (null == _objectPath) {
|
||||
throw new DBusException("Invalid object path: null");
|
||||
}
|
||||
if (null == _type) {
|
||||
throw new ClassCastException("Not A DBus Interface");
|
||||
}
|
||||
|
||||
if (_objectPath.length() > MAX_NAME_LENGTH || !OBJECT_REGEX_PATTERN.matcher(_objectPath).matches()) {
|
||||
throw new DBusException("Invalid object path: " + _objectPath);
|
||||
}
|
||||
|
||||
if (!DBusInterface.class.isAssignableFrom(_type)) {
|
||||
throw new ClassCastException("Not A DBus Interface");
|
||||
}
|
||||
|
||||
// don't let people import things which don't have a
|
||||
// valid D-Bus interface name
|
||||
if (_type.getName().equals(_type.getSimpleName())) {
|
||||
throw new DBusException("DBusInterfaces cannot be declared outside a package");
|
||||
}
|
||||
|
||||
RemoteObject ro = new RemoteObject(null, _objectPath, _type, false);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T i = (T) Proxy.newProxyInstance(_type.getClassLoader(),
|
||||
new Class[] {_type}, new RemoteInvocationHandler(this, ro));
|
||||
|
||||
getImportedObjects().put(i, ro);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T extends DBusSignal> void removeSigHandler(DBusMatchRule _rule, DBusSigHandler<T> _handler) throws DBusException {
|
||||
Queue<DBusSigHandler<? extends DBusSignal>> v = getHandledSignals().get(_rule);
|
||||
if (null != v) {
|
||||
v.remove(_handler);
|
||||
if (0 == v.size()) {
|
||||
getHandledSignals().remove(_rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T extends DBusSignal> AutoCloseable addSigHandler(DBusMatchRule _rule, DBusSigHandler<T> _handler) throws DBusException {
|
||||
Queue<DBusSigHandler<? extends DBusSignal>> v =
|
||||
getHandledSignals().computeIfAbsent(_rule, val -> {
|
||||
Queue<DBusSigHandler<? extends DBusSignal>> l = new ConcurrentLinkedQueue<>();
|
||||
return l;
|
||||
});
|
||||
|
||||
v.add(_handler);
|
||||
return new AutoCloseable() {
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
removeSigHandler(_rule, _handler);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeGenericSigHandler(DBusMatchRule _rule, DBusSigHandler<DBusSignal> _handler) throws DBusException {
|
||||
Queue<DBusSigHandler<DBusSignal>> v = getGenericHandledSignals().get(_rule);
|
||||
if (null != v) {
|
||||
v.remove(_handler);
|
||||
if (0 == v.size()) {
|
||||
getGenericHandledSignals().remove(_rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AutoCloseable addGenericSigHandler(DBusMatchRule _rule, DBusSigHandler<DBusSignal> _handler) throws DBusException {
|
||||
Queue<DBusSigHandler<DBusSignal>> v =
|
||||
getGenericHandledSignals().computeIfAbsent(_rule, val -> {
|
||||
Queue<DBusSigHandler<DBusSignal>> l = new ConcurrentLinkedQueue<>();
|
||||
return l;
|
||||
});
|
||||
|
||||
v.add(_handler);
|
||||
return new AutoCloseable() {
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
removeGenericSigHandler(_rule, _handler);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends DBusInterface> T getExportedObject(String _source, String _path, Class<T> _type) throws DBusException {
|
||||
return getExportedObject(_path, _type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMachineId() {
|
||||
return machineId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBusInterface getExportedObject(String _source, String _path) throws DBusException {
|
||||
return getExportedObject(_path, (Class<DBusInterface>) null);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
package org.freedesktop.dbus.connections.impl;
|
||||
|
||||
import org.freedesktop.dbus.connections.BusAddress;
|
||||
import org.freedesktop.dbus.connections.config.ReceivingServiceConfig;
|
||||
import org.freedesktop.dbus.connections.config.TransportConfig;
|
||||
import org.freedesktop.dbus.exceptions.DBusException;
|
||||
import org.freedesktop.dbus.messages.Message;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Builder to create a new DirectConnection.
|
||||
*
|
||||
* @author hypfvieh
|
||||
* @version 4.1.0 - 2022-02-04
|
||||
*/
|
||||
public final class DirectConnectionBuilder extends BaseConnectionBuilder<DirectConnectionBuilder, DirectConnection> {
|
||||
|
||||
private DirectConnectionBuilder(BusAddress _address) {
|
||||
super(DirectConnectionBuilder.class, _address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given address to create the connection (e.g. used for remote TCP connected DBus daemons).
|
||||
*
|
||||
* @param _address address to use
|
||||
* @return this
|
||||
*/
|
||||
public static DirectConnectionBuilder forAddress(String _address) {
|
||||
DirectConnectionBuilder instance = new DirectConnectionBuilder(BusAddress.of(_address));
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the new {@link DBusConnection}.
|
||||
*
|
||||
* @return {@link DBusConnection}
|
||||
* @throws DBusException when DBusConnection could not be opened
|
||||
*/
|
||||
@Override
|
||||
public DirectConnection build() throws DBusException {
|
||||
ReceivingServiceConfig rsCfg = buildThreadConfig();
|
||||
TransportConfig transportCfg = buildTransportConfig();
|
||||
|
||||
DirectConnection c = new DirectConnection(transportCfg, rsCfg);
|
||||
c.setDisconnectCallback(getDisconnectCallback());
|
||||
c.setWeakReferences(isWeakReference());
|
||||
DirectConnection.setEndianness(getEndianess());
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default system endianness.
|
||||
*
|
||||
* @return LITTLE or BIG
|
||||
* @deprecated if required, use {@link BaseConnectionBuilder#getSystemEndianness()}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "4.2.0")
|
||||
public static byte getSystemEndianness() {
|
||||
return ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN)
|
||||
? Message.Endian.BIG
|
||||
: Message.Endian.LITTLE;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue