package de.tum.in.www1.jReto.module.wlan; import java.io.IOException; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.UUID; import javax.jmdns.JmDNS; import javax.jmdns.ServiceInfo; import de.tum.in.www1.jReto.module.api.Advertiser; import de.tum.in.www1.jReto.niotools.Dispatcher; public class WlanAdvertiser implements Advertiser { private Handler handler; private Dispatcher dispatcher; private ServerSocketChannel serverSocketChannel; private boolean advertising; String networkType; private JmDNS bonjourServer; private ServiceInfo serviceInfo; public WlanAdvertiser(Dispatcher dispatcher, String networkType) { if (dispatcher == null) throw new IllegalArgumentException("dispatcher may not be null"); if (networkType == null) throw new IllegalArgumentException("networkType may not be null"); this.advertising = false; this.networkType = networkType; this.dispatcher = dispatcher; Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { try { bonjourServer.close(); } catch (IOException e) { e.printStackTrace(); } } }); } protected void onAccept(ServerSocketChannel serverChannelSocket) { try { SocketChannel channel = serverChannelSocket.accept(); if (channel != null) { this.handler.onConnection(this, new WlanConnection(this.dispatcher, channel)); } } catch (IOException e) { System.err.println("Failed to accept socket."); } } @Override public void setAdvertiserHandler(Handler handler) { this.handler = handler; } @Override public Handler getAdvertiserHandler() { return this.handler; } @Override public boolean isAdvertising() { return this.advertising; } @Override public void startAdvertisingWithPeerIdentifier(UUID identifier) { if (identifier == null) throw new IllegalArgumentException(); if (this.advertising) return; // Configure & open the server socket try { this.serverSocketChannel = ServerSocketChannel.open(); this.serverSocketChannel.socket().bind(null); this.serverSocketChannel.configureBlocking(false); this.dispatcher.registerAcceptHandler( new Dispatcher.AcceptHandler<ServerSocketChannel>() { public void onAcceptable(ServerSocketChannel serverChannelSocket) { WlanAdvertiser.this.onAccept(serverChannelSocket); } }, this.serverSocketChannel); // Starting a new thread to start advertising using jmdns, since jmdns may block the thread for several seconds. new Thread(() -> { try { String serviceType = "_" + this.networkType + "wlan._tcp.local."; this.serviceInfo = ServiceInfo.create(serviceType, identifier.toString(), serverSocketChannel.socket().getLocalPort(), ""); this.bonjourServer = JmDNS.create("RetoWlanAdvertiser"); WlanAdvertiser.this.bonjourServer.registerService(serviceInfo); } catch (Exception e) { System.err.println("Error occurred: "+e); } }).start(); this.advertising = true; if (this.handler != null && this.advertising) handler.onAdvertisingStarted(this); } catch(IOException e) { System.err.println("Error occurred: "+e); } } @Override public void stopAdvertising() { try { this.dispatcher.unregister(this.serverSocketChannel); this.serverSocketChannel.close(); this.bonjourServer.unregisterService(this.serviceInfo); this.bonjourServer.close(); } catch (IOException e) { System.err.println("Failed to stop bonjour advertising."); } finally { this.serverSocketChannel = null; this.advertising = false; if (this.handler != null) handler.onAdvertisingStopped(this); } } }