All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.webpieces.http2engine.impl.shared.StreamState Maven / Gradle / Ivy

package com.webpieces.http2engine.impl.shared;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.webpieces.util.time.Time;

import com.webpieces.http2.api.dto.error.CancelReasonCode;
import com.webpieces.http2.api.dto.error.ConnectionException;
import com.webpieces.http2.api.dto.error.StreamException;
import com.webpieces.http2.api.dto.highlevel.Http2Headers;
import com.webpieces.http2.api.dto.lowlevel.lib.Http2Msg;
import com.webpieces.http2engine.impl.shared.data.Stream;

/**
 * WAY TOOO MANY IF statements in here...need a ClientStreamState AND a ServerStreamState so we can get rid of the if statements
 * @author dhiller
 *
 */
public class StreamState {

	private final static Logger log = LoggerFactory.getLogger(StreamState.class);

	private ConcurrentMap streamIdToStream = new ConcurrentHashMap<>();
	private long highestOddStream = 0;
	private long highestEvenStream = 0;
	
	//we need to time out closing streams  BUT just reuse the threads!!! do not use a timer thread
	private Time time;
	private String logId;

	public StreamState(Time time, String logId) {
		this.time = time;
		this.logId = logId;
	}

	//chanmgr thread only
	public ConcurrentMap closeEngine() {
		return streamIdToStream;
	}
	
	public boolean isLargeEnough(Http2Headers frame) {
		int id = frame.getStreamId();
		if(id % 1 == 0) {
			if(id > highestOddStream)
				return true;
		} else {
			if(id > highestEvenStream)
				return true;
		}
		return false;
	}
	
	//client threads
	public Stream create(Stream stream) {
		int id = stream.getStreamId();
		if(id % 2 == 0) {
			if(id < highestEvenStream)
				throw new IllegalStateException("stream id="+id+" is too low and must be higher than="+highestEvenStream);
			highestEvenStream = id;
		} else {
			if(id < highestOddStream)
				throw new IllegalStateException("stream id="+id+" is too low and must be higher than="+highestOddStream);
			highestOddStream = id;			
		}
			
		Stream oldStream = streamIdToStream.putIfAbsent(id, stream);
		if(oldStream == stream)
			throw new IllegalStateException("stream id="+id+" already exists");
		return stream;
	}
	
	public boolean isStreamExist(Http2Msg frame) {
		Stream stream = streamIdToStream.get(frame.getStreamId());
		return stream != null;
	}
	
	public Stream getStream(Http2Msg frame, boolean isConnectionError) {
		Stream stream = streamIdToStream.get(frame.getStreamId());
		if (stream == null) {
			int id = frame.getStreamId();
			if(id % 2 == 0) {
				check(frame, id, highestEvenStream, isConnectionError);
			} else {
				check(frame, id, highestOddStream, isConnectionError);
			}			
		}
		return stream;
	}

	private void check(Http2Msg frame, int id, long highestOpen, boolean isConnectionError) {
		if(id > highestOpen)
			throw new ConnectionException(CancelReasonCode.BAD_FRAME_RECEIVED_FOR_THIS_STATE, logId, id, "Stream in idle state and received this frame which should not happen in idle state.  frame="+frame);
		else if(isConnectionError)
			throw new ConnectionException(CancelReasonCode.CLOSED_STREAM, logId, id, "Stream must have been closed as it no longer exists.  high mark="+highestOpen+"  your frame="+frame);
		
		throw new StreamException(CancelReasonCode.CLOSED_STREAM, logId, id, "Stream must have been closed as it no longer exists.  high mark="+highestOpen+"  your frame="+frame);
	}

	//this method and create happen on a virtual single thread from channelmgr
	//so we do not need to synchronize
	public void updateAllStreams(long initialWindow) {
		for(Stream stream : streamIdToStream.values()) {
			stream.updateInitialWindow(initialWindow);
		}
	}

	public Stream remove(Stream stream, Object cause) {
		stream.setIsClosed(true);
		return streamIdToStream.remove(stream.getStreamId());
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy