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; } }
private void removeStream(IStream stream) { if (stream.isUnidirectional()) stream.getAssociatedStream().disassociate(stream); IStream removed = streams.remove(stream.getId()); if (removed != null) { assert removed == stream; if (streamIds.get() % 2 == stream.getId() % 2) localStreamCount.decrementAndGet(); LOG.debug("Removed {}", stream); notifyStreamClosed(stream); } }
private void processSyn(SessionFrameListener listener, IStream stream, SynStreamFrame frame) { stream.process(frame); // Update the last stream id before calling the application (which may send a GO_AWAY) updateLastStreamId(stream); StreamFrameListener streamListener; if (stream.isUnidirectional()) { PushInfo pushInfo = new PushInfo(frame.getHeaders(), frame.isClose()); streamListener = notifyOnPush(stream.getAssociatedStream().getStreamFrameListener(), stream, pushInfo); } else { SynInfo synInfo = new SynInfo(frame.getHeaders(), frame.isClose(), frame.getPriority()); streamListener = notifyOnSyn(listener, stream, synInfo); } stream.setStreamFrameListener(streamListener); flush(); // The onSyn() listener may have sent a frame that closed the stream if (stream.isClosed()) removeStream(stream); }