public void close(final Handler<Void> done) { if (!listening) { if (done != null) { executeCloseDone(ctx, done); } return; } listening = false; synchronized (vertx.sharedNetServers()) { if (actualServer != null) { actualServer.handlerManager.removeHandler(connectHandler, ctx); if (actualServer.handlerManager.hasHandlers()) { // The actual server still has handlers so we don't actually close it if (done != null) { executeCloseDone(ctx, done); } } else { // No Handlers left so close the actual server // The done handler needs to be executed on the context that calls close, NOT the context // of the actual server actualServer.actualClose(ctx, done); } } } }
private void actualClose(final Context closeContext, final Handler<Void> done) { if (id != null) { vertx.sharedNetServers().remove(id); } for (DefaultNetSocket sock : socketMap.values()) { sock.internalClose(); } // We need to reset it since sock.internalClose() above can call into the close handlers of // sockets on the same thread // which can cause context id for the thread to change! Context.setContext(closeContext); ChannelGroupFuture fut = serverChannelGroup.close(); if (done != null) { fut.addListener( new ChannelGroupFutureListener() { public void operationComplete(ChannelGroupFuture channelGroupFuture) throws Exception { executeCloseDone(closeContext, done); } }); } }
public NetServer listen(int port, String host) { if (connectHandler == null) { throw new IllegalStateException("Set connect handler first"); } if (listening) { throw new IllegalStateException("Listen already called"); } listening = true; synchronized (vertx.sharedNetServers()) { id = new ServerID(port, host); DefaultNetServer shared = vertx.sharedNetServers().get(id); if (shared == null) { serverChannelGroup = new DefaultChannelGroup("vertx-acceptor-channels"); ChannelFactory factory = new NioServerSocketChannelFactory(vertx.getAcceptorPool(), availableWorkers); ServerBootstrap bootstrap = new ServerBootstrap(factory); tcpHelper.checkSSL(); bootstrap.setPipelineFactory( new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { ChannelPipeline pipeline = Channels.pipeline(); if (tcpHelper.isSSL()) { SSLEngine engine = tcpHelper.getSSLContext().createSSLEngine(); engine.setUseClientMode(false); switch (tcpHelper.getClientAuth()) { case REQUEST: { engine.setWantClientAuth(true); break; } case REQUIRED: { engine.setNeedClientAuth(true); break; } case NONE: { engine.setNeedClientAuth(false); break; } } pipeline.addLast("ssl", new SslHandler(engine)); } pipeline.addLast( "chunkedWriter", new ChunkedWriteHandler()); // For large file / sendfile support pipeline.addLast("handler", new ServerHandler()); return pipeline; } }); bootstrap.setOptions(tcpHelper.generateConnectionOptions(true)); try { // TODO - currently bootstrap.bind is blocking - need to make it non blocking by not using // bootstrap directly Channel serverChannel = bootstrap.bind(new InetSocketAddress(InetAddress.getByName(host), port)); serverChannelGroup.add(serverChannel); log.trace("Net server listening on " + host + ":" + port); } catch (UnknownHostException e) { log.error("Failed to bind", e); } vertx.sharedNetServers().put(id, this); actualServer = this; } else { // Server already exists with that host/port - we will use that checkConfigs(actualServer, this); actualServer = shared; } actualServer.handlerManager.addHandler(connectHandler, ctx); } return this; }