1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.db.protocol.mysql.packet.handshake;
19
20 import com.google.common.base.Preconditions;
21 import lombok.Getter;
22 import org.apache.shardingsphere.db.protocol.constant.DatabaseProtocolServerInfo;
23 import org.apache.shardingsphere.db.protocol.mysql.constant.MySQLAuthenticationMethod;
24 import org.apache.shardingsphere.db.protocol.mysql.constant.MySQLCapabilityFlag;
25 import org.apache.shardingsphere.db.protocol.mysql.constant.MySQLConstants;
26 import org.apache.shardingsphere.db.protocol.mysql.constant.MySQLStatusFlag;
27 import org.apache.shardingsphere.db.protocol.mysql.packet.MySQLPacket;
28 import org.apache.shardingsphere.db.protocol.mysql.payload.MySQLPacketPayload;
29 import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
30 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
31
32
33
34
35
36
37 @Getter
38 public final class MySQLHandshakePacket extends MySQLPacket {
39
40 private final int protocolVersion = MySQLConstants.PROTOCOL_VERSION;
41
42 private final String serverVersion;
43
44 private final int connectionId;
45
46 private final int capabilityFlagsLower;
47
48 private final int characterSet;
49
50 private final MySQLStatusFlag statusFlag;
51
52 private final MySQLAuthenticationPluginData authPluginData;
53
54 private int capabilityFlagsUpper;
55
56 private String authPluginName;
57
58 public MySQLHandshakePacket(final int connectionId, final boolean sslEnabled, final MySQLAuthenticationPluginData authPluginData) {
59 serverVersion = DatabaseProtocolServerInfo.getDefaultProtocolVersion(TypedSPILoader.getService(DatabaseType.class, "MySQL"));
60 this.connectionId = connectionId;
61 capabilityFlagsLower = MySQLCapabilityFlag.calculateHandshakeCapabilityFlagsLower() | (sslEnabled ? MySQLCapabilityFlag.CLIENT_SSL.getValue() : 0);
62 characterSet = MySQLConstants.DEFAULT_CHARSET.getId();
63 statusFlag = MySQLStatusFlag.SERVER_STATUS_AUTOCOMMIT;
64 capabilityFlagsUpper = MySQLCapabilityFlag.calculateHandshakeCapabilityFlagsUpper();
65 this.authPluginData = authPluginData;
66 authPluginName = MySQLAuthenticationMethod.CACHING_SHA2_PASSWORD.getMethodName();
67 }
68
69 public MySQLHandshakePacket(final MySQLPacketPayload payload) {
70 Preconditions.checkArgument(protocolVersion == payload.readInt1());
71 serverVersion = payload.readStringNul();
72 connectionId = payload.readInt4();
73 final byte[] authPluginDataPart1 = payload.readStringNulByBytes();
74 capabilityFlagsLower = payload.readInt2();
75 characterSet = payload.readInt1();
76 statusFlag = MySQLStatusFlag.valueOf(payload.readInt2());
77 capabilityFlagsUpper = payload.readInt2();
78 payload.readInt1();
79 payload.skipReserved(10);
80 authPluginData = new MySQLAuthenticationPluginData(authPluginDataPart1, readAuthPluginDataPart2(payload));
81 authPluginName = readAuthPluginName(payload);
82 }
83
84
85
86
87
88
89
90
91
92
93
94 private byte[] readAuthPluginDataPart2(final MySQLPacketPayload payload) {
95 return isClientSecureConnection() ? payload.readStringNulByBytes() : new byte[0];
96 }
97
98 private String readAuthPluginName(final MySQLPacketPayload payload) {
99 return isClientPluginAuth() ? payload.readStringNul() : null;
100 }
101
102
103
104
105
106
107 public void setAuthPluginName(final MySQLAuthenticationMethod authenticationMethod) {
108 authPluginName = authenticationMethod.getMethodName();
109 capabilityFlagsUpper |= MySQLCapabilityFlag.CLIENT_PLUGIN_AUTH.getValue() >> 16;
110 }
111
112 @Override
113 protected void write(final MySQLPacketPayload payload) {
114 payload.writeInt1(protocolVersion);
115 payload.writeStringNul(serverVersion);
116 payload.writeInt4(connectionId);
117 payload.writeStringNul(new String(authPluginData.getAuthenticationPluginDataPart1()));
118 payload.writeInt2(capabilityFlagsLower);
119 payload.writeInt1(characterSet);
120 payload.writeInt2(statusFlag.getValue());
121 payload.writeInt2(capabilityFlagsUpper);
122 payload.writeInt1(isClientPluginAuth() ? authPluginData.getAuthenticationPluginData().length + 1 : 0);
123 payload.writeReserved(10);
124 writeAuthPluginDataPart2(payload);
125 writeAuthPluginName(payload);
126 }
127
128 private void writeAuthPluginDataPart2(final MySQLPacketPayload payload) {
129 if (isClientSecureConnection()) {
130 payload.writeStringNul(new String(authPluginData.getAuthenticationPluginDataPart2()));
131 }
132 }
133
134 private void writeAuthPluginName(final MySQLPacketPayload payload) {
135 if (isClientPluginAuth()) {
136 payload.writeStringNul(authPluginName);
137 }
138 }
139
140 private boolean isClientSecureConnection() {
141 return 0 != (capabilityFlagsLower & MySQLCapabilityFlag.CLIENT_SECURE_CONNECTION.getValue() & 0x00000ffff);
142 }
143
144 private boolean isClientPluginAuth() {
145 return 0 != (capabilityFlagsUpper & MySQLCapabilityFlag.CLIENT_PLUGIN_AUTH.getValue() >> 16);
146 }
147 }