diff --git a/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/EapClient.java b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/EapClient.java index e18af71..7ae8d03 100644 --- a/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/EapClient.java +++ b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/EapClient.java @@ -7,11 +7,9 @@ public interface EapClient { /** * 异步连接到服务器 - * @param host 服务器地址 - * @param port 服务器端口 * @return a Mono that completes when the connection is established or errors. */ - Mono connect(String host, int port); + Mono connect(); /** * 断开连接 diff --git a/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/EapClientManager.java b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/EapClientManager.java new file mode 100644 index 0000000..3fbc701 --- /dev/null +++ b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/EapClientManager.java @@ -0,0 +1,41 @@ +package com.github.aisde8.eap.connect.client; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Component +public class EapClientManager { + + private static final Logger logger = LoggerFactory.getLogger(EapClientManager.class); + + private final Map clients = new ConcurrentHashMap<>(); + + public void addClient(String host, int port, EapClient client) { + String key = generateKey(host, port); + clients.put(key, client); + logger.info("Client added: {}", key); + } + + public void removeClient(String host, int port) { + String key = generateKey(host, port); + clients.remove(key); + logger.info("Client removed: {}", key); + } + + public EapClient getClient(String host, int port) { + String key = generateKey(host, port); + return clients.get(key); + } + + public Map getAllClients() { + return clients; + } + + private String generateKey(String host, int port) { + return host + ":" + port; + } +} diff --git a/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/ClientOption.java b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/ClientOption.java new file mode 100644 index 0000000..13b019c --- /dev/null +++ b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/ClientOption.java @@ -0,0 +1,18 @@ +package com.github.aisde8.eap.connect.client.hsms; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ClientOption { + + private String host; + + private int port; + + private int deviceId; + + @Builder.Default + private TimeConfig timeConfig = new TimeConfig(); +} diff --git a/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsClient.java b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsClient.java new file mode 100644 index 0000000..82a4813 --- /dev/null +++ b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsClient.java @@ -0,0 +1,159 @@ +package com.github.aisde8.eap.connect.client.hsms; + +import com.github.aisde8.eap.connect.client.EapClient; +import com.github.aisde8.eap.connect.client.EapClientManager; +import com.github.aside8.eap.protocol.Message; +import com.github.aside8.eap.protocol.hsms.HsmsMessage; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.publisher.MonoSink; +import reactor.core.publisher.Sinks; + +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +public class HsmsClient implements EapClient { + private static final Logger logger = LoggerFactory.getLogger(HsmsClient.class); + + private EventLoopGroup group; + + private volatile Channel channel; + + private final ClientOption clientOption; + + private final AtomicInteger systemBytesGenerator = new AtomicInteger(0); + + private final Map> pendingReplies = new ConcurrentHashMap<>(); + + private final Sinks.Many messageSink = Sinks.many().multicast().onBackpressureBuffer(); + + private final EapClientManager eapClientManager; + + public HsmsClient(ClientOption clientOption, EapClientManager eapClientManager) { + this.clientOption = clientOption; + this.eapClientManager = eapClientManager; + } + + @Override + public Mono connect() { + group = new NioEventLoopGroup(); + Bootstrap bootstrap = new Bootstrap(); + bootstrap.group(group) + .channel(NioSocketChannel.class) + .option(ChannelOption.TCP_NODELAY, true) + .option(ChannelOption.SO_KEEPALIVE, true) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, clientOption.getTimeConfig().getT4() * 1000) + .handler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + pipeline.addLast(new LengthField4FrameDecoder()); + pipeline.addLast(new HsmsMessageDecoder()); + + pipeline.addLast(new HsmsMessageEncoder()); + pipeline.addLast(new LengthField4FrameEncoder()); + pipeline.addLast(new HsmsClientLogicHandler(pendingReplies, messageSink, systemBytesGenerator)); + } + }); + + ChannelFuture future = bootstrap.connect(clientOption.getHost(), clientOption.getPort()); + return Mono.create(sink -> future.addListener((ChannelFutureListener) f -> { + if (f.isSuccess()) { + channel = f.channel(); + eapClientManager.addClient(clientOption.getHost(), clientOption.getPort(), this); + sink.success(); + } else { + f.channel().close(); + sink.error(f.cause()); + } + })); + } + + @Override + public Mono disconnect() { + return Mono.create(sink -> { + if (group == null) { + sink.success(); + return; + } + + eapClientManager.removeClient(clientOption.getHost(), clientOption.getPort()); + pendingReplies.forEach((id, replySink) -> replySink.error(new IllegalStateException("Client Disconnected"))); + pendingReplies.clear(); + + group.shutdownGracefully().addListener(future -> { + if (future.isSuccess()) { + sink.success(); + } else { + sink.error(future.cause()); + } + }); + }); + } + + + @Override + public Flux receive() { + return messageSink.asFlux(); + } + + @Override + public Mono send(Message message) { + if (!isConnected()) { + return Mono.error(new IllegalStateException("Not connected")); + } + if (!(message instanceof HsmsMessage hsmsMessage)) { + return Mono.error(new IllegalArgumentException("Request must be an instance of HsmsMessage")); + } + + return Mono.create(sink -> { + if (hsmsMessage.isRequest()) { + hsmsMessage.setSystemBytes(systemBytesGenerator.incrementAndGet()); + } + channel.writeAndFlush(hsmsMessage).addListener(f -> { + if (f.isSuccess()) { + sink.success(); + } else { + sink.error(f.cause()); + } + }); + }); + } + + @Override + public Mono sendRequest(Message request) { + if (!isConnected()) { + return Mono.error(new IllegalStateException("Not connected")); + } + if (!(request instanceof HsmsMessage hsmsRequest)) { + return Mono.error(new IllegalArgumentException("Request must be an instance of HsmsMessage")); + } + + return Mono.create(sink -> { + int systemBytes = systemBytesGenerator.incrementAndGet(); + hsmsRequest.setSystemBytes(systemBytes); + sink.onDispose(() -> pendingReplies.remove(systemBytes)); + pendingReplies.put(systemBytes, sink); + channel.writeAndFlush(hsmsRequest).addListener(future -> { + if (!future.isSuccess()) { + pendingReplies.remove(systemBytes); + sink.error(future.cause()); + } + }); + }).timeout(Duration.ofMillis(clientOption.getTimeConfig().getT4() * 1000L)).cast(Message.class); + } + + @Override + public boolean isConnected() { + return channel != null && channel.isActive(); + } +} diff --git a/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsClientLogicHandler.java b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsClientLogicHandler.java new file mode 100644 index 0000000..b171e9d --- /dev/null +++ b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsClientLogicHandler.java @@ -0,0 +1,89 @@ +package com.github.aisde8.eap.connect.client.hsms; + +import com.github.aside8.eap.protocol.Message; +import com.github.aside8.eap.protocol.hsms.HsmsMessage; +import com.github.aside8.eap.protocol.hsms.HsmsMessages; +import io.netty.channel.ChannelException; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.util.concurrent.ScheduledFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.MonoSink; +import reactor.core.publisher.Sinks; + +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class HsmsClientLogicHandler extends SimpleChannelInboundHandler { + + private static final Logger logger = LoggerFactory.getLogger(HsmsClientLogicHandler.class); + + private final Map> pendingReplies; + + private final Sinks.Many messageSink; + + private final AtomicInteger systemBytesGenerator; + + private ScheduledFuture linkTestFuture; + + public HsmsClientLogicHandler(Map> pendingReplies, + Sinks.Many messageSink, + AtomicInteger systemBytesGenerator) { + + this.pendingReplies = pendingReplies; + this.messageSink = messageSink; + this.systemBytesGenerator = systemBytesGenerator; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, HsmsMessage msg) throws Exception { + int systemBytes = msg.getSystemBytes(); + MonoSink sink = pendingReplies.remove(systemBytes); + if (sink != null) { + // 找到了对应的请求,完成 Mono + sink.success(msg); + } else { + // 没找到,这是一个服务器主动推送的非请求消息 + messageSink.tryEmitNext(msg); + } + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + logger.info("HSMS Channel Active: {} -> {}", ctx.channel().localAddress(), ctx.channel().remoteAddress()); + + // 发送 SELECT_REQ 消息 + ctx.writeAndFlush(HsmsMessages.selectReq(systemBytesGenerator.incrementAndGet())); + + // 启动定时器发送 LINK_TEST_REQ 消息 + linkTestFuture = ctx.executor().scheduleAtFixedRate(() -> ctx.writeAndFlush(HsmsMessages.linkTestReq(systemBytesGenerator.incrementAndGet())), 3, 3, TimeUnit.SECONDS); + super.channelActive(ctx); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + logger.info("HSMS Channel Inactive: {} -> {}", ctx.channel().localAddress(), ctx.channel().remoteAddress()); + + // 取消定时器 + if (linkTestFuture != null) { + linkTestFuture.cancel(false); + } + + // 连接断开时,所有等待中的 Mono 都应失败 + pendingReplies.forEach((id, sink) -> sink.error(new ChannelException("Channel disconnected unexpectedly."))); + pendingReplies.clear(); + super.channelInactive(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + logger.error("HSMS Client Handler caught exception: {}", cause.getMessage(), cause); + + // 异常发生时,所有等待中的 Mono 都应失败 + pendingReplies.forEach((id, sink) -> sink.error(cause)); + pendingReplies.clear(); + ctx.close(); + } +} diff --git a/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsMessageDecoder.java b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsMessageDecoder.java new file mode 100644 index 0000000..4a4ac20 --- /dev/null +++ b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsMessageDecoder.java @@ -0,0 +1,18 @@ +package com.github.aisde8.eap.connect.client.hsms; + +import com.github.aside8.eap.protocol.hsms.HsmsMessage; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageDecoder; + +import java.util.List; + +public class HsmsMessageDecoder extends MessageToMessageDecoder { + + @Override + protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List out) throws Exception { + HsmsMessage hsmsMessage = new HsmsMessage(); + hsmsMessage.decode(byteBuf); + out.add(hsmsMessage); + } +} diff --git a/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsMessageEncoder.java b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsMessageEncoder.java new file mode 100644 index 0000000..f90f3ec --- /dev/null +++ b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/HsmsMessageEncoder.java @@ -0,0 +1,15 @@ +package com.github.aisde8.eap.connect.client.hsms; + +import com.github.aside8.eap.protocol.hsms.HsmsMessage; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageEncoder; + +import java.util.List; + +public class HsmsMessageEncoder extends MessageToMessageEncoder { + + @Override + protected void encode(ChannelHandlerContext channelHandlerContext, HsmsMessage hsmsMessage, List out) throws Exception { + out.add(hsmsMessage.encode(channelHandlerContext.alloc())); + } +} diff --git a/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/LengthField4FrameDecoder.java b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/LengthField4FrameDecoder.java new file mode 100644 index 0000000..701d5b1 --- /dev/null +++ b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/LengthField4FrameDecoder.java @@ -0,0 +1,10 @@ +package com.github.aisde8.eap.connect.client.hsms; + +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; + +public class LengthField4FrameDecoder extends LengthFieldBasedFrameDecoder { + + public LengthField4FrameDecoder() { + super(1024 * 1024, 0, 4, 0, 4); + } +} diff --git a/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/LengthField4FrameEncoder.java b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/LengthField4FrameEncoder.java new file mode 100644 index 0000000..eb61de9 --- /dev/null +++ b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/LengthField4FrameEncoder.java @@ -0,0 +1,10 @@ +package com.github.aisde8.eap.connect.client.hsms; + +import io.netty.handler.codec.LengthFieldPrepender; + +public class LengthField4FrameEncoder extends LengthFieldPrepender { + + public LengthField4FrameEncoder() { + super(4, 0); + } +} diff --git a/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/TimeConfig.java b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/TimeConfig.java new file mode 100644 index 0000000..5ac2c66 --- /dev/null +++ b/EAP-Connect/src/main/java/com/github/aisde8/eap/connect/client/hsms/TimeConfig.java @@ -0,0 +1,41 @@ +package com.github.aisde8.eap.connect.client.hsms; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TimeConfig { + + //Linktest Timer 用于周期性地发送 Linktest 消息以确认网络连接是否仍然有效。如果 T1 超时后未收到 Linktest 响应,则认为连接断开。 + @Builder.Default + private int T1 = 10; + + //Reply Timeout 用于等待发送的 SECS 消息的回复 (例如,对于S1F13 等 W-bit 为 1 的消息)。如果 T2 超时,认为消息未送达或丢失。用于等待发送的 SECS 消息的回复 (例如,对于 $\text{S1F13}$ 等 $\text{W}$-bit 为 1 的消息)。如果 T2 超时,认为消息未送达或丢失。 + @Builder.Default + private int T2 = 5; + + //Control Transaction Timeout 用于等待控制消息的确认 (例如 Select Request 消息的 Select Response 消息)。如果 T3 超时,认为连接失败。 + @Builder.Default + private int T3 = 15; + + //Connection Timeout 在 HSMS-SS 中,网络连接由操作系统和网络堆栈管理 。如果 T4 超时,认为连接失败。 + @Builder.Default + private int T4 = 30; + + //Connect Modulo (连接模数)定义了在尝试建立连接时,重复发送 Select Request 消息的间隔时间。 + @Builder.Default + private int T5 = 30; + + //Control Transaction Retries 定义了在等待控制消息确认时,最大允许的重试次数。如果超过 T6 次重试仍未收到确认,认为连接失败。 + @Builder.Default + private int T6 = 30; + + //Not Selected Timeout 连接建立后,等待 Select Request 或 Select Response 消息的最长等待时间 用于确保在连接建立后能迅速进入 $\text{Selected}$ 状态。 + @Builder.Default + private int T7 = 30; +} diff --git a/EAP-Connect/src/test/java/com/github/aisde8/eap/connect/client/hsms/HsmsClientTest.java b/EAP-Connect/src/test/java/com/github/aisde8/eap/connect/client/hsms/HsmsClientTest.java new file mode 100644 index 0000000..e8878df --- /dev/null +++ b/EAP-Connect/src/test/java/com/github/aisde8/eap/connect/client/hsms/HsmsClientTest.java @@ -0,0 +1,34 @@ +package com.github.aisde8.eap.connect.client.hsms; + +import com.github.aisde8.eap.connect.client.EapClientManager; +import com.github.aside8.eap.protocol.hsms.HsmsHeader; +import com.github.aside8.eap.protocol.hsms.HsmsMessage; +import com.github.aside8.eap.protocol.hsms.HsmsMessageType; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class HsmsClientTest { + + @Test + @Disabled + void testConnect() throws InterruptedException { + EapClientManager eapClientManager = new EapClientManager(); + HsmsClient hsmsClient = new HsmsClient(ClientOption.builder().host("172.16.57.40").port(9401).build(), eapClientManager); + hsmsClient.receive().map(message -> (HsmsMessage) message) + .subscribe(message -> System.out.println(message.toString())); + hsmsClient.connect().block(); + HsmsMessage hsmsMessage = new HsmsMessage(); + HsmsHeader header = new HsmsHeader(); + header.setSessionId((short) 0); + header.setPtype((byte) 0); + header.setStype((byte) HsmsMessageType.SELECT_REQ.getSType()); + header.setStream((byte) 0); + header.setFunction((byte) 0); + header.setSystemBytes((byte) 0); + hsmsMessage.setHeader(header); + hsmsClient.sendRequest(hsmsMessage); + Thread.sleep(1000 * 60); + } +} \ No newline at end of file diff --git a/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/Message.java b/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/Message.java index f0c5eef..99e0b21 100644 --- a/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/Message.java +++ b/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/Message.java @@ -6,7 +6,7 @@ * 通用消息接口/基类 * A message is a serializable object that can be encoded and decoded. */ -public interface Message extends Codec, Traceable, Serializable { +public interface Message extends Codec, Serializable { Protocol getProtocol(); } diff --git a/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/Traceable.java b/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/Traceable.java deleted file mode 100644 index ed8c281..0000000 --- a/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/Traceable.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.github.aside8.eap.protocol; - -public interface Traceable { - - /** - * 获取消息的跟踪ID - * @return 跟踪ID - */ - String getTraceId(); -} diff --git a/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/hsms/HsmsMessage.java b/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/hsms/HsmsMessage.java index c04081b..80b0c3e 100644 --- a/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/hsms/HsmsMessage.java +++ b/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/hsms/HsmsMessage.java @@ -37,6 +37,15 @@ public int getFunction() { .orElseThrow(() -> new IllegalStateException("HSMS header cannot be null.")); } + public boolean isRequest() { + HsmsMessageType messageType = getMessageType(); + return (messageType == HsmsMessageType.DATA_MESSAGE && getFunction() % 2 == 1) + || messageType == HsmsMessageType.SELECT_REQ + || messageType == HsmsMessageType.DESELECT_REQ + || messageType == HsmsMessageType.LINK_TEST_REQ + || messageType == HsmsMessageType.ABORT_REQ; + } + public HsmsMessageType getMessageType() { return Optional.ofNullable(header) .map(HsmsHeader::getStype) @@ -64,23 +73,11 @@ public ByteBuf encode(ByteBufAllocator allocator) { throw new IllegalStateException("HSMS header cannot be null."); } - ByteBuf headerBuf = header.encode(allocator); - ByteBuf bodyBuf = null; - if (body != null) { - bodyBuf = body.encode(allocator); - } - - int bodyLength = (bodyBuf != null) ? bodyBuf.readableBytes() : 0; - int totalLength = headerBuf.readableBytes() + bodyLength; - - ByteBuf lengthBuf = allocator.buffer(4).writeInt(totalLength); - CompositeByteBuf compositeBuf = allocator.compositeBuffer(); - compositeBuf.addComponents(true, lengthBuf, headerBuf); - if (bodyBuf != null) { - compositeBuf.addComponents(true, bodyBuf); + compositeBuf.addComponents(true, header.encode(allocator)); + if (body != null) { + compositeBuf.addComponents(true, body.encode(allocator)); } - return compositeBuf; } @@ -99,10 +96,4 @@ public void decode(ByteBuf in) { public Protocol getProtocol() { return Protocol.HSMS; } - - @Override - public String getTraceId() { - return String.valueOf(getSystemBytes()); - } - } diff --git a/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/hsms/HsmsMessageType.java b/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/hsms/HsmsMessageType.java index 00d36c4..c7aae8a 100644 --- a/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/hsms/HsmsMessageType.java +++ b/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/hsms/HsmsMessageType.java @@ -29,11 +29,11 @@ public enum HsmsMessageType { /** * LINKTEST.REQ (pType = 0, sType = 5) */ - LINKTEST_REQ(0, 5), + LINK_TEST_REQ(0, 5), /** - * LINKTEST.RSP (pType = 0, sType = 6) + * LINK_TEST.RSP (pType = 0, sType = 6) */ - LINKTEST_RSP(0, 6), + LINK_TEST_RSP(0, 6), /** * ABORT.REQ (pType = 0, sType = 9) */ diff --git a/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/hsms/HsmsMessages.java b/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/hsms/HsmsMessages.java new file mode 100644 index 0000000..853b3f9 --- /dev/null +++ b/EAP-Protocol/src/main/java/com/github/aside8/eap/protocol/hsms/HsmsMessages.java @@ -0,0 +1,78 @@ +package com.github.aside8.eap.protocol.hsms; + +import com.github.aside8.eap.protocol.secs2.SECSII; + +public class HsmsMessages { + + public static HsmsMessage dataReq(int deviceId, int stream, int function, int systemBytes, SECSII data) { + HsmsHeader header = HsmsHeader.builder() + .sessionId((short) deviceId) + .ptype((byte) HsmsMessageType.DATA_MESSAGE.getPType()) + .stype((byte) HsmsMessageType.DATA_MESSAGE.getSType()) + .stream((byte) stream) + .function((byte) function) + .systemBytes(systemBytes) + .build(); + return new HsmsMessage(header, data); + } + + public static HsmsMessage dataRes(HsmsMessage req, SECSII data) { + HsmsHeader header = HsmsHeader.builder() + .sessionId(req.getHeader().getSessionId()) + .ptype((byte) HsmsMessageType.DATA_MESSAGE.getPType()) + .stype((byte) HsmsMessageType.DATA_MESSAGE.getSType()) + .stream(req.getHeader().getStream()) + .function((byte) (req.getHeader().getFunction() + 1)) + .systemBytes(req.getHeader().getSystemBytes()) + .build(); + return new HsmsMessage(header, data); + } + + public static HsmsMessage selectReq(int systemBytes) { + HsmsHeader header = HsmsHeader.builder() + .sessionId((short) 0xFFFF) + .ptype((byte) HsmsMessageType.SELECT_REQ.getPType()) + .stype((byte) HsmsMessageType.SELECT_REQ.getSType()) + .stream((byte) 0x00) + .function((byte) 0x00) + .systemBytes(systemBytes) + .build(); + return new HsmsMessage(header, null); + } + + public static HsmsMessage selectResp(HsmsMessage req, SelectStatus selectStatus) { + HsmsHeader header = HsmsHeader.builder() + .sessionId(req.getHeader().getSessionId()) + .ptype((byte) HsmsMessageType.SELECT_RSP.getPType()) + .stype((byte) HsmsMessageType.SELECT_RSP.getSType()) + .stream(selectStatus.getCode()) + .function((byte) 0x00) + .systemBytes(req.getHeader().getSystemBytes()) + .build(); + return new HsmsMessage(header, null); + } + + public static HsmsMessage linkTestReq(int systemBytes) { + HsmsHeader header = HsmsHeader.builder() + .sessionId((short) 0xFFFF) + .ptype((byte) HsmsMessageType.LINK_TEST_REQ.getPType()) + .stype((byte) HsmsMessageType.LINK_TEST_REQ.getSType()) + .stream((byte) 0x00) + .function((byte) 0x00) + .systemBytes(systemBytes) + .build(); + return new HsmsMessage(header, null); + } + + public static HsmsMessage linkTestResp(HsmsMessage req) { + HsmsHeader header = HsmsHeader.builder() + .sessionId(req.getHeader().getSessionId()) + .ptype((byte) HsmsMessageType.LINK_TEST_RSP.getPType()) + .stype((byte) HsmsMessageType.LINK_TEST_RSP.getSType()) + .stream((byte) 0x00) + .function((byte) 0x00) + .systemBytes(req.getHeader().getSystemBytes()) + .build(); + return new HsmsMessage(header, null); + } +}