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

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

There is a newer version: 2.1.109
Show newest version
package com.webpieces.http2engine.impl.shared;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import org.webpieces.util.futures.XFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;

import org.webpieces.data.api.DataWrapper;
import org.webpieces.data.api.DataWrapperGenerator;
import org.webpieces.data.api.DataWrapperGeneratorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.webpieces.hpack.api.HpackParser;
import com.webpieces.hpack.api.MarshalState;
import com.webpieces.http2.api.dto.error.CancelReasonCode;
import com.webpieces.http2.api.dto.lowlevel.GoAwayFrame;
import com.webpieces.http2.api.dto.lowlevel.PingFrame;
import com.webpieces.http2.api.dto.lowlevel.lib.Http2Msg;
import com.webpieces.http2engine.api.error.ShutdownConnection;
import com.webpieces.http2engine.impl.shared.data.HeaderSettings;

public class Level7MarshalAndPing {

	private static final Logger log = LoggerFactory.getLogger(Level7MarshalAndPing.class);
	private static final DataWrapperGenerator dataGen = DataWrapperGeneratorFactory.createDataWrapperGenerator();

	private HpackParser parser;
	private EngineResultListener finalLayer;
	private HeaderSettings remoteSettings;
	private MarshalState marshalState;
	private AtomicReference> pingFutureRef;
	private String key;
	
	public Level7MarshalAndPing(String key, HpackParser parser, HeaderSettings remoteSettings, EngineResultListener finalLayer) {
		this.key = key;
		this.parser = parser;
		this.remoteSettings = remoteSettings;
		this.finalLayer = finalLayer;
		
		this.remoteSettings = remoteSettings;
        marshalState = parser.prepareToMarshal(remoteSettings.getHeaderTableSize(), remoteSettings.getMaxFrameSize());
	}
	
//	public XFuture sendControlFrameToClient(Http2Msg msg) {
//		return finalLayer.sendControlFrameToClient(msg);
//	}
	
	public XFuture sendPing() {
		PingFrame ping = new PingFrame();
		ping.setOpaqueData(8L);

		XFuture newFuture = new XFuture<>();
		boolean wasSet = pingFutureRef.compareAndSet(null, newFuture);
		if(!wasSet) {
			throw new IllegalStateException(key+"You must wait until the first ping you sent is complete.  2nd ping="+ping);
		}

		return sendFrameToSocket(ping)
				.thenCompose(c -> newFuture);
	}
	
	public XFuture processPing(PingFrame ping) {
		if(!ping.isPingResponse()) {
			PingFrame pingAck = new PingFrame();
			pingAck.setIsPingResponse(true);
			pingAck.setOpaqueData(ping.getOpaqueData());
			return sendFrameToSocket(pingAck);
		}

		XFuture future = pingFutureRef.get();
		if(future == null)
			throw new IllegalStateException(key+"bug, this should not be possible");

		pingFutureRef.compareAndSet(future, null); //clear the value
		future.complete(null);
		
		return XFuture.completedFuture(null);
	}

	public void setEncoderMaxTableSize(int value) {
		remoteSettings.setHeaderTableSize(value);
		marshalState.setOutgoingMaxTableSize(value);
	}
	
	public XFuture goAway(ShutdownConnection shutdown) {
		CancelReasonCode reason = shutdown.getReasonCode();
		byte[] bytes = shutdown.getReason().getBytes(StandardCharsets.UTF_8);
		DataWrapper debug = dataGen.wrapByteArray(bytes);

		GoAwayFrame frame = new GoAwayFrame();
		frame.setDebugData(debug);
		frame.setKnownErrorCode(reason.getErrorCode());

		XFuture future1 = sendControlDataToSocket(frame);
		finalLayer.closeSocket(shutdown);
		return future1;
	}
	
	public XFuture sendControlDataToSocket(Http2Msg msg) {
		int streamId = msg.getStreamId();
		if(streamId != 0)
			throw new IllegalArgumentException("control frame is not stream 0.  streamId="+streamId+" frame type="+msg.getClass());

		return sendFrameToSocket(msg);
	}

	public XFuture sendFrameToSocket(Http2Msg msg) {
		if(log.isDebugEnabled())
			log.debug(key+"sending frame down to socket(from client)=\n"+msg);
		DataWrapper data = parser.marshal(marshalState, msg);
		ByteBuffer buffer = ByteBuffer.wrap(data.createByteArray());
		return sendToSocket(buffer);
	}

	public XFuture sendToSocket(ByteBuffer buffer) {
		return finalLayer.sendToSocket(buffer);
	}


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy