/* D-Bus Java Implementation Copyright (c) 2005-2006 Matthew Johnson This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 2 or the Academic Free Licence Version 2.1. Full licence texts are included in the COPYING file with this program. */ package org.freedesktop.dbus.bin; import static org.freedesktop.dbus.Gettext._; import org.freedesktop.DBus; import org.freedesktop.dbus.AbstractConnection; import org.freedesktop.dbus.BusAddress; import org.freedesktop.dbus.DBusSignal; import org.freedesktop.dbus.DirectConnection; import org.freedesktop.dbus.Error; import org.freedesktop.dbus.Marshalling; import org.freedesktop.dbus.Message; import org.freedesktop.dbus.MessageReader; import org.freedesktop.dbus.MessageWriter; import org.freedesktop.dbus.MethodCall; import org.freedesktop.dbus.MethodReturn; import org.freedesktop.dbus.Transport; import org.freedesktop.dbus.UInt32; import org.freedesktop.dbus.exceptions.DBusException; import org.freedesktop.dbus.exceptions.DBusExecutionException; import org.freedesktop.dbus.exceptions.FatalException; 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.ServerSocket; import java.net.Socket; import java.text.MessageFormat; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import cx.ath.matthew.debug.Debug; import cx.ath.matthew.unix.UnixServerSocket; import cx.ath.matthew.unix.UnixSocket; import cx.ath.matthew.unix.UnixSocketAddress; /** * A replacement DBusDaemon */ public class DBusDaemon extends Thread { public static final int QUEUE_POLL_WAIT = 500; static class Connstruct { public UnixSocket usock; public Socket tsock; public MessageReader min; public MessageWriter mout; public String unique; public Connstruct(UnixSocket sock) { this.usock = sock; min = new MessageReader(sock.getInputStream()); mout = new MessageWriter(sock.getOutputStream()); } public Connstruct(Socket sock) throws IOException { this.tsock = sock; min = new MessageReader(sock.getInputStream()); mout = new MessageWriter(sock.getOutputStream()); } public String toString() { return null == unique ? ":?-?" : unique; } } static class MagicMap<A, B> { private Map<A, B> m; private LinkedList<A> q; private String name; public MagicMap(String name) { m = new HashMap<A, B>(); q = new LinkedList<A>(); this.name = name; } public A head() { return q.getFirst(); } public void putFirst(A a, B b) { if (Debug.debug) Debug.print("<"+name+"> Queueing {"+a+" => "+b+"}"); m.put(a, b); q.addFirst(a); } public void putLast(A a, B b) { if (Debug.debug) Debug.print("<"+name+"> Queueing {"+a+" => "+b+"}"); m.put(a, b); q.addLast(a); } public B remove(A a) { if (Debug.debug) Debug.print("<"+name+"> Removing {"+a+"}"); q.remove(a); return m.remove(a); } public int size() { return q.size(); } } public class DBusServer extends Thread implements DBus, DBus.Introspectable, DBus.Peer { public DBusServer() { setName("Server"); } public Connstruct c; public Message m; public boolean isRemote() { return false; } public String Hello() { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); synchronized (c) { if (null != c.unique) throw new org.freedesktop.DBus.Error.AccessDenied(_("Connection has already sent a Hello message")); synchronized (unique_lock) { c.unique = ":1."+(++next_unique); } } synchronized (names) { names.put(c.unique, c); } if (Debug.debug) Debug.print(Debug.WARN, "Client "+c.unique+" registered"); try { send(c, new DBusSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameAcquired", "s", c.unique)); DBusSignal s = new DBusSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", "sss", c.unique, "", c.unique); send(null, s); } catch (DBusException DBe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, DBe); } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return c.unique; } public String[] ListNames() { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); String[] ns; synchronized (names) { Set<String> nss = names.keySet(); ns = nss.toArray(new String[0]); } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return ns; } public boolean NameHasOwner(String name) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); boolean rv; synchronized (names) { rv = names.containsKey(name); } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return rv; } public String GetNameOwner(String name) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); Connstruct owner = names.get(name); String o; if (null == owner) o = ""; else o = owner.unique; if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return o; } public UInt32 GetConnectionUnixUser(String connection_name) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return new UInt32(0); } public UInt32 StartServiceByName(String name, UInt32 flags) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return new UInt32(0); } public UInt32 RequestName(String name, UInt32 flags) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); boolean exists = false; synchronized (names) { if (!(exists = names.containsKey(name))) names.put(name, c); } int rv; if (exists) { rv = DBus.DBUS_REQUEST_NAME_REPLY_EXISTS; } else { if (Debug.debug) Debug.print(Debug.WARN, "Client "+c.unique+" acquired name "+name); rv = DBus.DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; try { send(c, new DBusSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameAcquired", "s", name)); send(null, new DBusSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", "sss", name, "", c.unique)); } catch (DBusException DBe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, DBe); } } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return new UInt32(rv); } public UInt32 ReleaseName(String name) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); boolean exists = false; synchronized (names) { if ((exists = (names.containsKey(name) && names.get(name).equals(c)))) names.remove(name); } int rv; if (exists) { rv = DBus.DBUS_RELEASE_NAME_REPLY_NON_EXISTANT; } else { if (Debug.debug) Debug.print(Debug.WARN, "Client "+c.unique+" acquired name "+name); rv = DBus.DBUS_RELEASE_NAME_REPLY_RELEASED; try { send(c, new DBusSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameLost", "s", name)); send(null, new DBusSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", "sss", name, c.unique, "")); } catch (DBusException DBe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, DBe); } } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return new UInt32(rv); } public void AddMatch(String matchrule) throws Error.MatchRuleInvalid { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); if (Debug.debug) Debug.print(Debug.VERBOSE, "Adding match rule: "+matchrule); synchronized (sigrecips) { if (!sigrecips.contains(c)) sigrecips.add(c); } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return; } public void RemoveMatch(String matchrule) throws Error.MatchRuleInvalid { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); if (Debug.debug) Debug.print(Debug.VERBOSE, "Removing match rule: "+matchrule); if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return; } public String[] ListQueuedOwners(String name) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return new String[0]; } public UInt32 GetConnectionUnixProcessID(String connection_name) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return new UInt32(0); } public Byte[] GetConnectionSELinuxSecurityContext(String a) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return new Byte[0]; } public void ReloadConfig() { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return; } @SuppressWarnings("unchecked") private void handleMessage(Connstruct c, Message m) throws DBusException { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); if (Debug.debug) Debug.print(Debug.VERBOSE, "Handling message "+m+" from "+c.unique); if (!(m instanceof MethodCall)) return; Object[] args = m.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(m.getName(), cs); try { this.c = c; this.m = m; rv = meth.invoke(dbus_server, args); if (null == rv) { send(c, new MethodReturn("org.freedesktop.DBus", (MethodCall) m, null), true); } else { String sig = Marshalling.getDBusType(meth.getGenericReturnType())[0]; send(c, new MethodReturn("org.freedesktop.DBus", (MethodCall) m, sig, rv), true); } } catch (InvocationTargetException ITe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, ITe); if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, ITe.getCause()); send(c, new org.freedesktop.dbus.Error("org.freedesktop.DBus", m, ITe.getCause())); } catch (DBusExecutionException DBEe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, DBEe); send(c, new org.freedesktop.dbus.Error("org.freedesktop.DBus", m, DBEe)); } catch (Exception e) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, e); send(c,new org.freedesktop.dbus.Error("org.freedesktop.DBus", c.unique, "org.freedesktop.DBus.Error.GeneralError", m.getSerial(), "s", _("An error occurred while calling ")+m.getName())); } } catch (NoSuchMethodException NSMe) { send(c,new org.freedesktop.dbus.Error("org.freedesktop.DBus", c.unique, "org.freedesktop.DBus.Error.UnknownMethod", m.getSerial(), "s", _("This service does not support ")+m.getName())); } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } 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>"; } public void Ping() {} public void run() { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); while (_run) { Message m; Connstruct c; // block on outqueue synchronized (localqueue) { while (localqueue.size() == 0) try { localqueue.wait(); } catch (InterruptedException Ie) { } m = localqueue.head(); c = localqueue.remove(m).get(); } if (null != c) try { if (Debug.debug) Debug.print(Debug.VERBOSE, "<localqueue> Got message "+m+" from "+c); handleMessage(c, m); } catch (DBusException DBe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, DBe); } else if (Debug.debug) Debug.print(Debug.INFO, "Discarding "+m+" connection reaped"); } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } } public class Sender extends Thread { public Sender() { setName("Sender"); } public void run() { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); while (_run) { if (Debug.debug) Debug.print(Debug.VERBOSE, "Acquiring lock on outqueue and blocking for data"); Message m = null; Connstruct c = null; // block on outqueue synchronized (outqueue) { while (outqueue.size() == 0) try { outqueue.wait(); } catch (InterruptedException Ie) { } m = outqueue.head(); WeakReference<Connstruct> wc = outqueue.remove(m); if (null != wc) c = wc.get(); } if (null != c) { if (Debug.debug) Debug.print(Debug.VERBOSE, "<outqueue> Got message "+m+" for "+c.unique); if (Debug.debug) Debug.print(Debug.INFO, "Sending message "+m+" to "+c.unique); try { c.mout.writeMessage(m); } catch (IOException IOe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, IOe); removeConnection(c); } } else if (Debug.debug) Debug.print(Debug.INFO, "Discarding "+m+" connection reaped"); } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } } public class Reader extends Thread { private Connstruct conn; private WeakReference<Connstruct> weakconn; private boolean _lrun = true; public Reader(Connstruct conn) { this.conn = conn; weakconn = new WeakReference<Connstruct>(conn); setName("Reader"); } public void stopRunning() { _lrun = false; } public void run() { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); while (_run && _lrun) { Message m = null; try { m = conn.min.readMessage(); } catch (IOException IOe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, IOe); removeConnection(conn); } catch (DBusException DBe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, DBe); if (DBe instanceof FatalException) removeConnection(conn); } if (null != m) { if (Debug.debug) Debug.print(Debug.INFO, "Read "+m+" from "+conn.unique); synchronized (inqueue) { inqueue.putLast(m, weakconn); inqueue.notifyAll(); } } } conn = null; if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } } private Map<Connstruct, Reader> conns = new HashMap<Connstruct, Reader>(); private HashMap<String, Connstruct> names = new HashMap<String, Connstruct>(); private MagicMap<Message, WeakReference<Connstruct>> outqueue = new MagicMap<Message, WeakReference<Connstruct>>("out"); private MagicMap<Message, WeakReference<Connstruct>> inqueue = new MagicMap<Message, WeakReference<Connstruct>>("in"); private MagicMap<Message, WeakReference<Connstruct>> localqueue = new MagicMap<Message, WeakReference<Connstruct>>("local"); private List<Connstruct> sigrecips = new Vector<Connstruct>(); private boolean _run = true; private int next_unique = 0; private Object unique_lock = new Object(); DBusServer dbus_server = new DBusServer(); Sender sender = new Sender(); public DBusDaemon() { setName("Daemon"); synchronized (names) { names.put("org.freedesktop.DBus", null); } } @SuppressWarnings("unchecked") private void send(Connstruct c, Message m) { send (c, m, false); } private void send(Connstruct c, Message m, boolean head) { if (Debug.debug){ Debug.print(Debug.DEBUG, "enter"); if (null == c) Debug.print(Debug.VERBOSE, "Queing message "+m+" for all connections"); else Debug.print(Debug.VERBOSE, "Queing message "+m+" for "+c.unique); } // send to all connections if (null == c) { synchronized (conns) { synchronized (outqueue) { for (Connstruct d: conns.keySet()) if (head) outqueue.putFirst(m, new WeakReference<Connstruct>(d)); else outqueue.putLast(m, new WeakReference<Connstruct>(d)); outqueue.notifyAll(); } } } else { synchronized (outqueue) { if (head) outqueue.putFirst(m, new WeakReference<Connstruct>(c)); else outqueue.putLast(m, new WeakReference<Connstruct>(c)); outqueue.notifyAll(); } } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } @SuppressWarnings("unchecked") private List<Connstruct> findSignalMatches(DBusSignal sig) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); List<Connstruct> l; synchronized (sigrecips) { l = new Vector<Connstruct>(sigrecips); } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); return l; } @SuppressWarnings("unchecked") public void run() { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); while (_run) { try { Message m; Connstruct c = null; WeakReference<Connstruct> wc; synchronized (inqueue) { while (0 == inqueue.size()) try { inqueue.wait(); } catch (InterruptedException Ie) {} m = inqueue.head(); wc = inqueue.remove(m); if (null != wc) c = wc.get(); } if (null != c) { if (Debug.debug) Debug.print(Debug.INFO, "<inqueue> Got message "+m+" from "+c.unique); // check if they have hello'd if (null == c.unique && (!(m instanceof MethodCall) || !"org.freedesktop.DBus".equals(m.getDestination()) || !"Hello".equals(m.getName()))) { send(c,new Error("org.freedesktop.DBus", null, "org.freedesktop.DBus.Error.AccessDenied", m.getSerial(), "s", _("You must send a Hello message"))); } else { try { if (null != c.unique) m.setSource(c.unique); } catch (DBusException DBe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, DBe); send(c,new Error("org.freedesktop.DBus", null, "org.freedesktop.DBus.Error.GeneralError", m.getSerial(), "s", _("Sending message failed"))); } if ("org.freedesktop.DBus".equals(m.getDestination())) { synchronized (localqueue) { localqueue.putLast(m, wc); localqueue.notifyAll(); } } else { if (m instanceof DBusSignal) { List<Connstruct> list = findSignalMatches((DBusSignal) m); for (Connstruct d: list) send(d, m); } else { Connstruct dest = names.get(m.getDestination()); if (null == dest) { send(c, new Error("org.freedesktop.DBus", null, "org.freedesktop.DBus.Error.ServiceUnknown", m.getSerial(), "s", MessageFormat.format(_("The name `{0}' does not exist"), new Object[] { m.getDestination() }))); } else send(dest, m); } } } } } catch (DBusException DBe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, DBe); } } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } private void removeConnection(Connstruct c) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); boolean exists; synchronized(conns) { if ((exists = conns.containsKey(c))) { Reader r = conns.get(c); r.stopRunning(); conns.remove(c); } } if (exists) { try { if (null != c.usock) c.usock.close(); if (null != c.tsock) c.tsock.close(); } catch (IOException IOe) {} synchronized(names) { List<String> toRemove = new Vector<String>(); for (String name: names.keySet()) if (names.get(name) == c) { toRemove.add(name); try { send(null, new DBusSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", "sss", name, c.unique, "")); } catch (DBusException DBe) { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, DBe); } } for (String name: toRemove) names.remove(name); } } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } public void addSock(UnixSocket us) { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); if (Debug.debug) Debug.print(Debug.WARN, "New Client"); Connstruct c = new Connstruct(us); Reader r = new Reader(c); synchronized (conns) { conns.put(c, r); } r.start(); if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } public void addSock(Socket s) throws IOException { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); if (Debug.debug) Debug.print(Debug.WARN, "New Client"); Connstruct c = new Connstruct(s); Reader r = new Reader(c); synchronized (conns) { conns.put(c, r); } r.start(); if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } 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] [-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 { PrintWriter w = new PrintWriter(new FileOutputStream(file)); w.println(data); w.close(); } public static void main(String args[]) throws Exception { if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.DEBUG, "enter"); else if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); String addr = null; String pidfile = null; String addrfile = 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 syntax(); } catch (ArrayIndexOutOfBoundsException AIOOBe) { syntax(); } // generate a random address if none specified if (null == addr && unix) addr = DirectConnection.createDynamicSession(); else if (null == addr && tcp) addr = DirectConnection.createDynamicTCPSession(); BusAddress address = new BusAddress(addr); if (null == address.getParameter("guid")) { addr += ",guid="+Transport.genGUID(); address = new BusAddress(addr); } // print address to stdout if (printaddress) System.out.println(addr); // 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 if (Debug.debug) Debug.print(Debug.WARN, "Binding to "+addr); if ("unix".equals(address.getType())) doUnix(address); else if ("tcp".equals(address.getType())) doTCP(address); else throw new Exception("Unknown address type: "+address.getType()); if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } private static void doUnix(BusAddress address) throws IOException { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); UnixServerSocket uss; if (null != address. getParameter("abstract")) uss = new UnixServerSocket(new UnixSocketAddress(address.getParameter("abstract"), true)); else uss = new UnixServerSocket(new UnixSocketAddress(address.getParameter("path"), false)); DBusDaemon d = new DBusDaemon(); d.start(); d.sender.start(); d.dbus_server.start(); // accept new connections while (d._run) { UnixSocket s = uss.accept(); if ((new Transport.SASL()).auth(Transport.SASL.MODE_SERVER, Transport.SASL.AUTH_EXTERNAL, address.getParameter("guid"), s.getOutputStream(), s.getInputStream(), s)) { // s.setBlocking(false); d.addSock(s); } else s.close(); } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } private static void doTCP(BusAddress address) throws IOException { if (Debug.debug) Debug.print(Debug.DEBUG, "enter"); ServerSocket ss = new ServerSocket(Integer.parseInt(address.getParameter("port")),10, InetAddress.getByName(address.getParameter("host"))); DBusDaemon d = new DBusDaemon(); d.start(); d.sender.start(); d.dbus_server.start(); // accept new connections while (d._run) { Socket s = ss.accept(); boolean authOK=false; try { authOK = (new Transport.SASL()).auth(Transport.SASL.MODE_SERVER, Transport.SASL.AUTH_EXTERNAL, address.getParameter("guid"), s.getOutputStream(), s.getInputStream(), null); } catch (Exception e) { if (Debug.debug) Debug. print(Debug.DEBUG, e); } if (authOK) { d.addSock(s); } else s.close(); } if (Debug.debug) Debug.print(Debug.DEBUG, "exit"); } }