protected NioEndpoint addEndpoint( SocketChannel c ) { // Note: we purposely do NOT put the key in the endpoint. // SelectionKeys are dangerous outside the selector thread // and this is safer. NioEndpoint p = new NioEndpoint( this, nextEndpointId(), c ); endpoints.put( p.getId(), p ); // Enqueue an endpoint event for the listeners addEvent( EndpointEvent.createAdd( this, p ) ); return p; }
public void close() { close(false); }
protected void write( SelectionKey key ) throws IOException { NioEndpoint p = (NioEndpoint)key.attachment(); SocketChannel c = (SocketChannel)key.channel(); // We will send what we can and move on. ByteBuffer current = p.peekPending(); if( current == NioEndpoint.CLOSE_MARKER ) { // This connection wants to be closed now closeEndpoint(p); // Nothing more to do return; } c.write( current ); // If we wrote all of that packet then we need to remove it if( current.remaining() == 0 ) { p.removePending(); } // If we happened to empty the pending queue then let's read // again. if( !p.hasPending() ) { key.interestOps( SelectionKey.OP_READ ); } }
public void send( ByteBuffer data ) { if( data == null ) { throw new IllegalArgumentException( "Data cannot be null." ); } if( closing ) { throw new KernelException( "Endpoint has been closed:" + socket ); } send( data, true, true ); }
protected void removeEndpoint( NioEndpoint p, SocketChannel c ) { endpoints.remove( p.getId() ); log.log( Level.FINE, "Endpoints size:{0}", endpoints.size() ); // Enqueue an endpoint event for the listeners addEvent( EndpointEvent.createRemove( this, p ) ); wakeupReader(); }
protected void setupSelectorOptions() { // For now, selection keys will either be in OP_READ // or OP_WRITE. So while we are writing a buffer, we // will not be reading. This is way simpler and less // error prone... it can always be changed when everything // else works if we are looking to micro-optimize. // Setup options based on the current state of // the endpoints. This could potentially be more // efficiently done as change requests... or simply // keeping a thread-safe set of endpoints with pending // writes. For most cases, it shouldn't matter. for( Map.Entry<NioEndpoint,SelectionKey> e : endpointKeys.entrySet() ) { if( e.getKey().hasPending() ) { e.getValue().interestOps(SelectionKey.OP_WRITE); } } }
public void broadcast( Filter<? super Endpoint> filter, ByteBuffer data, boolean reliable, boolean copy ) { if( !reliable ) throw new UnsupportedOperationException( "Unreliable send not supported by this kernel." ); if( copy ) { // Copy the data just once byte[] temp = new byte[data.remaining()]; System.arraycopy(data.array(), data.position(), temp, 0, data.remaining()); data = ByteBuffer.wrap(temp); } // Hand it to all of the endpoints that match our routing for( NioEndpoint p : endpoints.values() ) { // Does it match the filter? if( filter != null && !filter.apply(p) ) continue; // Give it the data... but let each endpoint track their // own completion over the shared array of bytes by // duplicating it p.send( data.duplicate(), false, false ); } // Wake up the selector so it can reinitialize its // state accordingly. wakeupSelector(); }
protected void removeEndpoint( NioEndpoint p, SocketChannel c ) { endpoints.remove( p.getId() ); log.log( Level.FINE, "Endpoints size:{0}", endpoints.size() ); // Enqueue an endpoint event for the listeners addEvent( EndpointEvent.createRemove( this, p ) ); wakeupReader(); }
protected void setupSelectorOptions() { // For now, selection keys will either be in OP_READ // or OP_WRITE. So while we are writing a buffer, we // will not be reading. This is way simpler and less // error prone... it can always be changed when everything // else works if we are looking to micro-optimize. // Setup options based on the current state of // the endpoints. This could potentially be more // efficiently done as change requests... or simply // keeping a thread-safe set of endpoints with pending // writes. For most cases, it shouldn't matter. for( Map.Entry<NioEndpoint,SelectionKey> e : endpointKeys.entrySet() ) { if( e.getKey().hasPending() ) { e.getValue().interestOps(SelectionKey.OP_WRITE); } } }
protected void write( SelectionKey key ) throws IOException { NioEndpoint p = (NioEndpoint)key.attachment(); SocketChannel c = (SocketChannel)key.channel(); // We will send what we can and move on. ByteBuffer current = p.peekPending(); if( current == NioEndpoint.CLOSE_MARKER ) { // This connection wants to be closed now closeEndpoint(p); // Nothing more to do return; } c.write( current ); // If we wrote all of that packet then we need to remove it if( current.remaining() == 0 ) { p.removePending(); } // If we happened to empty the pending queue then let's read // again. if( !p.hasPending() ) { key.interestOps( SelectionKey.OP_READ ); } }
protected NioEndpoint addEndpoint( SocketChannel c ) { // Note: we purposely do NOT put the key in the endpoint. // SelectionKeys are dangerous outside the selector thread // and this is safer. NioEndpoint p = new NioEndpoint( this, nextEndpointId(), c ); endpoints.put( p.getId(), p ); // Enqueue an endpoint event for the listeners addEvent( EndpointEvent.createAdd( this, p ) ); return p; }
public void close( boolean flushData ) { if( flushData ) { closing = true; // Enqueue a close marker message to let the server // know we should close send( CLOSE_MARKER, false, true ); return; } try { // Note: even though we may be disconnected from the socket.isConnected() // standpoint, it's still safest to tell the kernel so that it can be sure // to stop managing us gracefully. kernel.closeEndpoint(this); } catch( IOException e ) { throw new KernelException( "Error closing endpoint for socket:" + socket, e ); } }
protected void removeEndpoint( NioEndpoint p, SocketChannel c ) { endpoints.remove( p.getId() ); // Enqueue an endpoint event for the listeners addEvent( EndpointEvent.createRemove( this, p ) ); // If there are no pending messages then add one so that the // kernel-user knows to wake up if it is only listening for // envelopes. if( !hasEnvelopes() ) { // Note: this is not really a race condition. At worst, our // event has already been handled by now and it does no harm // to check again. addEnvelope( EVENTS_PENDING ); } }
public void close() { close(false); }
protected void setupSelectorOptions() { // For now, selection keys will either be in OP_READ // or OP_WRITE. So while we are writing a buffer, we // will not be reading. This is way simpler and less // error prone... it can always be changed when everything // else works if we are looking to micro-optimize. // Setup options based on the current state of // the endpoints. This could potentially be more // efficiently done as change requests... or simply // keeping a thread-safe set of endpoints with pending // writes. For most cases, it shouldn't matter. for( Map.Entry<NioEndpoint,SelectionKey> e : endpointKeys.entrySet() ) { if( e.getKey().hasPending() ) { e.getValue().interestOps(SelectionKey.OP_WRITE); } } }
protected void write( SelectionKey key ) throws IOException { NioEndpoint p = (NioEndpoint)key.attachment(); SocketChannel c = (SocketChannel)key.channel(); // We will send what we can and move on. ByteBuffer current = p.peekPending(); if( current == NioEndpoint.CLOSE_MARKER ) { // This connection wants to be closed now closeEndpoint(p); // Nothing more to do return; } c.write( current ); // If we wrote all of that packet then we need to remove it if( current.remaining() == 0 ) { p.removePending(); } // If we happened to empty the pending queue then let's read // again. if( !p.hasPending() ) { key.interestOps( SelectionKey.OP_READ ); } }
protected NioEndpoint addEndpoint( SocketChannel c ) { // Note: we purposely do NOT put the key in the endpoint. // SelectionKeys are dangerous outside the selector thread // and this is safer. NioEndpoint p = new NioEndpoint( this, nextEndpointId(), c ); endpoints.put( p.getId(), p ); // Enqueue an endpoint event for the listeners addEvent( EndpointEvent.createAdd( this, p ) ); return p; }
public void send( ByteBuffer data ) { if( data == null ) { throw new IllegalArgumentException( "Data cannot be null." ); } if( closing ) { throw new KernelException( "Endpoint has been closed:" + socket ); } send( data, true, true ); }
public void close() { close(false); }
public void send( ByteBuffer data ) { if( data == null ) { throw new IllegalArgumentException( "Data cannot be null." ); } if( closing ) { throw new KernelException( "Endpoint has been closed:" + socket ); } send( data, true, true ); }