diff --git a/src/main/java/component/MutableField.java b/src/main/java/component/MutableField.java index 822623a..9a0b082 100644 --- a/src/main/java/component/MutableField.java +++ b/src/main/java/component/MutableField.java @@ -10,8 +10,8 @@ import encoding.*; * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 */ public class MutableField implements TlvComponentBase,IEncodingAble { - private MutableProtectField mutableProtectField; - private MutableDangerousField mutableDangerousField; + public MutableProtectField mutableProtectField; + public MutableDangerousField mutableDangerousField; public MutableField(){ mutableProtectField=new MutableProtectField(); diff --git a/src/main/java/component/TTL.java b/src/main/java/component/TTL.java index 86d4ae2..c665015 100644 --- a/src/main/java/component/TTL.java +++ b/src/main/java/component/TTL.java @@ -19,6 +19,9 @@ public class TTL implements IEncodingAble { */ private long ttl; + public TTL(){ + } + public TTL(Block block){ buildTTLByBlock(block); } diff --git a/src/main/java/encoding/SelfEncodingBase.java b/src/main/java/encoding/SelfEncodingBase.java new file mode 100644 index 0000000..cfff5d6 --- /dev/null +++ b/src/main/java/encoding/SelfEncodingBase.java @@ -0,0 +1,97 @@ +package encoding; + +import component.CanBePrefix; + +/* + * @Author: Wang Feng + * @Description: 利用对接口的函数回调,实现对任意实现了 IEncodingAble 接口的对象进行自编码 + * @Version: 1.0.0 + * @Date: 16:17 2021/3/15 + * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 + */ +public class SelfEncodingBase { + + // 用来实现自编码的辅助结构 + private Block rawBlock; + // 存放回调的函数 +// private IEncodingAble iEncodingAble; + + public SelfEncodingBase(){ + } + + /** + * 获取编码后的Block + * @return + */ + public Block getRawBlock(){ + return rawBlock; + } + + /** + * 设置回调函数(接口的函数) + * @param iEncodingAble + */ +// public void setiEncodingAble(IEncodingAble iEncodingAble) { +// this.iEncodingAble = iEncodingAble; +// } + + /** + * 对一个实现了 IEncodingAble 接口的对象进行自编码 + * // @Description: + * // 1. 用 rawBlock缓存编码的结果; + * // 2. 如果 rawBlock不为空,且指向一个有效的 Block,则直接返回raw + * // 3. 如果 rawBlock为空,或者指向的不是一个有效的 Block,则将对象编码为 Block 之后返回,同时用 raw指针缓存编码的结果 + * @param iEncodingAble + * @return + */ + public Block selfWireEncode(IEncodingAble iEncodingAble){ +// this.setiEncodingAble(iEncodingAble); + if((this.rawBlock!=null)&&this.rawBlock.isValid()){ + return this.rawBlock; + } + + Block block=easyEncoder(iEncodingAble); + if(block==null){ + return null; + } + this.rawBlock=block; + return block; + } + + /** + * 自编码辅助函数 + * 利用对接口的函数回调,实现对任意实现了 IEncodingAble 接口的对象进行自编码 + * @param iEncodingAble + * @return + */ + private Block easyEncoder(IEncodingAble iEncodingAble){ + Encoder encoder=new Encoder(); + + // 首先测量目标 TLV 的大小 + encoder.estimatorReset(); + int targetLen=iEncodingAble.wireEncode(encoder); + if(targetLen<=0){ + return null; + } + + // 编码初始化 + if(!encoder.encoderReset(new SizeT(targetLen),new SizeT(0))){ + return null; + } + + // 实际执行编码 + targetLen=iEncodingAble.wireEncode(encoder); + if(targetLen<=0){ + return null; + } + + byte[] buffer=encoder.getBuffer(); + if((buffer==null)||buffer.length==0){ + return null; + } + + // 返回编码的结果 + return Block.createBlockByBuffer(buffer,true); + } + +} diff --git a/src/main/java/packet/CPacket.java b/src/main/java/packet/CPacket.java index 60e4034..d493e2c 100644 --- a/src/main/java/packet/CPacket.java +++ b/src/main/java/packet/CPacket.java @@ -1,5 +1,10 @@ package packet; +import component.IdentifierWrapper; +import component.Payload; +import component.TTL; +import encoding.*; + /* * @Author: Wang Feng * @Description: @@ -27,6 +32,164 @@ package packet; // } // } // -public class CPacket { +public class CPacket implements InteractWithField, IEncodingAble { + private MINPacket minPacket; + private TTL ttl; + private Payload payload; + private String flatIdentifier; // 推式包拥有一个扁平的标识 + public CPacket(){ + minPacket=new MINPacket(); + ttl=new TTL(); + payload=new Payload(); + } + + /** + * 将 CPacket 的各项属性填充到 MINPacket 中定义的对应分区当中 + * @Description: + * // 1. 主要填充标识区、只读区和可变区 + * @return + */ + @Override + public boolean fillDataToFields() { + // 可变区 => 受保护区(无) + + // 填充可变区 => 非受保护区 + // 首先清除所有的Block + this.minPacket.mutableField.mutableDangerousField.clearBlocks(); + Block block=new SelfEncodingBase().selfWireEncode(this.ttl); + if(block==null){ + return false; + } + this.minPacket.mutableField.mutableDangerousField.addBlock(block); + + // 填充只读区 + // 首先清除所有的Block + this.minPacket.readOnlyField.clearBlocks(); + block=new SelfEncodingBase().selfWireEncode(this.payload); + if(block==null){ + return false; + } + this.minPacket.readOnlyField.addBlock(block); + + // 填充标识区 + // 首先清除所有的标识 + this.minPacket.identifierField.clearIdentifiers(); + IdentifierWrapper identifierWrapper= + new IdentifierWrapper().createCommonIdentifierByString(this.flatIdentifier); + if(identifierWrapper==null){ + return false; + } + this.minPacket.identifierField.addIdentifier(identifierWrapper); + + return true; + } + + /** + * 从 MINPacket 的分区当中提取出 CPacket 的各项属性 + * @return + */ + @Override + public boolean extraDataFromFields() { + // 提取 Payload + Block payloadBlock=this.minPacket.readOnlyField.getBlockByType(new VlInt(TLV.TlvPayload)); + if(payloadBlock==null){ + return false; + } + if(this.payload.wireDecode(payloadBlock)){ + return false; + } + + // 提取 TTL + Block ttlBlock=this.minPacket.mutableField.mutableDangerousField.getBlockByType(new VlInt(TLV.TlvTTL)); + if(ttlBlock==null){ + return false; + } + if(this.ttl.wireDecode(ttlBlock)){ + return false; + } + + // 提取标识 + IdentifierWrapper commonIdentifier=this.minPacket.identifierField.getIdentifierByType(new VlInt(TLV.TlvIdentifierCommon)); + if(commonIdentifier==null){ + return false; + } + String identifierString=commonIdentifier.toUri(); + if((identifierString.length()>0)&&(identifierString.startsWith("/"))){ + this.flatIdentifier=identifierString.substring(1); + } + + return true; + } + + /** + * 将 CPacket 编码成 TLV + * @param encoder + * @return + */ + @Override + public int wireEncode(Encoder encoder) { + // 首先将属性填充到分区当中 + if(!this.fillDataToFields()){ + return 0; + } + + // 指定包类型 + this.minPacket.packetType=new VlInt(TLV.TlvPacketMINCommon); + + return this.minPacket.wireEncode(encoder); + } + + /** + * 从 TLV Block 中解码出一个 CPacket + * @param block + * @return + */ + @Override + public boolean wireDecode(Block block) { + if(!this.minPacket.wireDecode(block)){ + return false; + } + return this.extraDataFromFields(); + } + + /** + * 展示平面标识 + * @return + */ + public String toUri(){ + return this.flatIdentifier; + } + + /** + * 设置推式包的平面标识,eg: asdfsvnjweivnjsdcs + * @param identifier + */ + public void setIdentifier(String identifier){ + this.flatIdentifier=identifier; + } + + /** + * 获取推式包的平面标识 + * @return + */ + public String getIdentifier(){ + return this.flatIdentifier; + } + + /** + * 得到 TTL + * @return + */ + public TTL getTtl() { + return ttl; + } + + /** + * 设置 TTL + * @param ttl + */ + public void setTtl(TTL ttl) { + this.ttl = ttl; + } } diff --git a/src/main/java/packet/InteractWithField.java b/src/main/java/packet/InteractWithField.java new file mode 100644 index 0000000..de8f03c --- /dev/null +++ b/src/main/java/packet/InteractWithField.java @@ -0,0 +1,22 @@ +package packet; + +/* + * @Author: Wang Feng + * @Description: 定义了一个网络包应该实现哪些和分区交互的方法 + * @Version: 1.0.0 + * @Date: 9:21 2021/3/13 + * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 + */ +public interface InteractWithField { + /** + * 将包的属性填充到网络包的四个分区当中 + * @return + */ + boolean fillDataToFields(); + + /** + * 从网络包的四个分区当中提取出特定网络包的相关属性 + * @return + */ + boolean extraDataFromFields(); +} diff --git a/src/main/java/packet/MINPacket.java b/src/main/java/packet/MINPacket.java new file mode 100644 index 0000000..94825da --- /dev/null +++ b/src/main/java/packet/MINPacket.java @@ -0,0 +1,163 @@ +package packet; + +import component.IdentifierField; +import component.MutableField; +import component.ReadOnlyField; +import encoding.*; + +/* + * @Author: Wang Fengs + * @Description: 表示一个MIN网络层包的通用结构 + * todo: 需要在signature完成之后取消signatureField的注释 + * @Version: 1.0.0 + * @Date: 22:07 2021/3/13 + * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 + */ +public class MINPacket implements IEncodingAble { + public IdentifierField identifierField; // 标识区 +// private SignatureField signatureField; // 签名区 + public ReadOnlyField readOnlyField; // 只读区 + public MutableField mutableField; // 可变区 + public VlInt packetType; // 包类型 + + /** + * 判断 MIN 包是否是一个有效的包 + * @return + */ + public boolean isPacketValid(){ + return TLV.isValidPacketType(packetType); + } + + + /** + * 将 Packet 线速编码为 TLV + * @param encoder + * @return + */ + @Override + public int wireEncode(Encoder encoder) { + if(!this.isPacketValid()){ + return 0; + } + int totalLength=0; + + // 编码 TLV-VALUE + + // 可变区 + int tmplen=this.mutableField.wireEncode(encoder); + if(tmplen<=0){ + return 0; + } + totalLength+=tmplen; + + // 只读区 + tmplen=this.readOnlyField.wireEncode(encoder); + if(tmplen<=0){ + return 0; + } + totalLength+=tmplen; + + // 签名区 +// tmplen=this.signatureField.wireEncode(encoder); +// if(tmplen<=0){ +// return 0; +// } +// totalLength+=tmplen; + + // 标识区 + tmplen=this.identifierField.wireEncode(encoder); + if(tmplen<=0){ + return 0; + } + totalLength+=tmplen; + + // 编码包 TLV-LENGTH + tmplen=encoder.prependVarNumber(new VlInt(totalLength)); + if(tmplen<=0){ + return 0; + } + totalLength+=tmplen; + + // 编码包 TLV-TYPE + tmplen=encoder.prependVarNumber(this.packetType); + if(tmplen<=0){ + return 0; + } + totalLength+=tmplen; + + return totalLength; + } + + /** + * 线速解码,将 MIN包 TLV 中的四个区域分别解析出来 + * // @Description: + * // 1. 解析出四个区的TLV; + * // 2. 检查必要的TLV是否存在,不存在则抛出异常,以下为必须条件: + * // a. 必须包含标识区,且标识区至少包含一个标识 + * @param block + * @return + */ + @Override + public boolean wireDecode(Block block) { + // 首先判断包是否有效 + if(!block.isValid()){ + return false; + } + // 首先解析子 Block + if(!block.parseSubElements()){ + return false; + } + + // 标记,用来记录是否满足必要条件 + boolean existIdentifier=false; + + // 解析四个标识区 + int elementSize=block.getSubElements().length(); + for (int i=0;i