Beispiel #1
0
  /** No read-delimiters specified, so fire events as data segments arrive. */
  @SuppressWarnings("resource")
  private void readUnboundedRawLoop(Socket socket) throws IOException {
    CountableInputStream cis =
        new CountableInputStream(socket.getInputStream(), _counterRecvOps, _counterRecvRate);

    // create a buffer that'll be reused
    if (_buffer == null) _buffer = new byte[1024 * 10 * 2];

    while (!_shutdown) {
      int bytesRead = cis.read(_buffer);

      if (bytesRead <= 0) break;

      String segment = bufferToString(_buffer, 0, bytesRead);

      // fire the handler
      handleReceivedData(segment);
    }

    // the peer has gracefully closed down the connection or we're shutting down

    if (!_shutdown) {
      // then fire the disconnected callback
      Handler.tryHandle(_disconnectedCallback, _callbackErrorHandler);
    }
  }
Beispiel #2
0
  /** (convenience method) */
  private void sendBufferNow0(OutputStream os, byte[] buffer, String origData) {
    try {
      os.write(buffer);
    } catch (Exception exc) {
      // ignore
    }

    Handler.tryHandle(_sentCallback, origData, _callbackErrorHandler);
  }
Beispiel #3
0
  /**
   * The reading loop will continually read until an error occurs or the stream is gracefully ended
   * by the peer.
   *
   * <p>("resource" warning suppression applies to 'bis'. It's not valid because socket itself gets
   * closed)
   */
  @SuppressWarnings("resource")
  private void readTextLoop(Socket socket) throws Exception {
    InputStream in = socket.getInputStream();
    BufferedInputStream bis =
        new BufferedInputStream(
            new CountableInputStream(in, _counterRecvOps, _counterRecvRate), 1024);

    // create a buffer that'll be reused
    // start off small, will grow as needed
    BufferBuilder bb = new BufferBuilder(256);

    while (!_shutdown) {
      int c = bis.read();

      if (c < 0) break;

      if (charMatches((char) c, _receiveDelimiters)) {
        String str = bb.getTrimmedString();
        if (str != null) handleReceivedData(str);

        bb.reset();

      } else {
        if (bb.getSize() >= MAX_SEGMENT_ALLOWED) {
          // drop the connection
          throw new IOException(
              "Too much data arrived (at least "
                  + bb.getSize() / 1024
                  + " KB) before any delimeter was present; dropping connection.");
        }

        bb.append((byte) c);
      }
    } // (while)

    // the peer has gracefully closed down the connection or we're shutting down

    if (!_shutdown) {
      // send out last data
      String str = bb.getTrimmedString();
      if (str != null) handleReceivedData(str);

      // then fire the disconnected callback
      Handler.tryHandle(_disconnectedCallback, _callbackErrorHandler);
    }
  }
Beispiel #4
0
  /**
   * The reading loop will continually read until an error occurs or the stream is gracefully ended
   * by the peer.
   *
   * <p>(Suppress 'resource' ignored because 'in' stream is closed in calling function.)
   */
  @SuppressWarnings("resource")
  private void readLengthDelimitedLoop(Socket socket, char startFlag, Character optStopFlag)
      throws Exception {
    InputStream in = socket.getInputStream();
    BufferedInputStream bis =
        new BufferedInputStream(
            new CountableInputStream(in, _counterRecvOps, _counterRecvRate), 1024);

    // create a buffer that'll be reused
    // start off small, will grow as needed
    BufferBuilder bb = new BufferBuilder(256);

    // create an additional temporary buffer which can be used with 'length' delimited parsing
    byte[] buffer = new byte[1024];

    // got 'start flag'?
    boolean synced = false;

    // how many bytes to read
    int bytesToRead = 0;

    while (!_shutdown) {
      int c = bis.read();

      if (c < 0) break;

      // discard data until we sync up with the 'start' flag
      if (!synced) {
        if (c == startFlag) {
          synced = true;
          // (put back)
          bb.append(c);

          // read 'length' (value excludes 'start', 'stop' flags)
          int len1 = Stream.readUnsignedByte(bis);
          int len2 = Stream.readUnsignedByte(bis);

          int length = Stream.readUnsignedShort(len1, len2);

          if (length >= MAX_SEGMENT_ALLOWED)
            // drop the connection
            throw new IOException(
                "Packet length indicates it is too large to accept ("
                    + Formatting.formatByteLength(length)
                    + ").");

          // (put back)
          bb.append(len1);
          bb.append(len2);

          // already read 2 ('length') length
          bytesToRead = length - 2;
        } else {
          // not synced, so keep discarding
          continue;
        }
      }

      while (!_shutdown) {
        // we're synced, so can read as much as we need to

        if (bytesToRead > 0) {
          int bytesRead = bis.read(buffer, 0, Math.min(bytesToRead, buffer.length));
          if (bytesRead < 0) throw new EOFException();

          bytesToRead -= bytesRead;

          // 'copy' the buffer
          bb.append(buffer, 0, bytesRead);
        } else {
          // we've read enough
          break;
        }
      }

      if (optStopFlag != null) {
        c = Stream.readUnsignedByte(bis);

        if (c != optStopFlag.charValue())
          throw new IOException("Stop flag was not matched after reading the packet bytes.");

        // (put back)
        bb.append(c);

        // fire the handled event
        String str = bb.getRawString();
        handleReceivedData(str);

        bb.reset();

        synced = false;
      }
    } // (while)

    // the peer has gracefully closed down the connection or we're shutting down

    if (!_shutdown) {
      // drop left over data and fire the disconnected callback
      Handler.tryHandle(_disconnectedCallback, _callbackErrorHandler);
    }
  }
Beispiel #5
0
  /** Establishes a socket and continually reads. */
  private void connectAndRead() throws Exception {
    Socket socket = null;
    OutputStream os = null;

    try {
      socket = new Socket();
      InetSocketAddress socketAddress = parseAndResolveDestination(_dest);
      socket.connect(socketAddress, CONNECT_TIMEOUT);

      _counterConnections.incr();

      socket.setSoTimeout(_timeout);

      // 'inject' countable stream
      os = new CountableOutputStream(socket.getOutputStream(), _counterSendOps, _counterSendRate);

      // update flag
      _lastSuccessfulConnection = System.nanoTime();

      synchronized (_lock) {
        if (_shutdown) return;

        _socket = socket;
        _outputStream = os;

        // connection has been successful so reset variables
        // related to exponential back-off

        _recentlyConnected = true;

        _backoffTime = MIN_CONNETION_GAP;
      }

      // fire the connected event
      _callbackHandler.handle(_connectedCallback, _callbackErrorHandler);

      // start reading
      if (_mode == Modes.LengthDelimitedRaw)
        readLengthDelimitedLoop(socket, _binaryStartFlag, _binaryStopFlag);
      else if (_mode == Modes.CharacterDelimitedText) readTextLoop(socket);
      else { // mode is 'UnboundedRaw'
        readUnboundedRawLoop(socket);
      }

      // (any non-timeout exceptions will be propagated to caller...)

    } catch (Exception exc) {
      // fire the disconnected handler if was previously connected
      if (os != null) Handler.tryHandle(_disconnectedCallback, _callbackErrorHandler);

      throw exc;

    } finally {
      // always gracefully close the socket and invalidate the socket fields

      synchronized (_lock) {
        _socket = null;
        _outputStream = null;
      }

      Stream.safeClose(socket);
    }
  }