private IStream createStream( SynStreamFrame frame, StreamFrameListener listener, boolean local, Promise<Stream> promise) { IStream associatedStream = streams.get(frame.getAssociatedStreamId()); IStream stream = new StandardStream( frame.getStreamId(), frame.getPriority(), this, associatedStream, promise); flowControlStrategy.onNewStream(this, stream); stream.updateCloseState(frame.isClose(), local); stream.setStreamFrameListener(listener); if (stream.isUnidirectional()) { // Unidirectional streams are implicitly half closed stream.updateCloseState(true, !local); if (!stream.isClosed()) stream.getAssociatedStream().associate(stream); } int streamId = stream.getId(); if (local) { while (true) { int oldStreamCountValue = localStreamCount.get(); int maxConcurrentStreams = maxConcurrentLocalStreams; if (maxConcurrentStreams > -1 && oldStreamCountValue >= maxConcurrentStreams) { String message = String.format("Max concurrent local streams (%d) exceeded.", maxConcurrentStreams); LOG.debug(message); promise.failed(new SPDYException(message)); return null; } if (localStreamCount.compareAndSet(oldStreamCountValue, oldStreamCountValue + 1)) break; } } if (streams.putIfAbsent(streamId, stream) != null) { String message = "Duplicate stream id " + streamId; IllegalStateException duplicateIdException = new IllegalStateException(message); promise.failed(duplicateIdException); if (local) { localStreamCount.decrementAndGet(); throw duplicateIdException; } RstInfo rstInfo = new RstInfo(streamId, StreamStatus.PROTOCOL_ERROR); LOG.debug("Duplicate stream, {}", rstInfo); rst(rstInfo, new Callback.Adapter()); // We don't care (too much) if the reset fails. return null; } else { LOG.debug("Created {}", stream); notifyStreamCreated(stream); return stream; } }
@Override public void complete() { bufferPool.release(buffer); IStream stream = getStream(); dataInfo.consume(size); flowControlStrategy.updateWindow(StandardSession.this, stream, -size); if (dataInfo.available() > 0) { // We have written a frame out of this DataInfo, but there is more to write. // We need to keep the correct ordering of frames, to avoid that another // DataInfo for the same stream is written before this one is finished. prepend(this); flush(); } else { super.complete(); stream.updateCloseState(dataInfo.isClose(), true); if (stream.isClosed()) removeStream(stream); } }