/** * Creates a named and versioned Server that will utilize both reliable and fast * transports to communicate with clients. The specified port * will be used for both TCP and UDP communication. * * @param gameName This is the name that identifies the game. Connecting clients * must use this name or be turned away. * @param version This is a game-specific verison that helps detect when out-of-date * clients have connected to an incompatible server. * @param tcpPort The port upon which the TCP hosting will listen for new connections. * @param udpPort The port upon which the UDP hosting will listen for new 'fast' UDP * messages. Set to -1 if 'fast' traffic should go over TCP. This will * completely disable UDP traffic for this server. */ public static Server createServer( String gameName, int version, int tcpPort, int udpPort ) throws IOException { UdpKernel fast = udpPort == -1 ? null : new UdpKernel(udpPort); SelectorKernel reliable = new SelectorKernel(tcpPort); return new DefaultServer( gameName, version, reliable, fast ); }
protected void newData( DatagramPacket packet ) { // So the tricky part here is figuring out the endpoint and // whether it's new or not. In these UDP schemes, firewalls have // to be ported back to a specific machine so we will consider // the address + port (ie: SocketAddress) the defacto unique // ID. Endpoint p = getEndpoint( packet.getSocketAddress(), true ); // We'll copy the data to trim it. byte[] data = new byte[packet.getLength()]; System.arraycopy(packet.getData(), 0, data, 0, data.length); Envelope env = new Envelope( p, data, false ); addEnvelope( env ); }
protected Endpoint getEndpoint( SocketAddress address, boolean create ) { UdpEndpoint p = socketEndpoints.get(address); if( p == null && create ) { p = new UdpEndpoint( this, nextEndpointId(), address, thread.getSocket() ); socketEndpoints.put( address, p ); // Add an event for it. addEvent( EndpointEvent.createAdd( this, p ) ); } return p; }
/** * Called by the endpoints when they need to be closed. */ protected void closeEndpoint( UdpEndpoint p ) throws IOException { // Just book-keeping to do here. if( socketEndpoints.remove( p.getRemoteAddress() ) == null ) return; log.log( Level.FINE, "Closing endpoint:{0}.", p ); log.log( Level.FINE, "Socket endpoints size:{0}", socketEndpoints.size() ); addEvent( EndpointEvent.createRemove( this, p ) ); wakeupReader(); }
public void close( boolean flush ) { // No real reason to flush UDP traffic yet... especially // when considering that the outbound UDP isn't even // queued. try { kernel.closeEndpoint(this); connected = false; } catch( IOException e ) { throw new KernelException( "Error closing endpoint for socket:" + socket, e ); } }
public void initialize() { if( thread != null ) throw new IllegalStateException( "Kernel already initialized." ); writer = Executors.newFixedThreadPool(2, new NamedThreadFactory(toString() + "-writer")); thread = createHostThread(); try { thread.connect(); thread.start(); } catch( IOException e ) { throw new KernelException( "Error hosting:" + address, e ); } }
public void run() { log.log( Level.FINE, "Kernel started for connection:{0}.", address ); // An atomic is safest and costs almost nothing while( go.get() ) { try { // Could reuse the packet but I don't see the // point and it may lead to subtle bugs if not properly // reset. DatagramPacket packet = new DatagramPacket( buffer, buffer.length ); socket.receive(packet); newData( packet ); } catch( IOException e ) { if( !go.get() ) return; reportError( e ); } } } }
public void send( ByteBuffer data ) { if( !isConnected() ) { throw new KernelException( "Endpoint is not connected:" + this ); } try { DatagramPacket p = new DatagramPacket( data.array(), data.position(), data.remaining(), address ); // Just queue it up for the kernel threads to write // out kernel.enqueueWrite( this, p ); //socket.send(p); } catch (Exception e) { if (e instanceof SocketException) { throw new KernelException("Error sending datagram to:" + address, e); } else if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { throw new RuntimeException(e); } } }
/** * Called by the endpoints when they need to be closed. */ protected void closeEndpoint( UdpEndpoint p ) throws IOException { log.log( Level.INFO, "Closing endpoint:{0}.", p ); // Just book-keeping to do here. socketEndpoints.remove( p.getRemoteAddress() ); addEvent( EndpointEvent.createRemove( this, p ) ); }
public void terminate() throws InterruptedException { if( thread == null ) throw new IllegalStateException( "Kernel not initialized." ); try { thread.close(); writer.shutdown(); thread = null; // Need to let any caller waiting for a read() wakeup wakeupReader(); } catch( IOException e ) { throw new KernelException( "Error closing host connection:" + address, e ); } }
/** * Called by the endpoints when they need to be closed. */ protected void closeEndpoint( UdpEndpoint p ) throws IOException { // Just book-keeping to do here. if( socketEndpoints.remove( p.getRemoteAddress() ) == null ) return; log.log( Level.FINE, "Closing endpoint:{0}.", p ); log.log( Level.FINE, "Socket endpoints size:{0}", socketEndpoints.size() ); addEvent( EndpointEvent.createRemove( this, p ) ); wakeupReader(); }
public void close( boolean flush ) { // No real reason to flush UDP traffic yet... especially // when considering that the outbound UDP isn't even // queued. try { kernel.closeEndpoint(this); connected = false; } catch( IOException e ) { throw new KernelException( "Error closing endpoint for socket:" + socket, e ); } }
public void initialize() { if( thread != null ) throw new IllegalStateException( "Kernel already initialized." ); writer = Executors.newFixedThreadPool(2, new NamedThreadFactory(toString() + "-writer")); thread = createHostThread(); try { thread.connect(); thread.start(); } catch( IOException e ) { throw new KernelException( "Error hosting:" + address, e ); } }
public void run() { log.log( Level.INFO, "Kernel started for connection:{0}.", address ); // An atomic is safest and costs almost nothing while( go.get() ) { try { // Could reuse the packet but I don't see the // point and it may lead to subtle bugs if not properly // reset. DatagramPacket packet = new DatagramPacket( buffer, buffer.length ); socket.receive(packet); newData( packet ); } catch( IOException e ) { if( !go.get() ) return; reportError( e ); } } } }
public void send( ByteBuffer data ) { if( !isConnected() ) { throw new KernelException( "Endpoint is not connected:" + this ); } try { DatagramPacket p = new DatagramPacket( data.array(), data.position(), data.remaining(), address ); // Just queue it up for the kernel threads to write // out kernel.enqueueWrite( this, p ); //socket.send(p); } catch( IOException e ) { throw new KernelException( "Error sending datagram to:" + address, e ); } }
public void terminate() throws InterruptedException { if( thread == null ) throw new IllegalStateException( "Kernel not initialized." ); try { thread.close(); writer.shutdown(); thread = null; // Need to let any caller waiting for a read() wakeup wakeupReader(); } catch( IOException e ) { throw new KernelException( "Error closing host connection:" + address, e ); } }
protected Endpoint getEndpoint( SocketAddress address, boolean create ) { UdpEndpoint p = socketEndpoints.get(address); if( p == null && create ) { p = new UdpEndpoint( this, nextEndpointId(), address, thread.getSocket() ); socketEndpoints.put( address, p ); // Add an event for it. addEvent( EndpointEvent.createAdd( this, p ) ); } return p; }
protected void newData( DatagramPacket packet ) { // So the tricky part here is figuring out the endpoint and // whether it's new or not. In these UDP schemes, firewalls have // to be ported back to a specific machine so we will consider // the address + port (ie: SocketAddress) the defacto unique // ID. Endpoint p = getEndpoint( packet.getSocketAddress(), true ); // We'll copy the data to trim it. byte[] data = new byte[packet.getLength()]; System.arraycopy(packet.getData(), 0, data, 0, data.length); Envelope env = new Envelope( p, data, false ); addEnvelope( env ); }
public void close( boolean flush ) { // No real reason to flush UDP traffic yet... especially // when considering that the outbound UDP isn't even // queued. try { kernel.closeEndpoint(this); connected = false; } catch( IOException e ) { throw new KernelException( "Error closing endpoint for socket:" + socket, e ); } }
public void initialize() { if( thread != null ) throw new IllegalStateException( "Kernel already initialized." ); writer = Executors.newFixedThreadPool(2, new NamedThreadFactory(toString() + "-writer")); thread = createHostThread(); try { thread.connect(); thread.start(); } catch( IOException e ) { throw new KernelException( "Error hosting:" + address, e ); } }