Example usage for java.nio.channels SocketChannel read

List of usage examples for java.nio.channels SocketChannel read

Introduction

In this page you can find the example usage for java.nio.channels SocketChannel read.

Prototype

public final long read(ByteBuffer[] dsts) throws IOException 

Source Link

Usage

From source file:morphy.service.SocketConnectionService.java

protected synchronized String readMessage(SocketChannel channel) {
    try {/*from  w  w  w  . j  a  v a2 s.co m*/
        ByteBuffer buffer = ByteBuffer.allocate(maxCommunicationSizeBytes);
        int charsRead = -1;
        try {
            charsRead = channel.read(buffer);
        } catch (IOException cce) {
            if (channel.isOpen()) {
                channel.close();
                if (LOG.isInfoEnabled()) {
                    LOG.info("Closed channel " + channel);
                }
            }
        }
        if (charsRead == -1) {
            return null;
        } else if (charsRead > 0) {
            buffer.flip();

            Charset charset = Charset.forName(Morphy.getInstance().getMorphyPreferences()
                    .getString(PreferenceKeys.SocketConnectionServiceCharEncoding));

            SocketChannelUserSession socketChannelUserSession = socketToSession.get(channel.socket());

            byte[] bytes = buffer.array();
            buffer.position(0);

            System.out.println("IN: " + new String(bytes).trim());
            if (looksLikeTimesealInit(bytes)) {
                if (socketChannelUserSession.usingTimeseal == false) {
                    // First time?
                    socketChannelUserSession.usingTimeseal = true;
                    return MSG_TIMESEAL_OK;
                }
            }

            if (socketChannelUserSession.usingTimeseal) {
                /*
                 * Clients may pass multiple Timeseal-encoded messages at once.
                 * We need to parse each separated message to Timeseal decoder as necessary. 
                 */

                byte[] bytesToDecode = Arrays.copyOfRange(bytes, 0, charsRead - 1 /* \n or 10 */);
                byte[][] splitBytes = TimesealCoder.splitBytes(bytesToDecode, (byte) 10);

                buffer = ByteBuffer.allocate(bytesToDecode.length);
                buffer.position(0);
                for (int i = 0; i < splitBytes.length; i++) {
                    byte[] splitBytesToDecode = splitBytes[i];
                    TimesealParseResult parseResult = timesealCoder.decode(splitBytesToDecode);
                    if (parseResult != null) {
                        System.out.println(parseResult.getTimestamp());
                        parseResult.setMessage(parseResult.getMessage() + "\n");
                        System.out.println(parseResult.getMessage());

                        buffer.put(parseResult.getMessage().getBytes(charset));
                    }
                }
                //buffer.position(0);
                buffer.flip();
            }

            CharsetDecoder decoder = charset.newDecoder();
            CharBuffer charBuffer = decoder.decode(buffer);
            String message = charBuffer.toString();
            return message;
            //System.out.println(message);
            //return "";
        } else {
            return "";
        }
    } catch (Throwable t) {
        if (LOG.isErrorEnabled())
            LOG.error("Error reading SocketChannel " + channel.socket().getLocalAddress(), t);
        return null;
    }
}

From source file:com.springrts.springls.ServerThread.java

/** Check for incoming messages */
private void readIncomingMessages() {

    Client client = null;/*w w w .j  a  v a2s.c o m*/
    try {
        // non-blocking select, returns immediately regardless of
        // how many keys are ready
        readSelector.selectNow();

        // fetch the keys
        Set<SelectionKey> readyKeys = readSelector.selectedKeys();

        // run through the keys and process each one
        while (!readyKeys.isEmpty()) {
            SelectionKey key = readyKeys.iterator().next();
            readyKeys.remove(key);
            SocketChannel channel = (SocketChannel) key.channel();
            client = (Client) key.attachment();
            if (client.isHalfDead()) {
                continue;
            }
            readBuffer.clear();

            client.setTimeOfLastReceive(System.currentTimeMillis());

            // read from the channel into our buffer
            long nBytes = channel.read(readBuffer);
            client.addReceived(nBytes);

            // basic anti-flood protection
            FloodProtectionService floodProtection = getContext().getService(FloodProtectionService.class);
            if ((floodProtection != null) && floodProtection.isFlooding(client)) {
                continue;
            }

            // check for end-of-stream
            if (nBytes == -1) {
                LOG.debug("Socket disconnected - killing client");
                channel.close();
                // this will also close the socket channel
                getContext().getClients().killClient(client);
            } else {
                // use a CharsetDecoder to turn those bytes into a string
                // and append it to the client's StringBuilder
                readBuffer.flip();
                String str = getContext().getServer().getAsciiDecoder().decode(readBuffer).toString();
                readBuffer.clear();
                client.appendToRecvBuf(str);

                // TODO move this to Client#appendToRecvBuf(String)
                // check for a full line
                String line = client.readLine();
                while (line != null) {
                    executeCommandWrapper(line, client);

                    if (!client.isAlive()) {
                        // in case the client was killed within the
                        // executeCommand() method
                        break;
                    }
                    line = client.readLine();
                }
            }
        }
    } catch (IOException ioex) {
        LOG.info("exception during select(): possibly due to force disconnect. Killing the client ...");
        if (client != null) {
            getContext().getClients().killClient(client, "Quit: connection lost");
        }
        LOG.debug("... the exception was:", ioex);
    }
}

From source file:edu.hawaii.soest.pacioos.text.SocketTextSource.java

@Override
protected boolean execute() {

    log.debug("SocketTextSource.execute() called.");
    // do not execute the stream if there is no connection
    if (!isConnected())
        return false;

    boolean failed = false;

    /* Get a connection to the instrument */
    SocketChannel socket = getSocketConnection();
    if (socket == null)
        return false;

    // while data are being sent, read them into the buffer
    try {//from   w  ww .  ja  v  a2s .  com
        // create four byte placeholders used to evaluate up to a four-byte 
        // window.  The FIFO layout looks like:
        //           -------------------------
        //   in ---> | One | Two |Three|Four |  ---> out
        //           -------------------------
        byte byteOne = 0x00, // set initial placeholder values
                byteTwo = 0x00, byteThree = 0x00, byteFour = 0x00;

        // Create a buffer that will store the sample bytes as they are read
        ByteBuffer sampleBuffer = ByteBuffer.allocate(getBufferSize());

        // create a byte buffer to store bytes from the TCP stream
        ByteBuffer buffer = ByteBuffer.allocateDirect(getBufferSize());

        // while there are bytes to read from the socket ...
        while (socket.read(buffer) != -1 || buffer.position() > 0) {

            // prepare the buffer for reading
            buffer.flip();

            // while there are unread bytes in the ByteBuffer
            while (buffer.hasRemaining()) {
                byteOne = buffer.get();

                // log the byte stream
                String character = new String(new byte[] { byteOne });
                if (log.isDebugEnabled()) {
                    List<Byte> whitespaceBytes = new ArrayList<Byte>();
                    whitespaceBytes.add(new Byte((byte) 0x0A));
                    whitespaceBytes.add(new Byte((byte) 0x0D));
                    if (whitespaceBytes.contains(new Byte(byteOne))) {
                        character = new String(Hex.encodeHex((new byte[] { byteOne })));

                    }
                }
                log.debug("char: " + character + "\t" + "b1: "
                        + new String(Hex.encodeHex((new byte[] { byteOne }))) + "\t" + "b2: "
                        + new String(Hex.encodeHex((new byte[] { byteTwo }))) + "\t" + "b3: "
                        + new String(Hex.encodeHex((new byte[] { byteThree }))) + "\t" + "b4: "
                        + new String(Hex.encodeHex((new byte[] { byteFour }))) + "\t" + "sample pos: "
                        + sampleBuffer.position() + "\t" + "sample rem: " + sampleBuffer.remaining() + "\t"
                        + "sample cnt: " + sampleByteCount + "\t" + "buffer pos: " + buffer.position() + "\t"
                        + "buffer rem: " + buffer.remaining() + "\t" + "state: " + state);

                // evaluate each byte to find the record delimiter(s), and when found, validate and
                // send the sample to the DataTurbine.
                int numberOfChannelsFlushed = 0;

                if (getRecordDelimiters().length == 2) {
                    // have we hit the delimiters in the stream yet?
                    if (byteTwo == getFirstDelimiterByte() && byteOne == getSecondDelimiterByte()) {
                        sampleBuffer.put(byteOne);
                        sampleByteCount++;
                        // extract just the length of the sample bytes out of the
                        // sample buffer, and place it in the channel map as a 
                        // byte array.  Then, send it to the DataTurbine.
                        log.debug("Sample byte count: " + sampleByteCount);
                        byte[] sampleArray = new byte[sampleByteCount];
                        sampleBuffer.flip();
                        sampleBuffer.get(sampleArray);
                        String sampleString = new String(sampleArray, "US-ASCII");

                        if (validateSample(sampleString)) {
                            numberOfChannelsFlushed = sendSample(sampleString);

                        }

                        sampleBuffer.clear();
                        sampleByteCount = 0;
                        byteOne = 0x00;
                        byteTwo = 0x00;
                        byteThree = 0x00;
                        byteFour = 0x00;
                        log.debug("Cleared b1,b2,b3,b4. Cleared sampleBuffer. Cleared rbnbChannelMap.");

                    } else {
                        // still in the middle of the sample, keep adding bytes
                        sampleByteCount++; // add each byte found

                        if (sampleBuffer.remaining() > 0) {
                            sampleBuffer.put(byteOne);

                        } else {
                            sampleBuffer.compact();
                            log.debug("Compacting sampleBuffer ...");
                            sampleBuffer.put(byteOne);

                        }

                    }

                } else if (getRecordDelimiters().length == 1) {
                    // have we hit the delimiter in the stream yet?
                    if (byteOne == getFirstDelimiterByte()) {
                        sampleBuffer.put(byteOne);
                        sampleByteCount++;
                        // extract just the length of the sample bytes out of the
                        // sample buffer, and place it in the channel map as a 
                        // byte array.  Then, send it to the DataTurbine.
                        byte[] sampleArray = new byte[sampleByteCount];
                        sampleBuffer.flip();
                        sampleBuffer.get(sampleArray);
                        String sampleString = new String(sampleArray, "US-ASCII");

                        if (validateSample(sampleString)) {
                            numberOfChannelsFlushed = sendSample(sampleString);

                        }

                        sampleBuffer.clear();
                        sampleByteCount = 0;
                        byteOne = 0x00;
                        byteTwo = 0x00;
                        byteThree = 0x00;
                        byteFour = 0x00;
                        log.debug("Cleared b1,b2,b3,b4. Cleared sampleBuffer. Cleared rbnbChannelMap.");

                    } else {
                        // still in the middle of the sample, keep adding bytes
                        sampleByteCount++; // add each byte found

                        if (sampleBuffer.remaining() > 0) {
                            sampleBuffer.put(byteOne);

                        } else {
                            sampleBuffer.compact();
                            log.debug("Compacting sampleBuffer ...");
                            sampleBuffer.put(byteOne);

                        }

                    }

                } // end getRecordDelimiters().length

                // shift the bytes in the FIFO window
                byteFour = byteThree;
                byteThree = byteTwo;
                byteTwo = byteOne;

            } //end while (more unread bytes)

            // prepare the buffer to read in more bytes from the stream
            buffer.compact();

        } // end while (more socket bytes to read)
        socket.close();

    } catch (IOException e) {
        // handle exceptions
        // In the event of an i/o exception, log the exception, and allow execute()
        // to return false, which will prompt a retry.
        failed = true;
        log.error("There was a communication error in sending the data sample. The message was: "
                + e.getMessage());
        if (log.isDebugEnabled()) {
            e.printStackTrace();
        }
        return !failed;

    } catch (SAPIException sapie) {
        // In the event of an RBNB communication  exception, log the exception, 
        // and allow execute() to return false, which will prompt a retry.
        failed = true;
        log.error("There was an RBNB error while sending the data sample. The message was: "
                + sapie.getMessage());
        if (log.isDebugEnabled()) {
            sapie.printStackTrace();
        }
        return !failed;
    }

    return !failed;

}

From source file:hornet.framework.clamav.service.ClamAVCheckService.java

/**
 * Lecture du fichier et envoi sur la socket.
 *
 * @param resultat//w  w  w  .j  a v  a  2s . co m
 *            resultat
 * @param fileForTestSize
 *            fileForTestSize
 * @param channel
 *            channel
 * @param bufFileForTestRead
 *            bufFileForTestRead
 * @throws IOException
 *             IOException
 */
protected void readAndSendFile(final StringBuilder resultat, final long fileForTestSize,
        final SocketChannel channel, final MappedByteBuffer bufFileForTestRead) throws IOException {

    // Envoi de la commande
    final ByteBuffer writeReadBuffer = ByteBuffer.allocate(BUFFER_SIZE);
    writeReadBuffer.put(ClamAVCheckService.COMMANDE.getBytes(UTF_8));
    writeReadBuffer.put(this.intToByteArray((int) fileForTestSize));
    writeReadBuffer.flip();
    channel.write(writeReadBuffer);

    // Envoi du fichier

    long size = fileForTestSize;
    // envoi du fichier
    while (size > 0) {
        size -= channel.write(bufFileForTestRead);
    }
    final ByteBuffer writeBuffer = ByteBuffer.allocate(4);
    writeBuffer.put(new byte[] { 0, 0, 0, 0 });
    writeBuffer.flip();
    channel.write(writeBuffer);

    // lecture de la rponse
    ByteBuffer readBuffer;
    readBuffer = ByteBuffer.allocate(BUFFER_SIZE);
    // lecture de la rponse
    readBuffer.clear();
    boolean readLine = false;
    while (!readLine) {
        final int numReaden = channel.read(readBuffer);
        if (numReaden > 0) {
            readLine = readBuffer.get(numReaden - 1) == '\n';
            resultat.append(new String(readBuffer.array(), 0, numReaden, UTF_8));
            readBuffer.clear();
        } else {
            if (numReaden == -1) {
                readLine = true;
                readBuffer.clear();
            }
        }
    }
}

From source file:jp.queuelinker.system.net.SelectorThread.java

@Override
public void run() {
    ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
    // I believe the inner try-catches does not cause overhead.
    // http://stackoverflow.com/questions/141560/
    long sendCount = 0;

    SocketChannel currentChannel;
    SelectionKey key = null;/*from w  w  w.j  ava2s.  c o m*/
    while (true) {
        try {
            selector.select();
            // selector.selectNow();
        } catch (ClosedSelectorException e) {
            logger.fatal("BUG: The selector is closed.");
            return;
        } catch (IOException e) {
            logger.fatal("An IOException occured while calling select().");
            // Fatal Error. Notify the error to the users and leave the matter to them.
            for (ChannelState state : channels) {
                state.callBack.fatalError();
            }
            return;
        }

        if (!requests.isEmpty()) {
            handleRequest();
            continue;
        }

        if (stopRequested) {
            return;
        }

        Set<SelectionKey> keys = selector.selectedKeys();

        Iterator<SelectionKey> iter = keys.iterator();
        iter_loop: while (iter.hasNext()) {
            key = iter.next();
            iter.remove(); // Required. Don't remove.

            if (key.isReadable()) {
                currentChannel = (SocketChannel) key.channel();
                final ChannelState state = (ChannelState) key.attachment();

                int valid;
                try {
                    valid = currentChannel.read(buffer);
                } catch (IOException e) {
                    logger.warn("An IOException happened while reading from a channel.");
                    state.callBack.exceptionOccured(state.channelId, state.attachment);
                    key.cancel();
                    continue;
                }
                if (valid == -1) {
                    // Normal socket close?
                    state.callBack.exceptionOccured(state.channelId, state.attachment);
                    // cleanUpChannel(state.channelId);
                    key.cancel();
                    continue;
                }

                buffer.rewind();
                if (state.callBack.receive(state.channelId, buffer, valid, state.attachment) == false) {
                    state.key.interestOps(state.key.interestOps() & ~SelectionKey.OP_READ);
                }
                buffer.clear();
            } else if (key.isWritable()) {
                currentChannel = (SocketChannel) key.channel();
                final ChannelState state = (ChannelState) key.attachment();

                while (state.sendBuffer.readableSize() < WRITE_SIZE) {
                    ByteBuffer newBuffer = state.callBack.send(state.channelId, state.attachment);
                    if (newBuffer != null) {
                        state.sendBuffer.write(newBuffer);
                        if (++sendCount % 50000 == 0) {
                            logger.info("Send Count: " + sendCount);
                        }
                    } else if (state.sendBuffer.readableSize() == 0) {
                        key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
                        continue iter_loop;
                    } else {
                        break;
                    }
                }

                final int available = state.sendBuffer.readableSize();
                if (available >= WRITE_SIZE || ++state.noopCount >= HEURISTIC_WAIT) {
                    int done;
                    try {
                        done = currentChannel.write(state.sendBuffer.getByteBuffer());
                    } catch (IOException e) {
                        logger.warn("An IOException occured while writing to a channel.");
                        state.callBack.exceptionOccured(state.channelId, state.attachment);
                        key.cancel();
                        continue;
                    }
                    if (done < available) {
                        state.sendBuffer.rollback(available - done);
                    }
                    state.sendBuffer.compact();
                    state.noopCount = 0;
                }
            } else if (key.isAcceptable()) {
                ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                ChannelState state = (ChannelState) key.attachment();
                SocketChannel socketChannel;
                try {
                    socketChannel = channel.accept();
                    socketChannel.configureBlocking(false);
                } catch (IOException e) {
                    continue; // Do nothing.
                }
                state.callBack.newConnection(state.channelId, socketChannel, state.attachment);
            }
        }
    }
}

From source file:edu.hawaii.soest.kilonalu.flntu.FLNTUSource.java

/**
 * A method that executes the streaming of data from the source to the RBNB
 * server after all configuration of settings, connections to hosts, and
 * thread initiatizing occurs.  This method contains the detailed code for 
 * streaming the data and interpreting the stream.
 *//*ww w .  ja va2  s .com*/
protected boolean execute() {
    logger.debug("FLNTUSource.execute() called.");
    // do not execute the stream if there is no connection
    if (!isConnected())
        return false;

    boolean failed = false;

    SocketChannel socket = getSocketConnection();

    // while data are being sent, read them into the buffer
    try {
        // create four byte placeholders used to evaluate up to a four-byte 
        // window.  The FIFO layout looks like:
        //           -------------------------
        //   in ---> | One | Two |Three|Four |  ---> out
        //           -------------------------
        byte byteOne = 0x00, // set initial placeholder values
                byteTwo = 0x00, byteThree = 0x00, byteFour = 0x00;

        // Create a buffer that will store the sample bytes as they are read
        ByteBuffer sampleBuffer = ByteBuffer.allocate(getBufferSize());

        // create a byte buffer to store bytes from the TCP stream
        ByteBuffer buffer = ByteBuffer.allocateDirect(getBufferSize());

        // add a channel of data that will be pushed to the server.  
        // Each sample will be sent to the Data Turbine as an rbnb frame.
        ChannelMap rbnbChannelMap = new ChannelMap();

        // while there are bytes to read from the socket ...
        while (socket.read(buffer) != -1 || buffer.position() > 0) {

            // prepare the buffer for reading
            buffer.flip();

            // while there are unread bytes in the ByteBuffer
            while (buffer.hasRemaining()) {
                byteOne = buffer.get();
                logger.debug("char: " + (char) byteOne + "\t" + "b1: "
                        + new String(Hex.encodeHex((new byte[] { byteOne }))) + "\t" + "b2: "
                        + new String(Hex.encodeHex((new byte[] { byteTwo }))) + "\t" + "b3: "
                        + new String(Hex.encodeHex((new byte[] { byteThree }))) + "\t" + "b4: "
                        + new String(Hex.encodeHex((new byte[] { byteFour }))) + "\t" + "sample pos: "
                        + sampleBuffer.position() + "\t" + "sample rem: " + sampleBuffer.remaining() + "\t"
                        + "sample cnt: " + sampleByteCount + "\t" + "buffer pos: " + buffer.position() + "\t"
                        + "buffer rem: " + buffer.remaining() + "\t" + "state: " + state);

                // Use a State Machine to process the byte stream.
                switch (state) {

                case 0:

                    // sample sets begin with 'mvs 1\r\n' and end with 'mvs 0\r\n'.  Find the 
                    // beginning of the sample set using the 4-byte window (s 1\r\n)
                    // note bytes are in reverse order in the FIFO window
                    if (byteOne == 0x0A && byteTwo == 0x0D && byteThree == 0x31 && byteFour == 0x20) {
                        // we've found the beginning of a sample set, move on
                        state = 1;
                        break;

                    } else {
                        break;
                    }

                case 1: // read the rest of the bytes to the next EOL characters

                    // sample line is terminated by record delimiter byte (\r\n)
                    // note bytes are in reverse order in the FIFO window
                    if (byteOne == 0x0A && byteTwo == 0x0D && byteThree == 0x30 && byteFour == 0x20) {

                        // we've found the sample set ending, clear buffers and return
                        // to state 0 to wait for the next set
                        byteOne = 0x00;
                        byteTwo = 0x00;
                        byteThree = 0x00;
                        byteFour = 0x00;
                        sampleBuffer.clear();
                        sampleByteCount = 0;
                        rbnbChannelMap.Clear();
                        logger.debug("Cleared b1,b2,b3,b4. Cleared sampleBuffer. Cleared rbnbChannelMap.");
                        state = 0;

                        // if we're not at the sample set end, look for individual samples    
                    } else if (byteOne == 0x0A && byteTwo == 0x0D) {

                        // found the sample ending delimiter
                        // add in the sample delimiter to the sample buffer
                        if (sampleBuffer.remaining() > 0) {
                            sampleBuffer.put(byteOne);
                            sampleByteCount++;
                        } else {
                            sampleBuffer.compact();
                            logger.debug("Compacting sampleBuffer ...");
                            sampleBuffer.put(byteOne);
                            sampleByteCount++;

                        }

                        // extract just the length of the sample bytes out of the
                        // sample buffer, and place it in the channel map as a 
                        // byte array.  Then, send it to the data turbine.
                        byte[] sampleArray = new byte[sampleByteCount];
                        sampleBuffer.flip();
                        sampleBuffer.get(sampleArray);

                        // send the sample to the data turbine
                        rbnbChannelMap.PutTimeAuto("server");
                        String sampleString = new String(sampleArray, "US-ASCII");
                        int channelIndex = rbnbChannelMap.Add(getRBNBChannelName());
                        rbnbChannelMap.PutMime(channelIndex, "text/plain");
                        rbnbChannelMap.PutDataAsString(channelIndex, sampleString);
                        getSource().Flush(rbnbChannelMap);
                        logger.info("Sample: " + sampleString.substring(0, sampleString.length() - 2)
                                + " sent data to the DataTurbine. ");
                        byteOne = 0x00;
                        byteTwo = 0x00;
                        byteThree = 0x00;
                        byteFour = 0x00;
                        sampleBuffer.clear();
                        sampleByteCount = 0;
                        rbnbChannelMap.Clear();
                        logger.debug("Cleared b1,b2,b3,b4. Cleared sampleBuffer. Cleared rbnbChannelMap.");
                        break;

                    } else { // not 0x0

                        // still in the middle of the sample, keep adding bytes
                        sampleByteCount++; // add each byte found

                        if (sampleBuffer.remaining() > 0) {
                            sampleBuffer.put(byteOne);
                        } else {
                            sampleBuffer.compact();
                            logger.debug("Compacting sampleBuffer ...");
                            sampleBuffer.put(byteOne);

                        }

                        break;
                    } // end if for 0x0D20 EOL

                } // end switch statement

                // shift the bytes in the FIFO window
                byteFour = byteThree;
                byteThree = byteTwo;
                byteTwo = byteOne;

            } //end while (more unread bytes)

            // prepare the buffer to read in more bytes from the stream
            buffer.compact();

        } // end while (more socket bytes to read)
        socket.close();

    } catch (IOException e) {
        // handle exceptions
        // In the event of an i/o exception, log the exception, and allow execute()
        // to return false, which will prompt a retry.
        failed = true;
        e.printStackTrace();
        return !failed;
    } catch (SAPIException sapie) {
        // In the event of an RBNB communication  exception, log the exception, 
        // and allow execute() to return false, which will prompt a retry.
        failed = true;
        sapie.printStackTrace();
        return !failed;
    }

    return !failed;
}

From source file:edu.hawaii.soest.kilonalu.tchain.TChainSource.java

/**
 * A method that executes the streaming of data from the source to the RBNB
 * server after all configuration of settings, connections to hosts, and
 * thread initiatizing occurs.  This method contains the detailed code for 
 * streaming the data and interpreting the stream.
 *//*from  w  ww . j av a 2s  . c  o m*/
protected boolean execute() {
    logger.debug("TChainSource.execute() called.");
    // do not execute the stream if there is no connection
    if (!isConnected())
        return false;

    boolean failed = false;

    SocketChannel socket = getSocketConnection();

    // while data are being sent, read them into the buffer
    try {
        // create four byte placeholders used to evaluate up to a four-byte 
        // window.  The FIFO layout looks like:
        //           -------------------------
        //   in ---> | One | Two |Three|Four |  ---> out
        //           -------------------------
        byte byteOne = 0x00, // set initial placeholder values
                byteTwo = 0x00, byteThree = 0x00, byteFour = 0x00;

        // Create a buffer that will store the sample bytes as they are read
        ByteBuffer sampleBuffer = ByteBuffer.allocate(getBufferSize());

        // create a byte buffer to store bytes from the TCP stream
        ByteBuffer buffer = ByteBuffer.allocateDirect(getBufferSize());

        // add a channel of data that will be pushed to the server.  
        // Each sample will be sent to the Data Turbine as an rbnb frame.
        ChannelMap rbnbChannelMap = new ChannelMap();

        // while there are bytes to read from the socket ...
        while (socket.read(buffer) != -1 || buffer.position() > 0) {

            // prepare the buffer for reading
            buffer.flip();

            // while there are unread bytes in the ByteBuffer
            while (buffer.hasRemaining()) {
                byteOne = buffer.get();
                logger.debug("char: " + (char) byteOne + "\t" + "b1: "
                        + new String(Hex.encodeHex((new byte[] { byteOne }))) + "\t" + "b2: "
                        + new String(Hex.encodeHex((new byte[] { byteTwo }))) + "\t" + "b3: "
                        + new String(Hex.encodeHex((new byte[] { byteThree }))) + "\t" + "b4: "
                        + new String(Hex.encodeHex((new byte[] { byteFour }))) + "\t" + "sample pos: "
                        + sampleBuffer.position() + "\t" + "sample rem: " + sampleBuffer.remaining() + "\t"
                        + "sample cnt: " + sampleByteCount + "\t" + "buffer pos: " + buffer.position() + "\t"
                        + "buffer rem: " + buffer.remaining() + "\t" + "state: " + state);

                // Use a State Machine to process the byte stream.
                // Start building an rbnb frame for the entire sample, first by 
                // inserting a timestamp into the channelMap.  This time is merely
                // the time of insert into the data turbine, not the time of
                // observations of the measurements.  That time should be parsed out
                // of the sample in the Sink client code

                switch (state) {

                case 0:

                    // sample line ending is '\r\n' (carraige return, newline)
                    // note bytes are in reverse order in the FIFO window
                    if (byteOne == this.firstDelimiterByte && byteTwo == this.secondDelimiterByte) {
                        // we've found the end of a sample, move on
                        state = 1;
                        break;

                    } else {
                        break;
                    }

                case 1: // read the rest of the bytes to the next EOL characters

                    // sample line is terminated by record delimiter bytes (usually \r\n or \n)
                    // note bytes are in reverse order in the FIFO window
                    if (byteOne == this.firstDelimiterByte && byteTwo == this.secondDelimiterByte) {

                        // rewind the sample to overwrite the line ending so we can add
                        // in the timestamp (then add the line ending)
                        sampleBuffer.position(sampleBuffer.position() - 1);
                        --sampleByteCount;

                        // add the delimiter to the end of the sample.
                        byte[] delimiterAsBytes = getFieldDelimiter().getBytes("US-ASCII");

                        for (byte delim : delimiterAsBytes) {
                            sampleBuffer.put(delim);
                            sampleByteCount++;
                        }

                        // then add a timestamp to the end of the sample
                        DATE_FORMAT.setTimeZone(TZ);
                        byte[] sampleDateAsBytes = DATE_FORMAT.format(new Date()).getBytes("US-ASCII");
                        for (byte b : sampleDateAsBytes) {
                            sampleBuffer.put(b);
                            sampleByteCount++;
                        }

                        // add the last two bytes found (usually \r\n) to the sample buffer
                        if (sampleBuffer.remaining() > 0) {
                            sampleBuffer.put(byteOne);
                            sampleByteCount++;
                            sampleBuffer.put(byteTwo);
                            sampleByteCount++;

                        } else {
                            sampleBuffer.compact();
                            sampleBuffer.put(byteOne);
                            sampleByteCount++;
                            sampleBuffer.put(byteTwo);
                            sampleByteCount++;

                        }

                        // extract just the length of the sample bytes out of the
                        // sample buffer, and place it in the channel map as a 
                        // byte array.  Then, send it to the data turbine.
                        byte[] sampleArray = new byte[sampleByteCount];
                        sampleBuffer.flip();
                        sampleBuffer.get(sampleArray);

                        // send the sample to the data turbine
                        rbnbChannelMap.PutTimeAuto("server");
                        String sampleString = new String(sampleArray, "US-ASCII");
                        int channelIndex = rbnbChannelMap.Add(getRBNBChannelName());
                        rbnbChannelMap.PutMime(channelIndex, "text/plain");
                        rbnbChannelMap.PutDataAsString(channelIndex, sampleString);
                        getSource().Flush(rbnbChannelMap);
                        logger.info("Sample: " + sampleString.substring(0, sampleString.length() - 2)
                                + " sent data to the DataTurbine. ");

                        byteOne = 0x00;
                        byteTwo = 0x00;
                        byteThree = 0x00;
                        byteFour = 0x00;
                        sampleBuffer.clear();
                        sampleByteCount = 0;
                        rbnbChannelMap.Clear();
                        logger.debug("Cleared b1,b2,b3,b4. Cleared sampleBuffer. Cleared rbnbChannelMap.");
                        //state = 0;

                    } else { // not 0x0D20

                        // still in the middle of the sample, keep adding bytes
                        sampleByteCount++; // add each byte found

                        if (sampleBuffer.remaining() > 0) {
                            sampleBuffer.put(byteOne);
                        } else {
                            sampleBuffer.compact();
                            logger.debug("Compacting sampleBuffer ...");
                            sampleBuffer.put(byteOne);

                        }

                        break;
                    } // end if for 0x0D20 EOL

                } // end switch statement

                // shift the bytes in the FIFO window
                byteFour = byteThree;
                byteThree = byteTwo;
                byteTwo = byteOne;

            } //end while (more unread bytes)

            // prepare the buffer to read in more bytes from the stream
            buffer.compact();

        } // end while (more socket bytes to read)
        socket.close();

    } catch (IOException e) {
        // handle exceptions
        // In the event of an i/o exception, log the exception, and allow execute()
        // to return false, which will prompt a retry.
        failed = true;
        e.printStackTrace();
        return !failed;
    } catch (SAPIException sapie) {
        // In the event of an RBNB communication  exception, log the exception, 
        // and allow execute() to return false, which will prompt a retry.
        failed = true;
        sapie.printStackTrace();
        return !failed;
    }

    return !failed;
}

From source file:edu.hawaii.soest.kilonalu.adcp.ADCPSource.java

/**
 * A method that executes the streaming of data from the source to the RBNB
 * server after all configuration of settings, connections to hosts, and
 * thread initiatizing occurs.  This method contains the detailed code for 
 * streaming the data and interpreting the stream.
 *//*from  ww  w .  ja v  a2  s.com*/
protected boolean execute() {

    // do not execute the stream if there is no connection
    if (!isConnected())
        return false;

    boolean failed = false;

    SocketChannel socket = getSocketConnection();

    // while data are being sent, read them into the buffer
    try {
        // create four byte placeholders used to evaluate up to a four-byte 
        // window.  The FIFO layout looks like:
        //           -------------------------
        //   in ---> | One | Two |Three|Four |  ---> out
        //           -------------------------
        byte byteOne = 0x00, // set initial placeholder values
                byteTwo = 0x00, byteThree = 0x00, byteFour = 0x00;

        // Create a buffer that will store the ensemble bytes as they are read
        ByteBuffer ensembleBuffer = ByteBuffer.allocate(getBufferSize());

        // create a byte buffer to store bytes from the TCP stream
        ByteBuffer buffer = ByteBuffer.allocateDirect(getBufferSize());

        // add a channel of data that will be pushed to the server.  
        // Each ensemble will be sent to the Data Turbine as an rbnb frame.
        ChannelMap rbnbChannelMap = new ChannelMap();
        int channelIndex = rbnbChannelMap.Add(getRBNBChannelName());

        // while there are bytes to read from the socket ...
        while (socket.read(buffer) != -1 || buffer.position() > 0) {
            // prepare the buffer for reading
            buffer.flip();

            // while there are unread bytes in the ByteBuffer
            while (buffer.hasRemaining()) {
                byteOne = buffer.get();

                // Use a State Machine to process the byte stream.
                // Start building an rbnb frame for the entire ensemble, first by 
                // inserting a timestamp into the channelMap.  This time is merely
                // the time of insert into the data turbine, not the time of
                // observations of the measurements.  That time should be parsed out
                // of the ensemble in the Sink client code

                System.out.print("\rProcessed byte # " + ensembleByteCount + " "
                        + new String(Hex.encodeHex((new byte[] { byteOne }))) + " - log msg is: ");

                switch (state) {

                case 0: // find ensemble header id
                    if (byteOne == 0x7F && byteTwo == 0x7F) {
                        ensembleByteCount++; // add Header ID
                        ensembleChecksum += (byteTwo & 0xFF);
                        ensembleByteCount++; // add Data Source ID
                        ensembleChecksum += (byteOne & 0xFF);

                        state = 1;
                        break;

                    } else {
                        break;

                    }

                case 1: // find the Ensemble Length (LSB)
                    ensembleByteCount++; // add Ensemble Byte Count (LSB)
                    ensembleChecksum += (byteOne & 0xFF);

                    state = 2;
                    break;

                case 2: // find the Ensemble Length (MSB)
                    ensembleByteCount++; // add Ensemble Byte Count (MSB)
                    ensembleChecksum += (byteOne & 0xFF);

                    int upperEnsembleByte = (byteOne & 0xFF) << 8;
                    int lowerEnsembleByte = (byteTwo & 0xFF);
                    ensembleBytes = upperEnsembleByte + lowerEnsembleByte;
                    logger.debug("Number of Bytes in the Ensemble: " + ensembleBytes);

                    if (ensembleBuffer.remaining() > 0) {

                        ensembleBuffer.put(byteFour);
                        ensembleBuffer.put(byteThree);
                        ensembleBuffer.put(byteTwo);
                        ensembleBuffer.put(byteOne);
                    } else {

                        ensembleBuffer.compact();
                        ensembleBuffer.put(byteFour);
                        ensembleBuffer.put(byteThree);
                        ensembleBuffer.put(byteTwo);
                        ensembleBuffer.put(byteOne);
                    }

                    state = 3;
                    break;

                // verify that the header is real, not a random 0x7F7F
                case 3: // find the number of data types in the ensemble

                    // set the numberOfDataTypes byte
                    if (ensembleByteCount == NUMBER_OF_DATA_TYPES_OFFSET - 1) {
                        ensembleByteCount++;
                        ensembleChecksum += (byteOne & 0xFF);
                        numberOfDataTypes = (byteOne & 0xFF);
                        // calculate the number of bytes to the Fixed Leader ID
                        dataTypeOneOffset = 6 + (2 * numberOfDataTypes);

                        if (ensembleBuffer.remaining() > 0) {
                            ensembleBuffer.put(byteOne);

                        } else {
                            ensembleBuffer.compact();
                            ensembleBuffer.put(byteOne);

                        }
                        state = 4;
                        break;

                    } else {
                        ensembleByteCount++;
                        ensembleChecksum += (byteOne & 0xFF);

                        if (ensembleBuffer.remaining() > 0) {
                            ensembleBuffer.put(byteOne);

                        } else {
                            ensembleBuffer.compact();
                            ensembleBuffer.put(byteOne);

                        }

                        break;
                    }

                case 4: // find the offset to data type #1 and verify the header ID
                    if ((ensembleByteCount == dataTypeOneOffset + 1) && byteOne == 0x00 && byteTwo == 0x00) {
                        ensembleByteCount++;
                        ensembleChecksum += (byteOne & 0xFF);
                        // we are confident that the previous sequence of 0x7F7F is truly
                        // an headerID and not a random occurrence in the stream because
                        // we have identified the Fixed Leader ID (0x0000) the correct
                        // number of bytes beyond the 0x7F7F
                        headerIsVerified = true;

                        if (ensembleBuffer.remaining() > 0) {
                            ensembleBuffer.put(byteOne);

                        } else {
                            ensembleBuffer.compact();
                            ensembleBuffer.put(byteOne);

                        }

                        state = 5;
                        break;

                    } else {

                        if (ensembleByteCount > dataTypeOneOffset + 1) {
                            // We've hit a random 0x7F7F byte sequence that is not a true
                            // ensemble header id.  Reset the processing and look for the 
                            // next 0x7F7F sequence in the stream
                            ensembleByteCount = 0;
                            ensembleChecksum = 0;
                            dataTypeOneOffset = 0;
                            numberOfDataTypes = 0;
                            headerIsVerified = false;
                            ensembleBuffer.clear();
                            rbnbChannelMap.Clear();
                            channelIndex = rbnbChannelMap.Add(getRBNBChannelName());

                            byteOne = 0x00;
                            byteTwo = 0x00;
                            byteThree = 0x00;
                            byteFour = 0x00;

                            state = 0;

                            if (ensembleBuffer.remaining() > 0) {
                                ensembleBuffer.put(byteOne);

                            } else {
                                ensembleBuffer.compact();
                                ensembleBuffer.put(byteOne);

                            }

                            break;

                        } else {
                            // We are still parsing bytes between the purported header ID
                            // and fixed leader ID. Keep parsing until we hit the fixed
                            // leader ID, or until we are greater than the dataTypeOneOffset
                            // stated value.
                            ensembleByteCount++;
                            ensembleChecksum += (byteOne & 0xFF);

                            if (ensembleBuffer.remaining() > 0) {
                                ensembleBuffer.put(byteOne);

                            } else {
                                ensembleBuffer.compact();
                                ensembleBuffer.put(byteOne);

                            }

                            break;
                        }

                    }

                case 5: // read the rest of the bytes to the next Header ID 

                    // if we've made it to the next ensemble's header id, prepare to
                    // flush the data.  Also check that the calculated byte count 
                    // is greater than the recorded byte count in case of finding an
                    // arbitrary 0x7f 0x7f sequence in the data stream
                    if (byteOne == 0x7F && byteTwo == 0x7F && (ensembleByteCount == ensembleBytes + 3)
                            && headerIsVerified) {

                        // remove the last bytes from the count (byteOne and byteTwo)
                        ensembleByteCount -= 1;

                        // remove the last three bytes from the checksum: 
                        // the two checksum bytes are not included, and the two 0x7f 
                        //bytes belong to the next ensemble, and one of them was 
                        // previously added. Reset the buffer position due to this too.
                        //ensembleChecksum -= (byteOne   & 0xFF);
                        ensembleChecksum -= (byteTwo & 0xFF);
                        ensembleChecksum -= (byteThree & 0xFF);
                        ensembleChecksum -= (byteFour & 0xFF);
                        // We are consistently 1 byte over in the checksum.  Trim it.  We need to
                        // troubleshoot why this is. CSJ 12/18/2007
                        ensembleChecksum = ensembleChecksum - 1;

                        // jockey byteThree into LSB, byteFour into MSB
                        int upperChecksumByte = (byteThree & 0xFF) << 8;
                        int lowerChecksumByte = (byteFour & 0xFF);
                        int trueChecksum = upperChecksumByte + lowerChecksumByte;

                        if (ensembleBuffer.remaining() > 0) {
                            ensembleBuffer.put((byte) lowerChecksumByte);
                            ensembleBuffer.put((byte) (upperChecksumByte >> 8));
                        } else {
                            ensembleBuffer.compact();
                            ensembleBuffer.put((byte) lowerChecksumByte);
                            ensembleBuffer.put((byte) (upperChecksumByte >> 8));
                        }

                        // check if the calculated checksum (modulo 65535) is equal
                        // to the true checksum; if so, flush to the data turbine
                        // Also, if the checksums are off by 1 byte, also flush the
                        // data.  We need to troubleshoot this bug CSJ 06/11/2008
                        if (((ensembleChecksum % 65535) == trueChecksum)
                                || ((ensembleChecksum + 1) % 65535 == trueChecksum)
                                || ((ensembleChecksum - 1) % 65535 == trueChecksum)) {

                            // extract just the length of the ensemble bytes out of the
                            // ensemble buffer, and place it in the channel map as a 
                            // byte array.  Then, send it to the data turbine.
                            byte[] ensembleArray = new byte[ensembleByteCount];
                            ensembleBuffer.flip();
                            ensembleBuffer.get(ensembleArray);

                            // send the ensemble to the data turbine
                            rbnbChannelMap.PutTimeAuto("server");
                            rbnbChannelMap.PutDataAsByteArray(channelIndex, ensembleArray);
                            getSource().Flush(rbnbChannelMap);
                            logger.debug("flushed: " + ensembleByteCount + " " + "ens cksum: "
                                    + ensembleChecksum + "\t\t" + "ens pos: " + ensembleBuffer.position() + "\t"
                                    + "ens rem: " + ensembleBuffer.remaining() + "\t" + "buf pos: "
                                    + buffer.position() + "\t" + "buf rem: " + buffer.remaining() + "\t"
                                    + "state: " + state);
                            logger.info("Sent ADCP ensemble to the data turbine.");

                            // only clear all four bytes if we are not one or two bytes 
                            // from the end of the byte buffer (i.e. the header id 
                            // is split or is all in the previous buffer)
                            if (byteOne == 0x7f && byteTwo == 0x7f && ensembleByteCount > ensembleBytes
                                    && buffer.position() == 0) {
                                byteThree = 0x00;
                                byteFour = 0x00;
                                logger.debug("Cleared ONLY b3, b4.");
                            } else if (byteOne == 0x7f && ensembleByteCount > ensembleBytes
                                    && buffer.position() == 1) {
                                buffer.position(buffer.position() - 1);
                                byteTwo = 0x00;
                                byteThree = 0x00;
                                byteFour = 0x00;
                                logger.debug("Cleared ONLY b2, b3, b4.");

                            } else {
                                byteOne = 0x00;
                                byteTwo = 0x00;
                                byteThree = 0x00;
                                byteFour = 0x00;
                                logger.debug("Cleared ALL b1, b2, b3, b4.");
                            }

                            //rewind the position to before the next ensemble's header id
                            if (buffer.position() >= 2) {
                                buffer.position(buffer.position() - 2);
                                logger.debug("Moved position back two, now: " + buffer.position());
                            }

                            ensembleBuffer.clear();
                            ensembleByteCount = 0;
                            ensembleBytes = 0;
                            ensembleChecksum = 0;
                            state = 0;
                            break;

                        } else {

                            // The checksums don't match, move on 
                            logger.info("not equal: " + "calc chksum: " + (ensembleChecksum % 65535)
                                    + "\tens chksum: " + trueChecksum + "\tbuf pos: " + buffer.position()
                                    + "\tbuf rem: " + buffer.remaining() + "\tens pos: "
                                    + ensembleBuffer.position() + "\tens rem: " + ensembleBuffer.remaining()
                                    + "\tstate: " + state);

                            rbnbChannelMap.Clear();
                            channelIndex = rbnbChannelMap.Add(getRBNBChannelName());
                            ensembleBuffer.clear();
                            ensembleByteCount = 0;
                            ensembleChecksum = 0;
                            ensembleBuffer.clear();
                            state = 0;
                            break;
                        }

                    } else {

                        // still in the middle of the ensemble, keep adding bytes
                        ensembleByteCount++; // add each byte found
                        ensembleChecksum += (byteOne & 0xFF);

                        if (ensembleBuffer.remaining() > 0) {
                            ensembleBuffer.put(byteOne);

                        } else {
                            ensembleBuffer.compact();
                            ensembleBuffer.put(byteOne);

                        }

                        break;
                    }
                }
                // shift the bytes in the FIFO window
                byteFour = byteThree;
                byteThree = byteTwo;
                byteTwo = byteOne;

                logger.debug("remaining:\t" + buffer.remaining() + "\tstate:\t" + state + "\tens byte count:\t"
                        + ensembleByteCount + "\tens bytes:\t" + ensembleBytes + "\tver:\t" + headerIsVerified
                        + "\tbyte value:\t" + new String(Hex.encodeHex((new byte[] { byteOne }))));
            } //end while (more unread bytes)

            // prepare the buffer to read in more bytes from the stream
            buffer.compact();

        } // end while (more socket bytes to read)
        socket.close();

    } catch (IOException e) {
        // handle exceptions
        // In the event of an i/o exception, log the exception, and allow execute()
        // to return false, which will prompt a retry.
        failed = true;
        e.printStackTrace();
        return !failed;
    } catch (SAPIException sapie) {
        // In the event of an RBNB communication  exception, log the exception, 
        // and allow execute() to return false, which will prompt a retry.
        failed = true;
        sapie.printStackTrace();
        return !failed;
    }

    return !failed;
}

From source file:co.elastic.tealess.SSLChecker.java

private void checkHandshake(SSLReport sslReport, SocketChannel socket) {
    final InetSocketAddress address = sslReport.getAddress();
    final String name = sslReport.getHostname();
    IOObserver ioObserver = new IOObserver();
    ObservingSSLEngine sslEngine = new ObservingSSLEngine(ctx.createSSLEngine(name, address.getPort()),
            ioObserver);/*from w w  w .  j  a v  a 2s  .  c o  m*/
    sslReport.setIOObserver(ioObserver);
    sslEngine.setUseClientMode(true);

    try {
        sslEngine.beginHandshake();
    } catch (SSLException e) {
        sslReport.setFailed(e);
        Throwable cause = Blame.get(e);
        logger.warn("beginHandshake failed: [{}] {}", cause.getClass(), cause.getMessage());
    }

    // TODO: Is this enough bytes?
    int size = sslEngine.getSession().getApplicationBufferSize() * 2;
    ByteBuffer localText = ByteBuffer.allocate(size);
    ByteBuffer localWire = ByteBuffer.allocate(size);
    ByteBuffer peerText = ByteBuffer.allocate(size);
    ByteBuffer peerWire = ByteBuffer.allocate(size);

    // TODO: I wonder... do we need to send any data at all?
    localText.put("SSL TEST. HELLO.".getBytes());
    localText.flip();

    SSLEngineResult result;
    logger.info("Starting SSL handshake [{}] ", address);
    try {
        SSLEngineResult.HandshakeStatus state;
        state = sslEngine.getHandshakeStatus();
        while (state != FINISHED) {
            // XXX: Use a Selector to wait for data.
            //logger.trace("State: {} [{}]", state, address);
            switch (state) {
            case NEED_TASK:
                sslEngine.getDelegatedTask().run();
                state = sslEngine.getHandshakeStatus();
                break;
            case NEED_WRAP:
                localWire.clear();
                result = sslEngine.wrap(localText, localWire);
                state = result.getHandshakeStatus();
                localWire.flip();
                while (localWire.hasRemaining()) {
                    socket.write(localWire);
                    //logger.trace("Sent {} bytes [{}]", bytes, address);
                }
                localWire.compact();
                break;
            case NEED_UNWRAP:
                // Try reading until we get data.
                Selector selector = Selector.open();
                while (peerWire.position() == 0) {
                    socket.read(peerWire);
                    try {
                        Thread.currentThread().sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("Read " + peerWire.position() + " bytes");
                peerWire.flip();
                result = sslEngine.unwrap(peerWire, peerText);
                state = result.getHandshakeStatus();
                peerWire.compact();
                break;
            }
        }
    } catch (IOException e) {
        sslReport.setFailed(e);
        sslReport.setSSLSession(sslEngine.getHandshakeSession());
        sslReport.setPeerCertificateDetails(peerCertificateDetails);
        logger.warn("beginHandshake failed", e);
        return;
    }

    logger.info("handshake completed [{}]", address);

    // Handshake OK!
    sslReport.setSSLSession(sslEngine.getSession());
}

From source file:HttpDownloadManager.java

public void run() {
    log.info("HttpDownloadManager thread starting.");

    // The download thread runs until release() is called
    while (!released) {
        // The thread blocks here waiting for something to happen
        try {/*from   w  w w.  j  a  va2 s .c  o m*/
            selector.select();
        } catch (IOException e) {
            // This should never happen.
            log.log(Level.SEVERE, "Error in select()", e);
            return;
        }

        // If release() was called, the thread should exit.
        if (released)
            break;

        // If any new Download objects are pending, deal with them first
        if (!pendingDownloads.isEmpty()) {
            // Although pendingDownloads is a synchronized list, we still
            // need to use a synchronized block to iterate through its
            // elements to prevent a concurrent call to download().
            synchronized (pendingDownloads) {
                Iterator iter = pendingDownloads.iterator();
                while (iter.hasNext()) {
                    // Get the pending download object from the list
                    DownloadImpl download = (DownloadImpl) iter.next();
                    iter.remove(); // And remove it.

                    // Now begin an asynchronous connection to the
                    // specified host and port. We don't block while
                    // waiting to connect.
                    SelectionKey key = null;
                    SocketChannel channel = null;
                    try {
                        // Open an unconnected channel
                        channel = SocketChannel.open();
                        // Put it in non-blocking mode
                        channel.configureBlocking(false);
                        // Register it with the selector, specifying that
                        // we want to know when it is ready to connect
                        // and when it is ready to read.
                        key = channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_CONNECT,
                                download);
                        // Create the web server address
                        SocketAddress address = new InetSocketAddress(download.host, download.port);
                        // Ask the channel to start connecting
                        // Note that we don't send the HTTP request yet.
                        // We'll do that when the connection completes.
                        channel.connect(address);
                    } catch (Exception e) {
                        handleError(download, channel, key, e);
                    }
                }
            }
        }

        // Now get the set of keys that are ready for connecting or reading
        Set keys = selector.selectedKeys();
        if (keys == null)
            continue; // bug workaround; should not be needed
        // Loop through the keys in the set
        for (Iterator i = keys.iterator(); i.hasNext();) {
            SelectionKey key = (SelectionKey) i.next();
            i.remove(); // Remove the key from the set before handling

            // Get the Download object we attached to the key
            DownloadImpl download = (DownloadImpl) key.attachment();
            // Get the channel associated with the key.
            SocketChannel channel = (SocketChannel) key.channel();

            try {
                if (key.isConnectable()) {
                    // If the channel is ready to connect, complete the
                    // connection and then send the HTTP GET request to it.
                    if (channel.finishConnect()) {
                        download.status = Status.CONNECTED;
                        // This is the HTTP request we wend
                        String request = "GET " + download.path + " HTTP/1.1\r\n" + "Host: " + download.host
                                + "\r\n" + "Connection: close\r\n" + "\r\n";
                        // Wrap in a CharBuffer and encode to a ByteBuffer
                        ByteBuffer requestBytes = LATIN1.encode(CharBuffer.wrap(request));
                        // Send the request to the server. If the bytes
                        // aren't all written in one call, we busy loop!
                        while (requestBytes.hasRemaining())
                            channel.write(requestBytes);

                        log.info("Sent HTTP request: " + download.host + ":" + download.port + ": " + request);
                    }
                }
                if (key.isReadable()) {
                    // If the key indicates that there is data to be read,
                    // then read it and store it in the Download object.
                    int numbytes = channel.read(buffer);

                    // If we read some bytes, store them, otherwise
                    // the download is complete and we need to note this
                    if (numbytes != -1) {
                        buffer.flip(); // Prepare to drain the buffer
                        download.addData(buffer); // Store the data
                        buffer.clear(); // Prepare for another read
                        log.info("Read " + numbytes + " bytes from " + download.host + ":" + download.port);
                    } else {
                        // If there are no more bytes to read
                        key.cancel(); // We're done with the key
                        channel.close(); // And with the channel.
                        download.status = Status.DONE;
                        if (download.listener != null) // notify listener
                            download.listener.done(download);
                        log.info("Download complete from " + download.host + ":" + download.port);
                    }
                }
            } catch (Exception e) {
                handleError(download, channel, key, e);
            }
        }
    }
    log.info("HttpDownloadManager thread exiting.");
}