Skip to content

Current Transport Provider architecture makes it hard to synchronise bootstrapping #213

Closed
@brett-smith

Description

While using dbus-java for simple access to an existing broker and exported services is very easy, I have found that some more complex uses require additional code and considerations that ideally could be better dealt with by dbus-java itself.

This has mostly turned up when using the embedded broker on non-Linux systems, where I bundle the broker along with a service. The service will attempt to start a broker, export some services on it, and then wait for a client to connect to the bus all in one JVM. All the while, a client will be attempting to connect to the bus from another JVM. If it happens to manage to make a physical connection to the bus, before the service has finished setting up (exporting services etc), then I may hit problems. The necessitates code (Thread.sleeps, polling code, excessive error checking) to deal with this.

A similar problem exists when trying to use DirectConnection, either in the same JVM or split over two or more. This is demonstrated by TestPeer2Peer. It only works as well as it does because there are a couple of Thread.sleeps() in there.

The crux of the problem is the blocking nature of the DirectConnectionBuilder.build() on the listening side. This will not return until the first client connection is received, so it is not possible to export services and have them ready for exactly when the client is "allowed in".
While withAutoConnect(false) helps, in that at least you can get the connection instance without waiting for a client, you still cannot easily synchronise reliably.

Going back to basics, this is a pattern I have used often for client/server sockets. It makes use of the natural blocking you get with a socket, and is totally reliable with no sleeps necessary for it to work (the Thread.sleep is just simulating work).

try(var srv = new ServerSocket(0))  /* Socket is bound at this point to a random port, but not listening */ {
		
	new Thread(()->{
		/* Different thread of execution. Can be same JVM in a Thread, or separate JVM */
		try(var clnt  = new Socket(InetAddress.getLocalHost(), srv.getLocalPort()) /* Will be blocked until ServerSocket.accept() is run */) {
			System.out.println("I got a " +  clnt.getInputStream().read());			
		}
		catch(Exception e) {
			//
		}
	}).start();
			
	//
	// Do other stuff that may take some time .....
	//
	Thread.sleep(5000);
			
	try(var srvClnt = srv.accept()) /* Will be blocked until thread opens socket */ {
		srvClnt.getOutputStream().write(new Random().nextInt(256));
	}
}

As it stands, this pattern is not possible with dbus-java due to it combining the binding and accepting of the sockets when dealing with listening sockets.

So in short, I think I am asking if you think this can decoupled, so it is possible to get a DirectConnection (or DBusConnection) for a listening transport and have it's listening socket bound, but not yet accepting until instructed to do so.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions