Skip to content

Commit 3e8f30f

Browse files
committed
feat: add device discover request
Signed-off-by: wei <[email protected]>
1 parent cf32c2c commit 3e8f30f

File tree

22 files changed

+333
-70
lines changed

22 files changed

+333
-70
lines changed

mdtp-client/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
<artifactId>mdtp-common</artifactId>
2222
<version>${project.version}</version>
2323
</dependency>
24+
<dependency>
25+
<groupId>io.github.protocol-laboratory</groupId>
26+
<artifactId>mdtp-server</artifactId>
27+
<scope>test</scope>
28+
</dependency>
2429
</dependencies>
2530

2631
</project>

mdtp-client/src/main/java/io/github/protocol/mdtp/client/MdtpClient.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
11
package io.github.protocol.mdtp.client;
22

3+
import io.github.protocol.mdtp.common.model.CDATHeader;
4+
import io.github.protocol.mdtp.common.model.DeviceDiscoveryRequest;
5+
import io.github.protocol.mdtp.common.model.MdtpPacket;
6+
import io.github.protocol.mdtp.common.model.MessageBodyHeader;
37
import io.netty.bootstrap.Bootstrap;
8+
import io.netty.buffer.Unpooled;
49
import io.netty.channel.ChannelFuture;
510
import io.netty.channel.ChannelInitializer;
611
import io.netty.channel.EventLoopGroup;
712
import io.netty.channel.nio.NioEventLoopGroup;
813
import io.netty.channel.socket.SocketChannel;
914
import io.netty.channel.socket.nio.NioSocketChannel;
15+
import lombok.Data;
1016
import lombok.extern.slf4j.Slf4j;
1117

1218
import java.io.Closeable;
1319
import java.io.IOException;
1420

1521
@Slf4j
22+
@Data
1623
public class MdtpClient implements Closeable {
1724
private final MdtpClientConfig config;
1825

26+
private ChannelFuture channelFuture;
27+
1928
private EventLoopGroup group;
2029

2130
public MdtpClient(MdtpClientConfig config) {
@@ -37,7 +46,7 @@ public void start() throws Exception {
3746
protected void initChannel(SocketChannel ch) throws Exception {
3847
}
3948
});
40-
ChannelFuture channelFuture = bootstrap.connect().sync();
49+
this.channelFuture = bootstrap.connect().sync();
4150
if (channelFuture.isSuccess()) {
4251
log.info("mdtp client started");
4352
} else {
@@ -55,4 +64,40 @@ public void close() throws IOException {
5564
this.group.shutdownGracefully();
5665
log.info("mdtp client closed");
5766
}
67+
68+
public void sendDeviceDiscoveryRequest(int[] deviceTypes) {
69+
log.info("start to send device discovery request.");
70+
DeviceDiscoveryRequest request = new DeviceDiscoveryRequest();
71+
request.setMessageBodyHeader(MessageBodyHeader.DEVICE_DISCOVERY_REQUEST);
72+
log.info("" + request.getMessageBodyHeader().toShort());
73+
request.setRequestId(request.generateRequestId());
74+
75+
if (deviceTypes == null) {
76+
request.setDeviceTypeCount((byte) 0);
77+
}
78+
79+
if (deviceTypes != null && deviceTypes.length > 0) {
80+
request.setMask((byte) 1);
81+
request.setDeviceTypeCount((byte) deviceTypes.length);
82+
request.setDeviceTypes(deviceTypes);
83+
}
84+
85+
CDATHeader cdatHeader = new CDATHeader();
86+
cdatHeader.setFormatType((byte) 0x02);
87+
cdatHeader.setProtocolVersion((byte) 1);
88+
cdatHeader.setMessageLength((short) 0);
89+
cdatHeader.setTimestamp(System.currentTimeMillis());
90+
cdatHeader.setFlags((byte) 0b01100000);
91+
cdatHeader.setSequenceNumber(0);
92+
cdatHeader.setLogicalChannelId(0);
93+
94+
MdtpPacket packet = new MdtpPacket();
95+
packet.setHeader(cdatHeader);
96+
packet.setSecurityHeader(null);
97+
packet.setBody(request);
98+
packet.setSignature(null);
99+
100+
this.channelFuture.channel().writeAndFlush(packet.toByteBuf(Unpooled.buffer()));
101+
log.info("send device discovery request success: " + packet);
102+
}
58103
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import io.github.protocol.mdtp.client.MdtpClient;
2+
import io.github.protocol.mdtp.client.MdtpClientConfig;
3+
import io.github.protocol.mdtp.common.model.DeviceDiscoveryRequest;
4+
import io.github.protocol.mdtp.common.model.MdtpPacket;
5+
import io.github.protocol.mdtp.server.MdtpServer;
6+
import io.github.protocol.mdtp.server.MdtpServerConfig;
7+
import io.netty.channel.Channel;
8+
import io.netty.channel.ChannelFuture;
9+
import io.netty.channel.EventLoopGroup;
10+
import io.netty.channel.embedded.EmbeddedChannel;
11+
import org.junit.jupiter.api.AfterEach;
12+
import org.junit.jupiter.api.BeforeEach;
13+
import org.junit.jupiter.api.Test;
14+
15+
import java.io.IOException;
16+
import java.net.ConnectException;
17+
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
import static org.junit.jupiter.api.Assertions.assertThrows;
20+
import static org.mockito.ArgumentMatchers.any;
21+
import static org.mockito.Mockito.mock;
22+
import static org.mockito.Mockito.verify;
23+
import static org.mockito.Mockito.when;
24+
25+
public class MdtpClientTest {
26+
27+
private MdtpClientConfig config;
28+
private MdtpClient mdtpClient;
29+
30+
private MdtpServer mdtpServer;
31+
private EventLoopGroup groupMock;
32+
private ChannelFuture channelFutureMock;
33+
34+
private EmbeddedChannel embeddedChannel;
35+
36+
@BeforeEach
37+
public void setUp() throws Exception {
38+
MdtpServerConfig mdtpServerConfig = new MdtpServerConfig().host("localhost").port(4146);
39+
mdtpServer = new MdtpServer(mdtpServerConfig);
40+
mdtpServer.start();
41+
42+
config = new MdtpClientConfig().host("localhost").port(4146);
43+
mdtpClient = new MdtpClient(config);
44+
45+
groupMock = mock(EventLoopGroup.class);
46+
channelFutureMock = mock(ChannelFuture.class);
47+
48+
mdtpClient.setGroup(groupMock);
49+
mdtpClient.setChannelFuture(channelFutureMock);
50+
}
51+
52+
@AfterEach
53+
public void close() throws IOException {
54+
mdtpServer.close();
55+
}
56+
57+
@Test
58+
public void testStartConnectionFailure() {
59+
ChannelFuture channelFutureMock = mock(ChannelFuture.class);
60+
when(channelFutureMock.isSuccess()).thenReturn(false);
61+
mdtpClient.setGroup(null);
62+
mdtpClient.setChannelFuture(channelFutureMock);
63+
assertThrows(ConnectException.class, () -> {
64+
mdtpClient.start();
65+
});
66+
}
67+
68+
@Test
69+
public void testClose() throws IOException {
70+
mdtpClient.close();
71+
verify(groupMock).shutdownGracefully();
72+
}
73+
74+
@Test
75+
public void testSendDeviceDiscoveryRequest() {
76+
Channel channelMock = mock(Channel.class);
77+
when(channelFutureMock.channel()).thenReturn(channelMock);
78+
int[] deviceTypes = {1, 2, 3};
79+
mdtpClient.sendDeviceDiscoveryRequest(deviceTypes);
80+
verify(channelMock).writeAndFlush(any());
81+
}
82+
83+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.github.protocol.mdtp.common.codec;
2+
3+
import io.github.protocol.mdtp.common.model.AbstractMessageBody;
4+
import io.github.protocol.mdtp.common.model.DeviceDiscoveryRequest;
5+
import io.netty.buffer.ByteBuf;
6+
7+
public class DeviceDiscoveryRequestDecoder implements MessageBodyDecoder {
8+
@Override
9+
public AbstractMessageBody handle(ByteBuf in) {
10+
return DeviceDiscoveryRequest.fromByteBuf(in);
11+
}
12+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.github.protocol.mdtp.common.codec;
2+
3+
4+
import io.github.protocol.mdtp.common.model.AbstractMessageBody;
5+
import io.github.protocol.mdtp.common.model.CDATHeader;
6+
import io.github.protocol.mdtp.common.model.MdtpPacket;
7+
import io.github.protocol.mdtp.common.model.MessageBodyHeader;
8+
import io.netty.buffer.ByteBuf;
9+
import io.netty.channel.ChannelHandlerContext;
10+
import io.netty.handler.codec.ByteToMessageDecoder;
11+
import lombok.extern.slf4j.Slf4j;
12+
13+
import java.util.List;
14+
15+
@Slf4j
16+
public class MdtpDecoder extends ByteToMessageDecoder {
17+
18+
@Override
19+
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
20+
21+
MdtpPacket mdtpPacket = new MdtpPacket();
22+
CDATHeader header = CDATHeader.fromByteBuf(in);
23+
24+
MessageBodyHeader messageBodyHeader = MessageBodyHeader.fromByteBuf(in);
25+
MessageBodyDecoder messageDecode = MessageDecoderFactory.getDecoder(messageBodyHeader);
26+
AbstractMessageBody messageBody = messageDecode.handle(in);
27+
messageBody.setMessageBodyHeader(messageBodyHeader);
28+
29+
mdtpPacket.setHeader(header);
30+
mdtpPacket.setBody(messageBody);
31+
32+
out.add(mdtpPacket);
33+
}
34+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package io.github.protocol.mdtp.common.codec;
2+
3+
import io.github.protocol.mdtp.common.model.AbstractMessageBody;
4+
import io.netty.buffer.ByteBuf;
5+
6+
public interface MessageBodyDecoder {
7+
AbstractMessageBody handle(ByteBuf in);
8+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.github.protocol.mdtp.common.codec;
2+
3+
import io.github.protocol.mdtp.common.model.MessageBodyHeader;
4+
5+
import java.util.HashMap;
6+
import java.util.Map;
7+
8+
public class MessageDecoderFactory {
9+
10+
private static final Map<Short, MessageBodyDecoder> decoders = new HashMap<>();
11+
12+
static {
13+
decoders.put(MessageBodyHeader.DEVICE_DISCOVERY_REQUEST.toShort(), new DeviceDiscoveryRequestDecoder());
14+
}
15+
16+
public static MessageBodyDecoder getDecoder(MessageBodyHeader header) {
17+
return decoders.get(header.toShort());
18+
}
19+
}

mdtp-common/src/main/java/io/github/protocol/mdtp/common/model/AbstractMessageBody.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,15 @@
77

88
@Data
99
public abstract class AbstractMessageBody {
10-
private short messageBodyHeader;
11-
12-
public void setMessageBodyHeader(MessageType messageType, ServiceGroup serviceGroup, DiscoveryServiceCode serviceCode) {
13-
this.messageBodyHeader = 0;
14-
this.messageBodyHeader |= (short) (messageType.getCode() & 0b111);
15-
this.messageBodyHeader |= (short) ((serviceGroup.getCode() & 0b1111111) << 3);
16-
this.messageBodyHeader |= (short) ((serviceCode.getCode() & 0b111111) << 10);
17-
}
10+
private MessageBodyHeader messageBodyHeader;
1811

1912
public short generateRequestId() {
2013
UUID uuid = UUID.randomUUID();
2114
return (short) (uuid.getLeastSignificantBits() & 0xFFFF);
2215
}
2316

2417
public ByteBuf toByteBuf(ByteBuf buffer) {
25-
buffer.writeShort(messageBodyHeader);
18+
messageBodyHeader.toByteBuf(buffer);
2619
return buffer;
2720
}
2821
}

mdtp-common/src/main/java/io/github/protocol/mdtp/common/model/CDATHeader.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,18 @@ public ByteBuf toByteBuf(ByteBuf buffer) {
3535
buffer.writeInt(logicalChannelId);
3636
return buffer;
3737
}
38+
39+
public static CDATHeader fromByteBuf(ByteBuf buffer) {
40+
CDATHeader header = new CDATHeader();
41+
42+
header.setFormatType(buffer.readByte());
43+
header.setProtocolVersion(buffer.readByte());
44+
header.setMessageLength(buffer.readShort());
45+
header.setTimestamp(buffer.readLong());
46+
header.setFlags(buffer.readByte());
47+
header.setSequenceNumber(buffer.readInt());
48+
header.setLogicalChannelId(buffer.readInt());
49+
50+
return header;
51+
}
3852
}

mdtp-common/src/main/java/io/github/protocol/mdtp/common/model/DeviceDiscoveryRequest.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66

77
@Data
8-
public class DeviceDiscoveryRequest extends AbstractMessageBody {
8+
public class DeviceDiscoveryRequest extends AbstractMessageBody{
9+
910
private short requestId;
1011

1112
private byte mask;
@@ -19,8 +20,10 @@ public ByteBuf toByteBuf(ByteBuf buffer) {
1920
buffer.writeShort(requestId);
2021
buffer.writeByte(mask);
2122
buffer.writeByte(deviceTypeCount);
22-
for (int deviceType : deviceTypes) {
23-
buffer.writeInt(deviceType);
23+
if (deviceTypeCount > 0) {
24+
for (int deviceType : deviceTypes) {
25+
buffer.writeInt(deviceType);
26+
}
2427
}
2528
return buffer;
2629
}

0 commit comments

Comments
 (0)