Quellcode durchsuchen

fixed issue #2099 , support user/passwd acl and canal admin operator

agapple vor 5 Jahren
Ursprung
Commit
3d4dbc9a8c
54 geänderte Dateien mit 8512 neuen und 723 gelöschten Zeilen
  1. 5 4
      .gitignore
  2. 63 0
      canal-admin/canal-admin-server/pom.xml
  3. 16 14
      canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/common/exception/ServiceException.java
  4. 124 0
      canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/connector/AdminConnector.java
  5. 318 0
      canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/connector/SimpleAdminConnector.java
  6. 31 0
      canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/connector/SimpleAdminConnectors.java
  7. 20 1
      canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/controller/CanalInstanceController.java
  8. 0 164
      canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/jmx/JMXConnection.java
  9. 4 2
      canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/Model.java
  10. 71 3
      canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/CanalConfigServiceImpl.java
  11. 13 12
      canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/CanalInstanceServiceImpl.java
  12. 18 32
      canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/NodeServerServiceImpl.java
  13. 31 7
      canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/UserServiceImpl.java
  14. 85 0
      canal-admin/canal-admin-server/src/main/resources/canal_manager.sql
  15. 0 0
      canal-admin/canal-admin-server/src/main/resources/public/index.html
  16. 0 0
      canal-admin/canal-admin-server/src/main/resources/public/static/js/chunk-e1a839e4.3175ead5.js
  17. 0 0
      canal-admin/canal-admin-server/src/main/resources/public/static/js/chunk-e1a839e4.7ee86dd8.js
  18. 40 0
      canal-admin/canal-admin-server/src/test/java/com/alibaba/otter/canal/admin/SimpleAdminConnectorTest.java
  19. 0 20
      canal-admin/canal-admin-server/src/test/java/com/alibaba/otter/canal/admin/jmx/JMXConnectionTest.java
  20. 5 5
      canal-admin/canal-admin-ui/src/views/canalServer/NodeServer.vue
  21. 0 22
      canal-admin/canal_manager.sql
  22. 11 2
      client/src/main/java/com/alibaba/otter/canal/client/impl/SimpleCanalConnector.java
  23. 14 5
      common/src/main/java/com/alibaba/otter/canal/common/utils/FileUtils.java
  24. 1 0
      common/src/main/java/com/alibaba/otter/canal/common/zookeeper/running/ServerRunningMonitor.java
  25. 5 1
      deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalConstants.java
  26. 4 0
      deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalController.java
  27. 0 23
      deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalLauncher.java
  28. 32 1
      deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalStater.java
  29. 224 0
      deployer/src/main/java/com/alibaba/otter/canal/deployer/admin/CanalAdminController.java
  30. 0 79
      deployer/src/main/java/com/alibaba/otter/canal/deployer/mbean/CanalServerAgent.java
  31. 0 156
      deployer/src/main/java/com/alibaba/otter/canal/deployer/mbean/CanalServerBean.java
  32. 0 90
      deployer/src/main/java/com/alibaba/otter/canal/deployer/mbean/CanalServerMXBean.java
  33. 10 2
      deployer/src/main/resources/canal.properties
  34. 1 2
      driver/src/test/java/com/alibaba/otter/canal/parse/driver/mysql/MysqlConnectorTest.java
  35. 5 0
      example/src/main/java/com/alibaba/otter/canal/example/AbstractCanalClientTest.java
  36. 6 0
      protocol/pom.xml
  37. 6253 0
      protocol/src/main/java/com/alibaba/otter/canal/protocol/AdminPacket.java
  38. 83 0
      protocol/src/main/java/com/alibaba/otter/canal/protocol/AdminProtocol.proto
  39. 5 5
      protocol/src/main/java/com/alibaba/otter/canal/protocol/CanalPacket.java
  40. 223 0
      protocol/src/main/java/com/alibaba/otter/canal/protocol/SecurityUtil.java
  41. 39 19
      server/src/main/java/com/alibaba/otter/canal/admin/CanalAdmin.java
  42. 119 0
      server/src/main/java/com/alibaba/otter/canal/admin/handler/ClientAuthenticationHandler.java
  43. 62 0
      server/src/main/java/com/alibaba/otter/canal/admin/handler/HandshakeInitializationHandler.java
  44. 154 0
      server/src/main/java/com/alibaba/otter/canal/admin/handler/SessionHandler.java
  45. 63 0
      server/src/main/java/com/alibaba/otter/canal/admin/netty/AdminNettyUtils.java
  46. 127 0
      server/src/main/java/com/alibaba/otter/canal/admin/netty/CanalAdminWithNetty.java
  47. 2 0
      server/src/main/java/com/alibaba/otter/canal/common/CanalMessageSerializer.java
  48. 35 0
      server/src/main/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded.java
  49. 13 8
      server/src/main/java/com/alibaba/otter/canal/server/netty/NettyUtils.java
  50. 18 1
      server/src/main/java/com/alibaba/otter/canal/server/netty/handler/ClientAuthenticationHandler.java
  51. 17 2
      server/src/main/java/com/alibaba/otter/canal/server/netty/handler/HandshakeInitializationHandler.java
  52. 107 34
      server/src/main/java/com/alibaba/otter/canal/server/netty/handler/SessionHandler.java
  53. 13 7
      server/src/test/java/com/alibaba/otter/canal/server/CanalServerTest.java
  54. 22 0
      server/src/test/java/com/alibaba/otter/canal/server/SecurityUtilTest.java

+ 5 - 4
.gitignore

@@ -18,7 +18,8 @@ jtester.properties
 *.rpm
 client-adapter/example/
 *.dat
-
-canal-admin/canal-admin-ui/dist
-canal-admin/canal-admin-ui/node
-canal-admin/canal-admin-ui/node_modules
+conf/
+canal-admin/canal-admin-ui/dist/
+canal-admin/canal-admin-ui/node/
+canal-admin/canal-admin-ui/node_modules/
+canal-admin/canal-admin-server/src/main/resources/conf/

+ 63 - 0
canal-admin/canal-admin-server/pom.xml

@@ -12,6 +12,12 @@
     <artifactId>canal-admin-server</artifactId>
 
     <dependencies>
+    	<dependency>
+			<groupId>com.alibaba.otter</groupId>
+			<artifactId>canal.protocol</artifactId>
+			<version>${project.version}</version>
+			<optional>true</optional>
+		</dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
@@ -134,6 +140,63 @@
                                     </resources>
                                 </configuration>
                             </execution>
+                            <execution>
+                                <id>copy canal default conf</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>copy-resources</goal>
+                                </goals>
+                                <configuration>
+                                    <outputDirectory>src/main/resources/conf</outputDirectory>
+                                    <overwrite>true</overwrite>
+                                    <resources>
+                                        <resource>
+                                            <directory>${project.parent.basedir}/../deployer/src/main/resources</directory>
+                                            <includes>
+                                                <include>canal.properties</include>
+                                            </includes>
+                                        </resource>
+                                    </resources>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>copy instance default conf</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>copy-resources</goal>
+                                </goals>
+                                <configuration>
+                                    <outputDirectory>src/main/resources/conf</outputDirectory>
+                                    <overwrite>true</overwrite>
+                                    <resources>
+                                        <resource>
+                                            <directory>${project.parent.basedir}/../deployer/src/main/resources/example</directory>
+                                            <includes>
+                                                <include>instance.properties</include>
+                                            </includes>
+                                        </resource>
+                                    </resources>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>copy client default conf</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>copy-resources</goal>
+                                </goals>
+                                <configuration>
+                                    <outputDirectory>src/main/resources/conf</outputDirectory>
+                                    <overwrite>true</overwrite>
+                                    <resources>
+                                        <resource>
+                                            <directory>${project.parent.basedir}/../client-adapter/launcher/src/main/resources</directory>
+                                            <includes>
+                                                <include>application.yml</include>
+                                            </includes>
+                                        </resource>
+                                    </resources>
+                                </configuration>
+                            </execution>
                         </executions>
                     </plugin>
                 </plugins>

+ 16 - 14
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/common/exception/ServiceException.java

@@ -25,23 +25,25 @@ import org.springframework.web.bind.annotation.ResponseStatus;
 @ResponseStatus(value = HttpStatus.SERVICE_UNAVAILABLE)
 public class ServiceException extends RuntimeException {
 
-	public ServiceException() {
-	}
+    private static final long serialVersionUID = -663217666968123330L;
 
-	public ServiceException(String message) {
-		super(message);
-	}
+    public ServiceException(){
+    }
 
-	public ServiceException(String message, Throwable cause) {
-		super(message, cause);
-	}
+    public ServiceException(String message){
+        super(message);
+    }
 
-	public ServiceException(Throwable cause) {
-		super(cause);
-	}
+    public ServiceException(String message, Throwable cause){
+        super(message, cause);
+    }
 
-	public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
-		super(message, cause, enableSuppression, writableStackTrace);
-	}
+    public ServiceException(Throwable cause){
+        super(cause);
+    }
+
+    public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace){
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
 
 }

+ 124 - 0
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/connector/AdminConnector.java

@@ -0,0 +1,124 @@
+package com.alibaba.otter.canal.admin.connector;
+
+import com.alibaba.otter.canal.admin.common.exception.ServiceException;
+import com.alibaba.otter.canal.protocol.exception.CanalClientException;
+
+/**
+ * canal数据操作客户端
+ * 
+ * @author zebin.xuzb @ 2012-6-19
+ * @author jianghang
+ * @version 1.0.0
+ */
+public interface AdminConnector {
+
+    /**
+     * 链接对应的canal server
+     * 
+     * @throws CanalClientException
+     */
+    void connect() throws ServiceException;
+
+    /**
+     * 释放链接
+     * 
+     * @throws CanalClientException
+     */
+    void disconnect() throws ServiceException;
+
+    /**
+     * 获取Canal Server状态
+     *
+     * @return 状态代码
+     */
+    boolean check();
+
+    /**
+     * 启动Canal Server
+     *
+     * @return 是否成功
+     */
+    boolean start();
+
+    /**
+     * 停止Canal Server
+     *
+     * @return 是否成功
+     */
+    boolean stop();
+
+    /**
+     * 重启Canal Server
+     *
+     * @return 是否成功
+     */
+    boolean restart();
+
+    /**
+     * 获取所有当前节点下运行中的实例
+     *
+     * @return 实例信息
+     */
+    String getRunningInstances();
+
+    /**
+     * 通过实例名检查
+     * 
+     * @param destination
+     * @return
+     */
+    boolean checkInstance(String destination);
+
+    /**
+     * 通过实例名启动实例
+     *
+     * @param destination 实例名
+     * @return 是否成功
+     */
+    boolean startInstance(String destination);
+
+    /**
+     * 通过实例名关闭实例
+     *
+     * @param destination 实例名
+     * @return 是否成功
+     */
+    boolean stopInstance(String destination);
+
+    /**
+     * 通过实例名重启实例
+     *
+     * @param destination 实例名
+     * @return 是否成功
+     */
+    boolean restartInstance(String destination);
+
+    /**
+     * 获取Canal Server日志列表
+     *
+     * @return 日志信息
+     */
+    String listCanalLog();
+
+    /**
+     * 获取Canal Server日志
+     *
+     * @return 日志信息
+     */
+    String canalLog(int lines);
+
+    /**
+     * 获取Instance的机器日志列表
+     * 
+     * @param destination
+     */
+    String listInstanceLog(String destination);
+
+    /**
+     * 通过实例名获取实例日志
+     *
+     * @return 日志信息
+     */
+    String instanceLog(String destination, String fileName, int lines);
+
+}

+ 318 - 0
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/connector/SimpleAdminConnector.java

@@ -0,0 +1,318 @@
+package com.alibaba.otter.canal.admin.connector;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.Channel;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.WritableByteChannel;
+import java.security.NoSuchAlgorithmException;
+
+import org.apache.commons.lang.BooleanUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.alibaba.otter.canal.admin.common.exception.ServiceException;
+import com.alibaba.otter.canal.protocol.AdminPacket.Ack;
+import com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth;
+import com.alibaba.otter.canal.protocol.AdminPacket.Handshake;
+import com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin;
+import com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin;
+import com.alibaba.otter.canal.protocol.AdminPacket.Packet;
+import com.alibaba.otter.canal.protocol.AdminPacket.PacketType;
+import com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin;
+import com.alibaba.otter.canal.protocol.SecurityUtil;
+import com.alibaba.otter.canal.protocol.exception.CanalClientException;
+import com.google.protobuf.ByteString;
+
+/**
+ * 基于netty实现的admin控制
+ * 
+ * @author agapple 2019年8月26日 上午10:23:44
+ * @since 1.1.4
+ */
+public class SimpleAdminConnector implements AdminConnector {
+
+    private static final Logger logger      = LoggerFactory.getLogger(SimpleAdminConnector.class);
+    private String              user;
+    private String              passwd;
+    private SocketAddress       address;
+    private int                 soTimeout   = 60000;                                              // milliseconds
+    private int                 idleTimeout = 60 * 60 * 1000;                                     // client和server之间的空闲链接超时的时间,默认为1小时
+    private final ByteBuffer    readHeader  = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
+    private final ByteBuffer    writeHeader = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
+    private SocketChannel       channel;
+    private ReadableByteChannel readableChannel;
+    private WritableByteChannel writableChannel;
+    private volatile boolean    connected   = false;
+
+    public SimpleAdminConnector(String ip, int port, String user, String passwd){
+        this.address = new InetSocketAddress(ip, port);
+        this.user = user;
+        this.passwd = passwd;
+    }
+
+    @Override
+    public void connect() throws ServiceException {
+        try {
+            if (connected) {
+                return;
+            }
+
+            channel = SocketChannel.open();
+            channel.socket().setSoTimeout(soTimeout);
+            channel.connect(address);
+            readableChannel = Channels.newChannel(channel.socket().getInputStream());
+            writableChannel = Channels.newChannel(channel.socket().getOutputStream());
+            Packet p = Packet.parseFrom(readNextPacket());
+            if (p.getVersion() != 1) {
+                throw new CanalClientException("unsupported version at this client.");
+            }
+
+            if (p.getType() != PacketType.HANDSHAKE) {
+                throw new CanalClientException("expect handshake but found other type.");
+            }
+
+            Handshake handshake = Handshake.parseFrom(p.getBody());
+            ByteString seed = handshake.getSeeds(); // seed for auth
+            String newPasswd = passwd;
+            if (passwd != null) {
+                // encode passwd
+                newPasswd = SecurityUtil.byte2HexStr(SecurityUtil.scramble411(passwd.getBytes(), seed.toByteArray()));
+            }
+
+            ClientAuth ca = ClientAuth.newBuilder()
+                .setUsername(user != null ? user : "")
+                .setPassword(ByteString.copyFromUtf8(newPasswd != null ? newPasswd : ""))
+                .setNetReadTimeout(idleTimeout)
+                .setNetWriteTimeout(idleTimeout)
+                .build();
+            writeWithHeader(Packet.newBuilder()
+                .setType(PacketType.CLIENTAUTHENTICATION)
+                .setBody(ca.toByteString())
+                .build()
+                .toByteArray());
+            //
+            Packet ack = Packet.parseFrom(readNextPacket());
+            if (ack.getType() != PacketType.ACK) {
+                throw new CanalClientException("unexpected packet type when ack is expected");
+            }
+
+            Ack ackBody = Ack.parseFrom(ack.getBody());
+            if (ackBody.getCode() > 0) {
+                throw new ServiceException("something goes wrong when doing authentication: " + ackBody.getMessage());
+            }
+
+            connected = true;
+        } catch (IOException e) {
+            throw new ServiceException(e);
+        } catch (NoSuchAlgorithmException e) {
+            throw new ServiceException(e);
+        }
+    }
+
+    @Override
+    public void disconnect() throws ServiceException {
+        if (!connected) {
+            return;
+        }
+
+        connected = false;
+        if (readableChannel != null) {
+            quietlyClose(readableChannel);
+            readableChannel = null;
+        }
+        if (writableChannel != null) {
+            quietlyClose(writableChannel);
+            writableChannel = null;
+        }
+        if (channel != null) {
+            quietlyClose(channel);
+            channel = null;
+        }
+    }
+
+    @Override
+    public boolean check() {
+        return BooleanUtils.toBoolean(Integer.valueOf(doServerAdmin("check")));
+    }
+
+    @Override
+    public boolean start() {
+        return BooleanUtils.toBoolean(Integer.valueOf(doServerAdmin("start")));
+    }
+
+    @Override
+    public boolean stop() {
+        return BooleanUtils.toBoolean(Integer.valueOf(doServerAdmin("stop")));
+    }
+
+    @Override
+    public boolean restart() {
+        return BooleanUtils.toBoolean(Integer.valueOf(doServerAdmin("restart")));
+    }
+
+    @Override
+    public String getRunningInstances() {
+        return doServerAdmin("list");
+    }
+
+    @Override
+    public boolean checkInstance(String destination) {
+        return BooleanUtils.toBoolean(Integer.valueOf(doInstanceAdmin(destination, "check")));
+    }
+
+    @Override
+    public boolean startInstance(String destination) {
+        return BooleanUtils.toBoolean(Integer.valueOf(doInstanceAdmin(destination, "start")));
+    }
+
+    @Override
+    public boolean stopInstance(String destination) {
+        return BooleanUtils.toBoolean(Integer.valueOf(doInstanceAdmin(destination, "stop")));
+    }
+
+    @Override
+    public boolean restartInstance(String destination) {
+        return BooleanUtils.toBoolean(Integer.valueOf(doInstanceAdmin(destination, "restart")));
+    }
+
+    @Override
+    public String listCanalLog() {
+        return doLogAdmin("server", "list", null, null, 0);
+    }
+
+    @Override
+    public String canalLog(int lines) {
+        return doLogAdmin("server", "file", null, null, lines);
+    }
+
+    @Override
+    public String listInstanceLog(String destination) {
+        return doLogAdmin("instance", "list", destination, null, 0);
+    }
+
+    @Override
+    public String instanceLog(String destination, String fileName, int lines) {
+        return doLogAdmin("instance", "file", destination, fileName, lines);
+    }
+
+    // ==================== helper method ====================
+
+    private String doServerAdmin(String action) {
+        try {
+            writeWithHeader(Packet.newBuilder()
+                .setType(PacketType.SERVER)
+                .setBody(ServerAdmin.newBuilder().setAction(action).build().toByteString())
+                .build()
+                .toByteArray());
+
+            Packet p = Packet.parseFrom(readNextPacket());
+            Ack ack = Ack.parseFrom(p.getBody());
+            if (ack.getCode() > 0) {
+                throw new ServiceException("failed to subscribe with reason: " + ack.getMessage());
+            }
+
+            return ack.getMessage();
+        } catch (IOException e) {
+            throw new ServiceException(e);
+        }
+    }
+
+    private String doInstanceAdmin(String destination, String action) {
+        try {
+            writeWithHeader(Packet.newBuilder()
+                .setType(PacketType.INSTANCE)
+                .setBody(InstanceAdmin.newBuilder()
+                    .setDestination(destination)
+                    .setAction(action)
+                    .build()
+                    .toByteString())
+                .build()
+                .toByteArray());
+
+            Packet p = Packet.parseFrom(readNextPacket());
+            Ack ack = Ack.parseFrom(p.getBody());
+            if (ack.getCode() > 0) {
+                throw new ServiceException("failed to subscribe with reason: " + ack.getMessage());
+            }
+
+            return ack.getMessage();
+        } catch (IOException e) {
+            throw new ServiceException(e);
+        }
+    }
+
+    private String doLogAdmin(String type, String action, String destination, String file, int count) {
+        try {
+            writeWithHeader(Packet.newBuilder()
+                .setType(PacketType.LOG)
+                .setBody(LogAdmin.newBuilder()
+                    .setType(type)
+                    .setAction(action)
+                    .setDestination(destination == null ? "" : destination)
+                    .setFile(file == null ? "" : file)
+                    .setCount(count)
+                    .build()
+                    .toByteString())
+                .build()
+                .toByteArray());
+
+            Packet p = Packet.parseFrom(readNextPacket());
+            Ack ack = Ack.parseFrom(p.getBody());
+            if (ack.getCode() > 0) {
+                throw new ServiceException("failed to subscribe with reason: " + ack.getMessage());
+            }
+
+            return ack.getMessage();
+        } catch (IOException e) {
+            throw new ServiceException(e);
+        }
+    }
+
+    private void writeWithHeader(byte[] body) throws IOException {
+        writeWithHeader(writableChannel, body);
+    }
+
+    private byte[] readNextPacket() throws IOException {
+        return readNextPacket(readableChannel);
+    }
+
+    private void writeWithHeader(WritableByteChannel channel, byte[] body) throws IOException {
+        writeHeader.clear();
+        writeHeader.putInt(body.length);
+        writeHeader.flip();
+        channel.write(writeHeader);
+        channel.write(ByteBuffer.wrap(body));
+    }
+
+    private byte[] readNextPacket(ReadableByteChannel channel) throws IOException {
+        readHeader.clear();
+        read(channel, readHeader);
+        int bodyLen = readHeader.getInt(0);
+        ByteBuffer bodyBuf = ByteBuffer.allocate(bodyLen).order(ByteOrder.BIG_ENDIAN);
+        read(channel, bodyBuf);
+        return bodyBuf.array();
+    }
+
+    private void read(ReadableByteChannel channel, ByteBuffer buffer) throws IOException {
+        while (buffer.hasRemaining()) {
+            int r = channel.read(buffer);
+            if (r == -1) {
+                throw new IOException("end of stream when reading header");
+            }
+        }
+    }
+
+    private void quietlyClose(Channel channel) {
+        try {
+            channel.close();
+        } catch (IOException e) {
+            logger.warn("exception on closing channel:{} \n {}", channel, e);
+        }
+    }
+}

+ 31 - 0
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/connector/SimpleAdminConnectors.java

@@ -0,0 +1,31 @@
+package com.alibaba.otter.canal.admin.connector;
+
+import java.util.function.Function;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SimpleAdminConnectors {
+
+    private static final Logger logger        = LoggerFactory.getLogger(SimpleAdminConnectors.class);
+    private static String       defaultUser   = "admin";
+    private static String       defaultPasswd = "admin";
+
+    public static <R> R execute(String ip, int port, Function<AdminConnector, R> function) {
+        return execute(ip, port, defaultUser, defaultPasswd, function);
+    }
+
+    public static <R> R execute(String ip, int port, String user, String passwd, Function<AdminConnector, R> function) {
+        SimpleAdminConnector connector = new SimpleAdminConnector(ip, port, user, passwd);
+        try {
+            connector.connect();
+            return function.apply(connector);
+        } catch (Exception e) {
+            logger.error(e.getMessage());
+        } finally {
+            connector.disconnect();
+        }
+
+        return null;
+    }
+}

+ 20 - 1
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/controller/CanalInstanceController.java

@@ -4,7 +4,14 @@ import java.util.List;
 import java.util.Map;
 
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import com.alibaba.otter.canal.admin.model.BaseModel;
 import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
@@ -49,6 +56,18 @@ public class CanalInstanceController {
         return BaseModel.getInstance("success");
     }
 
+    /**
+     * 实例详情信息
+     *
+     * @param id 实例配置id
+     * @param env 环境变量
+     * @return 实例信息
+     */
+    @GetMapping(value = "/instance")
+    public BaseModel<CanalInstanceConfig> config(@PathVariable Long id, @PathVariable String env) {
+        return BaseModel.getInstance(canalInstanceConfigService.detail(id));
+    }
+
     /**
      * 实例详情信息
      *

+ 0 - 164
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/jmx/JMXConnection.java

@@ -1,164 +0,0 @@
-package com.alibaba.otter.canal.admin.jmx;
-
-import com.alibaba.otter.canal.admin.common.exception.ServiceException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.management.*;
-import javax.management.remote.JMXConnector;
-import javax.management.remote.JMXConnectorFactory;
-import javax.management.remote.JMXServiceURL;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.SocketTimeoutException;
-import java.util.concurrent.*;
-import java.util.function.Function;
-
-/**
- * Canal Server JMX 控制层
- *
- * @author rewerma 2019-07-13 下午05:12:16
- * @version 1.0.0
- */
-public class JMXConnection {
-
-    private static final Logger logger = LoggerFactory.getLogger(JMXConnection.class);
-
-    private String              ip;
-    private Integer             port;
-    private JMXConnector        jmxc;
-    private CanalServerMXBean   canalServerMXBean;
-
-    public JMXConnection(String ip, Integer port){
-        this.ip = ip;
-        this.port = port;
-    }
-
-    /**
-     * 执行相关操作
-     *
-     * @param ip jmx ip
-     * @param port jmx port
-     * @param function 执行方法
-     * @param <R> 返回泛型
-     * @return 执行结果
-     */
-    public static <R> R execute(String ip, int port, Function<CanalServerMXBean, R> function) {
-        JMXConnection jmxConnection = new JMXConnection(ip, port);
-        try {
-            CanalServerMXBean canalServerMXBean = jmxConnection.getCanalServerMXBean();
-            return function.apply(canalServerMXBean);
-        } catch (Exception e) {
-            logger.error(e.getMessage());
-        } finally {
-            jmxConnection.close();
-        }
-        return null;
-    }
-
-    /**
-     * 连接远程jmx
-     */
-    public void connect() {
-        try {
-            JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + ip + ":" + port + "/jmxrmi");
-            // jmxc = JMXConnectorFactory.connect(url, null);
-            jmxc = connectWithTimeout(url, 3, TimeUnit.SECONDS);
-            MBeanServerConnection mBeanServerConnection = jmxc.getMBeanServerConnection();
-            ObjectName name = new ObjectName("CanalServerAgent:type=CanalServerStatus");
-            mBeanServerConnection.addNotificationListener(name, (notification, handback) -> {
-            }, null, null);
-            canalServerMXBean = MBeanServerInvocationHandler
-                .newProxyInstance(mBeanServerConnection, name, CanalServerMXBean.class, false);
-        } catch (Exception e) {
-            throw new ServiceException(e.getMessage(), e);
-        }
-    }
-
-    /**
-     * 带超时的jmx连接器
-     *
-     * @param url jmx url
-     * @param timeout 超时时间
-     * @param unit 超时时间单位
-     * @return JMXConnector
-     * @throws IOException 连接异常
-     */
-    private static JMXConnector connectWithTimeout(final JMXServiceURL url, long timeout,
-                                                   TimeUnit unit) throws IOException {
-        final BlockingQueue<Object> mailbox = new ArrayBlockingQueue<>(1);
-        ExecutorService executor = Executors.newSingleThreadExecutor(daemonThreadFactory);
-        executor.submit(() -> {
-            try {
-                JMXConnector connector = JMXConnectorFactory.connect(url);
-                if (!mailbox.offer(connector)) connector.close();
-            } catch (Throwable t) {
-                mailbox.offer(t);
-            }
-        });
-        Object result;
-        try {
-            result = mailbox.poll(timeout, unit);
-            if (result == null) {
-                if (!mailbox.offer("")) result = mailbox.take();
-            }
-        } catch (InterruptedException e) {
-            throw initCause(new InterruptedIOException(e.getMessage()), e);
-        } finally {
-            executor.shutdown();
-        }
-        if (result == null) throw new SocketTimeoutException("Connect timed out: " + url);
-        if (result instanceof JMXConnector) return (JMXConnector) result;
-        try {
-            throw (Throwable) result;
-        } catch (IOException | RuntimeException | Error e) {
-            throw e;
-        } catch (Throwable e) {
-            // In principle this can't happen but we wrap it anyway
-            throw new IOException(e.toString(), e);
-        }
-    }
-
-    private static <T extends Throwable> T initCause(T wrapper, Throwable wrapped) {
-        wrapper.initCause(wrapped);
-        return wrapper;
-    }
-
-    private static class DaemonThreadFactory implements ThreadFactory {
-
-        public Thread newThread(Runnable r) {
-            Thread t = Executors.defaultThreadFactory().newThread(r);
-            t.setDaemon(true);
-            return t;
-        }
-    }
-
-    private static final ThreadFactory daemonThreadFactory = new DaemonThreadFactory();
-
-    /**
-     * 获取MBean
-     *
-     * @return canalServerMXBean
-     */
-    public CanalServerMXBean getCanalServerMXBean() {
-        if (jmxc == null) {
-            connect();
-        }
-        return canalServerMXBean;
-    }
-
-    /**
-     * 关闭jmx连接
-     */
-    public void close() {
-        try {
-            if (jmxc != null) {
-                jmxc.close();
-            }
-        } catch (Exception e) {
-            logger.error(e.getMessage(), e);
-        } finally {
-            jmxc = null;
-        }
-    }
-}

+ 4 - 2
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/Model.java

@@ -2,12 +2,14 @@ package com.alibaba.otter.canal.admin.model;
 
 import io.ebean.Ebean;
 import io.ebean.EbeanServer;
-import org.apache.commons.beanutils.PropertyUtils;
+
+import java.lang.reflect.Field;
 
 import javax.persistence.Id;
 import javax.persistence.MappedSuperclass;
 import javax.persistence.OptimisticLockException;
-import java.lang.reflect.Field;
+
+import org.apache.commons.beanutils.PropertyUtils;
 
 /**
  * EBean Model扩展类

+ 71 - 3
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/CanalConfigServiceImpl.java

@@ -1,5 +1,13 @@
 package com.alibaba.otter.canal.admin.service.impl;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import com.alibaba.otter.canal.admin.model.CanalConfig;
@@ -14,15 +22,75 @@ import com.alibaba.otter.canal.admin.service.CanalConfigService;
 @Service
 public class CanalConfigServiceImpl implements CanalConfigService {
 
+    private Logger              logger               = LoggerFactory.getLogger(CanalConfigServiceImpl.class);
+
+    private static final String CANAL_GLOBAL_CONFIG  = "canal.properties";
+    private static final String CANAL_ADAPTER_CONFIG = "application.yml";
+
     public CanalConfig getCanalConfig() {
-        return CanalConfig.find.byId(1L);
+        long id = 1L;
+        CanalConfig config = CanalConfig.find.byId(id);
+        if (config == null) {
+            String context = loadDefaultConf(CANAL_GLOBAL_CONFIG);
+            if (context == null) {
+                return null;
+            }
+
+            config = new CanalConfig();
+            config.setId(id);
+            config.setName(CANAL_GLOBAL_CONFIG);
+            config.setModifiedTime(new Date());
+            config.setContent(context);
+            return config;
+        }
+
+        return config;
     }
 
     public CanalConfig getAdapterConfig() {
-        return CanalConfig.find.byId(2L);
+        long id = 2L;
+        CanalConfig config = CanalConfig.find.byId(id);
+        if (config == null) {
+            String context = loadDefaultConf(CANAL_ADAPTER_CONFIG);
+            if (context == null) {
+                return null;
+            }
+
+            config = new CanalConfig();
+            config.setId(id);
+            config.setName(CANAL_ADAPTER_CONFIG);
+            config.setModifiedTime(new Date());
+            config.setContent(context);
+            return config;
+        }
+
+        return config;
     }
 
     public void updateContent(CanalConfig canalConfig) {
-        canalConfig.update("content");
+        try {
+            canalConfig.insert();
+        } catch (Throwable e) {
+            canalConfig.update();
+        }
+    }
+
+    private String loadDefaultConf(String confFileName) {
+        InputStream input = null;
+        try {
+            input = Thread.currentThread().getContextClassLoader().getResourceAsStream("conf/" + confFileName);
+            if (input == null) {
+                return null;
+            }
+
+            return StringUtils.join(IOUtils.readLines(input), "\n");
+        } catch (IOException e) {
+            logger.error("find " + confFileName + " is error!", e);
+            return null;
+        } finally {
+            if (input != null) {
+                IOUtils.closeQuietly(input);
+            }
+        }
     }
 }

+ 13 - 12
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/CanalInstanceServiceImpl.java

@@ -1,5 +1,7 @@
 package com.alibaba.otter.canal.admin.service.impl;
 
+import io.ebean.Query;
+
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -7,14 +9,12 @@ import java.util.Map;
 import org.apache.commons.lang.StringUtils;
 import org.springframework.stereotype.Service;
 
-import com.alibaba.otter.canal.admin.jmx.CanalServerMXBean;
-import com.alibaba.otter.canal.admin.jmx.JMXConnection;
+import com.alibaba.otter.canal.admin.connector.AdminConnector;
+import com.alibaba.otter.canal.admin.connector.SimpleAdminConnectors;
 import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
 import com.alibaba.otter.canal.admin.model.NodeServer;
 import com.alibaba.otter.canal.admin.service.CanalInstanceService;
 
-import io.ebean.Query;
-
 /**
  * Canal实例配置信息业务层
  *
@@ -39,8 +39,9 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
         // check all canal instances running status
         List<NodeServer> nodeServers = NodeServer.find.query().findList();
         for (NodeServer nodeServer : nodeServers) {
-            String runningInstances = JMXConnection
-                .execute(nodeServer.getIp(), nodeServer.getPort(), CanalServerMXBean::getRunningInstances);
+            String runningInstances = SimpleAdminConnectors.execute(nodeServer.getIp(),
+                nodeServer.getPort(),
+                AdminConnector::getRunningInstances);
             if (runningInstances == null) {
                 continue;
             }
@@ -90,9 +91,9 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
             return result;
         }
 
-        String log = JMXConnection.execute(nodeServer.getIp(),
+        String log = SimpleAdminConnectors.execute(nodeServer.getIp(),
             nodeServer.getPort(),
-            canalServerMXBean -> canalServerMXBean.instanceLog(canalInstanceConfig.getName()));
+            adminConnector -> adminConnector.instanceLog(canalInstanceConfig.getName(), null, 100));
 
         result.put("instance", canalInstanceConfig.getName());
         result.put("log", log);
@@ -122,13 +123,13 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
         }
         Boolean resutl = null;
         if ("start".equals(option)) {
-            resutl = JMXConnection.execute(nodeServer.getIp(),
+            resutl = SimpleAdminConnectors.execute(nodeServer.getIp(),
                 nodeServer.getPort(),
-                canalServerMXBean -> canalServerMXBean.startInstance(canalInstanceConfig.getName()));
+                adminConnector -> adminConnector.startInstance(canalInstanceConfig.getName()));
         } else if ("stop".equals(option)) {
-            resutl = JMXConnection.execute(nodeServer.getIp(),
+            resutl = SimpleAdminConnectors.execute(nodeServer.getIp(),
                 nodeServer.getPort(),
-                canalServerMXBean -> canalServerMXBean.stopInstance(canalInstanceConfig.getName()));
+                adminConnector -> adminConnector.stopInstance(canalInstanceConfig.getName()));
         } else {
             return false;
         }

+ 18 - 32
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/NodeServerServiceImpl.java

@@ -1,5 +1,7 @@
 package com.alibaba.otter.canal.admin.service.impl;
 
+import io.ebean.Query;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
@@ -8,18 +10,14 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 
 import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import com.alibaba.otter.canal.admin.common.exception.ServiceException;
-import com.alibaba.otter.canal.admin.jmx.CanalServerMXBean;
-import com.alibaba.otter.canal.admin.jmx.JMXConnection;
+import com.alibaba.otter.canal.admin.connector.AdminConnector;
+import com.alibaba.otter.canal.admin.connector.SimpleAdminConnectors;
 import com.alibaba.otter.canal.admin.model.NodeServer;
 import com.alibaba.otter.canal.admin.service.NodeServerService;
 
-import io.ebean.Query;
-
 /**
  * 节点信息业务层
  *
@@ -29,8 +27,6 @@ import io.ebean.Query;
 @Service
 public class NodeServerServiceImpl implements NodeServerService {
 
-    private static final Logger logger = LoggerFactory.getLogger(NodeServerServiceImpl.class);
-
     public void save(NodeServer nodeServer) {
         int cnt = NodeServer.find.query()
             .where()
@@ -90,18 +86,9 @@ public class NodeServerServiceImpl implements NodeServerService {
         // get all nodes status
         for (NodeServer ns : nodeServers) {
             futures.add(executorService.submit(() -> {
-                int status = -1;
-                JMXConnection jmxConnection = new JMXConnection(ns.getIp(), ns.getPort());
-                try {
-                    CanalServerMXBean canalServerMXBean = jmxConnection.getCanalServerMXBean();
-                    status = canalServerMXBean.getStatus();
-                } catch (Exception e) {
-                    logger.warn(e.getMessage());
-                } finally {
-                    jmxConnection.close();
-                }
-                ns.setStatus(status);
-                return status != -1;
+                boolean status = SimpleAdminConnectors.execute(ns.getIp(), ns.getPort(), AdminConnector::check);
+                ns.setStatus(status ? 1 : 0);
+                return !status;
             }));
         }
         futures.forEach(f -> {
@@ -118,11 +105,8 @@ public class NodeServerServiceImpl implements NodeServerService {
     }
 
     public int remoteNodeStatus(String ip, Integer port) {
-        Integer resutl = JMXConnection.execute(ip, port, CanalServerMXBean::getStatus);
-        if (resutl == null) {
-            resutl = -1;
-        }
-        return resutl;
+        boolean result = SimpleAdminConnectors.execute(ip, port, AdminConnector::check);
+        return result ? 1 : 0;
     }
 
     public String remoteCanalLog(Long id) {
@@ -130,7 +114,9 @@ public class NodeServerServiceImpl implements NodeServerService {
         if (nodeServer == null) {
             return "";
         }
-        return JMXConnection.execute(nodeServer.getIp(), nodeServer.getPort(), CanalServerMXBean::canalLog);
+        return SimpleAdminConnectors.execute(nodeServer.getIp(),
+            nodeServer.getPort(),
+            adminConnector -> adminConnector.canalLog(100));
     }
 
     public boolean remoteOperation(Long id, String option) {
@@ -138,18 +124,18 @@ public class NodeServerServiceImpl implements NodeServerService {
         if (nodeServer == null) {
             return false;
         }
-        Boolean resutl = null;
+        Boolean result = null;
         if ("start".equals(option)) {
-            resutl = JMXConnection.execute(nodeServer.getIp(), nodeServer.getPort(), CanalServerMXBean::start);
+            result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getPort(), AdminConnector::start);
         } else if ("stop".equals(option)) {
-            resutl = JMXConnection.execute(nodeServer.getIp(), nodeServer.getPort(), CanalServerMXBean::stop);
+            result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getPort(), AdminConnector::stop);
         } else {
             return false;
         }
 
-        if (resutl == null) {
-            resutl = false;
+        if (result == null) {
+            result = false;
         }
-        return resutl;
+        return result;
     }
 }

+ 31 - 7
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/UserServiceImpl.java

@@ -1,10 +1,14 @@
 package com.alibaba.otter.canal.admin.service.impl;
 
+import java.security.NoSuchAlgorithmException;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+
 import com.alibaba.otter.canal.admin.common.exception.ServiceException;
 import com.alibaba.otter.canal.admin.model.User;
 import com.alibaba.otter.canal.admin.service.UserService;
-import org.apache.commons.lang.StringUtils;
-import org.springframework.stereotype.Service;
+import com.alibaba.otter.canal.protocol.SecurityUtil;
 
 /**
  * 用户信息业务层
@@ -15,11 +19,22 @@ import org.springframework.stereotype.Service;
 @Service
 public class UserServiceImpl implements UserService {
 
+    private static byte[] seeds = "canal is best!".getBytes();
+
     public User find4Login(String username, String password) {
         if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
             return null;
         }
-        User user = User.find.query().where().eq("username", username).eq("password", password).findOne();
+        User user = User.find.query().where().eq("username", username).findOne();
+        try {
+            byte[] pass = SecurityUtil.scramble411(password.getBytes(), seeds);
+            if (!SecurityUtil.scrambleServerAuth(pass, SecurityUtil.hexStr2Bytes(user.getPassword()), seeds)) {
+                throw new ServiceException("user:" + user.getName() + " passwd incorrect!");
+            }
+        } catch (NoSuchAlgorithmException e) {
+            throw new ServiceException("user:" + user.getName() + " auth failed!");
+        }
+
         if (user != null) {
             user.setPassword("");
         }
@@ -27,14 +42,23 @@ public class UserServiceImpl implements UserService {
     }
 
     public void update(User user) {
-        User userTmp = User.find.byId(1L);
+        User userTmp = User.find.query().where().eq("username", user.getUsername()).findOne();
         if (userTmp == null) {
             throw new ServiceException();
         }
-        if (!userTmp.getPassword().equals(user.getOldPassword())) {
-            throw new ServiceException("错误的旧密码");
+
+        try {
+            byte[] pass = SecurityUtil.scramble411(user.getOldPassword().getBytes(), seeds);
+            if (!SecurityUtil.scrambleServerAuth(pass, SecurityUtil.hexStr2Bytes(userTmp.getPassword()), seeds)) {
+                throw new ServiceException("old passwd is unmatch");
+            }
+
+            user.setId(userTmp.getId());
+            user.setPassword(SecurityUtil.scrambleGenPass(user.getPassword().getBytes()));
+        } catch (NoSuchAlgorithmException e) {
+            throw new ServiceException("passwd process failed");
         }
-        user.setId(1L);
+
         user.update("username", "nn:password");
     }
 }

+ 85 - 0
canal-admin/canal-admin-server/src/main/resources/canal_manager.sql

@@ -0,0 +1,85 @@
+CREATE DATABASE /*!32312 IF NOT EXISTS*/ `canal_manager` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */;
+
+USE `canal_manager`;
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for canal_adapter_config
+-- ----------------------------
+DROP TABLE IF EXISTS `canal_adapter_config`;
+CREATE TABLE `canal_adapter_config` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
+  `category` varchar(45) NOT NULL,
+  `name` varchar(45) NOT NULL,
+  `content` text NOT NULL,
+  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
+
+-- ----------------------------
+-- Table structure for canal_config
+-- ----------------------------
+DROP TABLE IF EXISTS `canal_config`;
+CREATE TABLE `canal_config` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
+  `name` varchar(45) NOT NULL,
+  `content` text NOT NULL,
+  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `name_UNIQUE` (`name`)
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
+
+-- ----------------------------
+-- Table structure for canal_instance_config
+-- ----------------------------
+DROP TABLE IF EXISTS `canal_instance_config`;
+CREATE TABLE `canal_instance_config` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
+  `name` varchar(45) NOT NULL,
+  `content` text NOT NULL,
+  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `name_UNIQUE` (`name`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
+
+-- ----------------------------
+-- Table structure for canal_node_server
+-- ----------------------------
+DROP TABLE IF EXISTS `canal_node_server`;
+CREATE TABLE `canal_node_server` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
+  `name` varchar(63) NOT NULL,
+  `ip` varchar(63) NOT NULL,
+  `port` int(11) DEFAULT NULL,
+  `port2` int(11) DEFAULT NULL,
+  `status` int(11) NOT NULL,
+  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
+
+-- ----------------------------
+-- Table structure for canal_user
+-- ----------------------------
+DROP TABLE IF EXISTS `canal_user`;
+CREATE TABLE `canal_user` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
+  `username` varchar(31) NOT NULL,
+  `password` varchar(128) NOT NULL,
+  `name` varchar(31) NOT NULL,
+  `roles` varchar(31) NOT NULL,
+  `introduction` varchar(255) DEFAULT NULL,
+  `avatar` varchar(255) DEFAULT NULL,
+  `creation_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
+
+-- ----------------------------
+-- Records of canal_user
+-- ----------------------------
+BEGIN;
+INSERT INTO `canal_user` VALUES (1, 'admin', '6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9', 'Canal Manager', 'admin', NULL, NULL, '2019-07-14 00:05:28');
+COMMIT;
+
+SET FOREIGN_KEY_CHECKS = 1;

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
canal-admin/canal-admin-server/src/main/resources/public/index.html


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
canal-admin/canal-admin-server/src/main/resources/public/static/js/chunk-e1a839e4.3175ead5.js


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
canal-admin/canal-admin-server/src/main/resources/public/static/js/chunk-e1a839e4.7ee86dd8.js


+ 40 - 0
canal-admin/canal-admin-server/src/test/java/com/alibaba/otter/canal/admin/SimpleAdminConnectorTest.java

@@ -0,0 +1,40 @@
+package com.alibaba.otter.canal.admin;
+
+import org.junit.Test;
+
+import com.alibaba.otter.canal.admin.connector.SimpleAdminConnector;
+
+public class SimpleAdminConnectorTest {
+
+    @Test
+    public void testSimple() {
+        SimpleAdminConnector connector = new SimpleAdminConnector("127.0.0.1", 11110, "admin", "admin");
+        connector.connect();
+        System.out.println("check 1 : " + connector.check());
+        System.out.println("getRunning Before stop 1 : " + connector.getRunningInstances());
+        System.out.println("stop 1: " + connector.stop());
+        System.out.println("getRunning After stop 1 : " + connector.getRunningInstances());
+        System.out.println("check 1 : " + connector.check());
+        System.out.println("listFile 1 : " + connector.listCanalLog());
+        System.out.println("getFile 1 : " + connector.canalLog(10));
+        connector.disconnect();
+
+        connector.connect();
+        System.out.println("check 2 : " + connector.check());
+        System.out.println("get Running Before start : " + connector.getRunningInstances());
+        System.out.println("start 2 : " + connector.start());
+        System.out.println("get Running After start : " + connector.getRunningInstances());
+        System.out.println("check 2 : " + connector.check());
+        System.out.println("check after before example 2 : " + connector.checkInstance("example"));
+        System.out.println("stop example 2 : " + connector.stopInstance("example"));
+        System.out.println("check example 2 : " + connector.checkInstance("example"));
+        System.out.println("start example 2 : " + connector.startInstance("example"));
+        System.out.println("check after start example 2 : " + connector.checkInstance("example"));
+        System.out.println("listFile 2 : " + connector.listCanalLog());
+        System.out.println("getFile 2 : " + connector.canalLog(10));
+
+        System.out.println("listFile 3 : " + connector.listInstanceLog("example"));
+        System.out.println("getFile 3 : " + connector.instanceLog("example", "example.log", 10));
+        connector.disconnect();
+    }
+}

+ 0 - 20
canal-admin/canal-admin-server/src/test/java/com/alibaba/otter/canal/admin/jmx/JMXConnectionTest.java

@@ -1,20 +0,0 @@
-package com.alibaba.otter.canal.admin.jmx;
-
-import org.junit.Test;
-
-public class JMXConnectionTest {
-
-    @Test
-    public void testSimple() {
-
-        JMXConnection jmxConnection = new JMXConnection("127.0.0.1", 11113);
-        try {
-            CanalServerMXBean canalServerMXBean = jmxConnection.getCanalServerMXBean();
-            System.out.println(canalServerMXBean.getStatus());
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            jmxConnection.close();
-        }
-    }
-}

+ 5 - 5
canal-admin/canal-admin-ui/src/views/canalServer/NodeServer.vue

@@ -25,7 +25,7 @@
           <span>{{ scope.row.ip }}</span>
         </template>
       </el-table-column>
-      <el-table-column label="JMX端口" min-width="100" align="center">
+      <el-table-column label="Admin 端口" min-width="100" align="center">
         <template slot-scope="scope">
           {{ scope.row.port }}
         </template>
@@ -65,8 +65,8 @@
         <el-form-item label="Server IP" prop="ip">
           <el-input v-model="nodeModel.ip" />
         </el-form-item>
-        <el-form-item label="JMX端口" prop="port">
-          <el-input v-model="nodeModel.port" placeholder="11113" type="number" />
+        <el-form-item label="Admin 端口" prop="port">
+          <el-input v-model="nodeModel.port" placeholder="11110" type="number" />
         </el-form-item>
         <el-form-item label="监控端口" prop="port2">
           <el-input v-model="nodeModel.port2" placeholder="11112" type="number" />
@@ -119,13 +119,13 @@ export default {
         id: undefined,
         name: null,
         ip: null,
-        port: 11113,
+        port: 11110,
         port2: 11112
       },
       rules: {
         name: [{ required: true, message: 'Server 名称不能为空', trigger: 'change' }],
         ip: [{ required: true, message: 'Server IP不能为空', trigger: 'change' }],
-        port: [{ required: true, message: 'Server JMX端口不能为空', trigger: 'change' }]
+        port: [{ required: true, message: 'Server Admin端口不能为空', trigger: 'change' }]
       },
       dialogStatus: 'create'
     }

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 22
canal-admin/canal_manager.sql


+ 11 - 2
client/src/main/java/com/alibaba/otter/canal/client/impl/SimpleCanalConnector.java

@@ -10,6 +10,7 @@ import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.SocketChannel;
 import java.nio.channels.WritableByteChannel;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
@@ -38,6 +39,7 @@ import com.alibaba.otter.canal.protocol.CanalPacket.Sub;
 import com.alibaba.otter.canal.protocol.CanalPacket.Unsub;
 import com.alibaba.otter.canal.protocol.ClientIdentity;
 import com.alibaba.otter.canal.protocol.Message;
+import com.alibaba.otter.canal.protocol.SecurityUtil;
 import com.alibaba.otter.canal.protocol.exception.CanalClientException;
 import com.google.protobuf.ByteString;
 
@@ -160,9 +162,16 @@ public class SimpleCanalConnector implements CanalConnector {
             Handshake handshake = Handshake.parseFrom(p.getBody());
             supportedCompressions.add(handshake.getSupportedCompressions());
             //
+            ByteString seed = handshake.getSeeds(); // seed for auth
+            String newPasswd = password;
+            if (password != null) {
+                // encode passwd
+                newPasswd = SecurityUtil.byte2HexStr(SecurityUtil.scramble411(password.getBytes(), seed.toByteArray()));
+            }
+
             ClientAuth ca = ClientAuth.newBuilder()
                 .setUsername(username != null ? username : "")
-                .setPassword(ByteString.copyFromUtf8(password != null ? password : ""))
+                .setPassword(ByteString.copyFromUtf8(newPasswd != null ? newPasswd : ""))
                 .setNetReadTimeout(idleTimeout)
                 .setNetWriteTimeout(idleTimeout)
                 .build();
@@ -185,7 +194,7 @@ public class SimpleCanalConnector implements CanalConnector {
 
             connected = true;
             return new InetSocketAddress(channel.socket().getLocalAddress(), channel.socket().getLocalPort());
-        } catch (IOException e) {
+        } catch (IOException | NoSuchAlgorithmException e) {
             throw new CanalClientException(e);
         }
     }

+ 14 - 5
common/src/main/java/com/alibaba/otter/canal/common/utils/FileUtils.java

@@ -12,20 +12,24 @@ public class FileUtils {
     private static final Logger logger = LoggerFactory.getLogger(FileUtils.class);
 
     public static String readFileFromOffset(String filename, int l, String charset) {
+        return readFileFromOffset(filename, l, charset, 4 * 1024 * 1024);
+    }
+
+    public static String readFileFromOffset(String filename, int l, String charset, int maxSize) {
         RandomAccessFile rf = null;
         StringBuilder res = new StringBuilder();
         try {
             rf = new RandomAccessFile(filename, "r");
-
             long fileLength = rf.length();
-
             long start = rf.getFilePointer();
-
             long readIndex = start + fileLength - 1;
+            long minIndex = readIndex - maxSize;
+            if (minIndex < 0) {
+                minIndex = 0;
+            }
 
             String line;
             rf.seek(readIndex);
-
             int k = 0;
             int c = -1;
             while (readIndex > start) {
@@ -48,7 +52,12 @@ public class FileUtils {
                     readIndex--;
                 }
                 readIndex--;
-                rf.seek(readIndex);
+                if (readIndex < minIndex) {
+                    break;
+                } else {
+                    rf.seek(readIndex);
+                }
+
                 if (readIndex == 0) {
                     readText = rf.readLine();
                 }

+ 1 - 0
common/src/main/java/com/alibaba/otter/canal/common/zookeeper/running/ServerRunningMonitor.java

@@ -148,6 +148,7 @@ public class ServerRunningMonitor extends AbstractCanalLifeCycle {
             activeData = serverData;
             processActiveEnter();// 触发一下事件
             mutex.set(true);
+            release = false;
         } catch (ZkNodeExistsException e) {
             bytes = zkClient.readData(path, true);
             if (bytes == null) {// 如果不存在节点,立即尝试一次

+ 5 - 1
deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalConstants.java

@@ -16,8 +16,12 @@ public class CanalConstants {
     public static final String CANAL_IP                             = ROOT + "." + "ip";
     public static final String CANAL_REGISTER_IP                    = ROOT + "." + "register.ip";
     public static final String CANAL_PORT                           = ROOT + "." + "port";
+    public static final String CANAL_USER                           = ROOT + "." + "user";
+    public static final String CANAL_PASSWD                         = ROOT + "." + "passwd";
     public static final String CANAL_METRICS_PULL_PORT              = ROOT + "." + "metrics.pull.port";
-    public static final String CANAL_ADMIN_JMX_PORT                 = ROOT + "." + "admin.jmx.port";
+    public static final String CANAL_ADMIN_PORT                     = ROOT + "." + "admin.port";
+    public static final String CANAL_ADMIN_USER                     = ROOT + "." + "admin.user";
+    public static final String CANAL_ADMIN_PASSWD                   = ROOT + "." + "admin.passwd";
     public static final String CANAL_ZKSERVERS                      = ROOT + "." + "zkServers";
     public static final String CANAL_WITHOUT_NETTY                  = ROOT + "." + "withoutNetty";
 

+ 4 - 0
deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalController.java

@@ -121,6 +121,9 @@ public class CanalController {
             embededCanalServer.setMetricsPort(11112);
         }
 
+        embededCanalServer.setUser(getProperty(properties, CanalConstants.CANAL_USER));
+        embededCanalServer.setPasswd(getProperty(properties, CanalConstants.CANAL_PASSWD));
+
         String canalWithoutNetty = getProperty(properties, CanalConstants.CANAL_WITHOUT_NETTY);
         if (canalWithoutNetty == null || "false".equals(canalWithoutNetty)) {
             canalServer = CanalServerWithNetty.instance();
@@ -571,4 +574,5 @@ public class CanalController {
     public Map<String, InstanceConfig> getInstanceConfigs() {
         return instanceConfigs;
     }
+
 }

+ 0 - 23
deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalLauncher.java

@@ -8,9 +8,6 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.alibaba.otter.canal.deployer.mbean.CanalServerAgent;
-import com.alibaba.otter.canal.deployer.mbean.CanalServerBean;
-import com.alibaba.otter.canal.deployer.mbean.CanalServerMXBean;
 import com.alibaba.otter.canal.deployer.monitor.remote.RemoteCanalConfigMonitor;
 import com.alibaba.otter.canal.deployer.monitor.remote.RemoteConfigLoader;
 import com.alibaba.otter.canal.deployer.monitor.remote.RemoteConfigLoaderFactory;
@@ -76,27 +73,7 @@ public class CanalLauncher {
                 });
             }
 
-            CanalServerAgent canalServerAgent = null;
-            String jmxPort = properties.getProperty(CanalConstants.CANAL_ADMIN_JMX_PORT);
-            if (StringUtils.isNotEmpty(jmxPort)) {
-                String ip = properties.getProperty(CanalConstants.CANAL_IP);
-                String registerIp = properties.getProperty(CanalConstants.CANAL_REGISTER_IP);
-                if (StringUtils.isEmpty(registerIp)) {
-                    // 兼容老的配置
-                    registerIp = ip;
-                }
-                CanalServerMXBean canalServerMBean = new CanalServerBean(canalStater);
-                canalServerAgent = new CanalServerAgent(registerIp, Integer.parseInt(jmxPort), canalServerMBean);
-                Thread agentThread = new Thread(canalServerAgent::start);
-                agentThread.start();
-            }
-
             runningLatch.await();
-
-            if (canalServerAgent != null) {
-                canalServerAgent.stop();
-            }
-
             if (remoteConfigLoader != null) {
                 remoteConfigLoader.destroy();
             }

+ 32 - 1
deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalStater.java

@@ -10,7 +10,9 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.alibaba.otter.canal.admin.netty.CanalAdminWithNetty;
 import com.alibaba.otter.canal.common.MQProperties;
+import com.alibaba.otter.canal.deployer.admin.CanalAdminController;
 import com.alibaba.otter.canal.kafka.CanalKafkaProducer;
 import com.alibaba.otter.canal.rocketmq.CanalRocketMQProducer;
 import com.alibaba.otter.canal.server.CanalMQStarter;
@@ -36,6 +38,8 @@ public class CanalStater {
     private volatile Properties properties;
     private volatile boolean    running         = false;
 
+    private CanalAdminWithNetty canalAdmin;
+
     public CanalStater(Properties properties){
         this.properties = properties;
     }
@@ -136,15 +140,42 @@ public class CanalStater {
             controller.setCanalMQStarter(canalMQStarter);
         }
 
+        // start canalAdmin
+        String port = properties.getProperty(CanalConstants.CANAL_ADMIN_PORT);
+        if (canalAdmin == null && StringUtils.isNotEmpty(port)) {
+            String user = properties.getProperty(CanalConstants.CANAL_ADMIN_USER);
+            String passwd = properties.getProperty(CanalConstants.CANAL_ADMIN_PASSWD);
+            CanalAdminController canalAdmin = new CanalAdminController(this);
+            canalAdmin.setUser(user);
+            canalAdmin.setPasswd(passwd);
+
+            String ip = properties.getProperty(CanalConstants.CANAL_IP);
+            CanalAdminWithNetty canalAdminWithNetty = CanalAdminWithNetty.instance();
+            canalAdminWithNetty.setCanalAdmin(canalAdmin);
+            canalAdminWithNetty.setPort(Integer.valueOf(port));
+            canalAdminWithNetty.setIp(ip);
+            canalAdminWithNetty.start();
+            this.canalAdmin = canalAdminWithNetty;
+        }
+
         running = true;
     }
 
+    public synchronized void stop() throws Throwable {
+        stop(false);
+    }
+
     /**
      * 销毁方法,远程配置变更时调用
      *
      * @throws Throwable
      */
-    public synchronized void stop() throws Throwable {
+    public synchronized void stop(boolean stopByAdmin) throws Throwable {
+        if (!stopByAdmin && canalAdmin != null) {
+            canalAdmin.stop();
+            canalAdmin = null;
+        }
+
         if (controller != null) {
             controller.stop();
             controller = null;

+ 224 - 0
deployer/src/main/java/com/alibaba/otter/canal/deployer/admin/CanalAdminController.java

@@ -0,0 +1,224 @@
+package com.alibaba.otter.canal.deployer.admin;
+
+import java.io.File;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.commons.io.filefilter.TrueFileFilter;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.alibaba.otter.canal.admin.CanalAdmin;
+import com.alibaba.otter.canal.common.utils.FileUtils;
+import com.alibaba.otter.canal.deployer.CanalController;
+import com.alibaba.otter.canal.deployer.CanalStater;
+import com.alibaba.otter.canal.deployer.InstanceConfig;
+import com.alibaba.otter.canal.deployer.monitor.InstanceAction;
+import com.alibaba.otter.canal.deployer.monitor.InstanceConfigMonitor;
+import com.alibaba.otter.canal.deployer.monitor.SpringInstanceConfigMonitor;
+import com.alibaba.otter.canal.instance.core.CanalInstance;
+import com.alibaba.otter.canal.protocol.SecurityUtil;
+import com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;
+import com.google.common.base.Joiner;
+
+/**
+ * 提供canal admin的管理操作
+ * 
+ * @author agapple 2019年8月24日 下午11:39:01
+ * @since 1.1.4
+ */
+public class CanalAdminController implements CanalAdmin {
+
+    private static final Logger logger = LoggerFactory.getLogger(CanalAdminController.class);
+    private String              user;
+    private String              passwd;
+    private CanalStater         canalStater;
+
+    public CanalAdminController(CanalStater canalStater){
+        this.canalStater = canalStater;
+    }
+
+    @Override
+    public boolean check() {
+        return canalStater.isRunning();
+    }
+
+    @Override
+    public synchronized boolean start() {
+        try {
+            if (!canalStater.isRunning()) {
+                canalStater.start();
+                return true;
+            }
+        } catch (Throwable e) {
+            logger.error(e.getMessage(), e);
+        }
+        return false;
+    }
+
+    @Override
+    public synchronized boolean stop() {
+        try {
+            if (canalStater.isRunning()) {
+                canalStater.stop(true);
+                return true;
+            }
+        } catch (Throwable e) {
+            logger.error(e.getMessage(), e);
+        }
+        return false;
+    }
+
+    @Override
+    public synchronized boolean restart() {
+        stop();
+        return start();
+    }
+
+    @Override
+    public boolean auth(String user, String passwd, byte[] seed) {
+        // 如果user/passwd密码为空,则任何用户账户都能登录
+        if ((StringUtils.isEmpty(this.user) || StringUtils.equals(this.user, user))) {
+            if (StringUtils.isEmpty(this.passwd)) {
+                return true;
+            } else if (StringUtils.isEmpty(passwd)) {
+                // 如果server密码有配置,客户端密码为空,则拒绝
+                return false;
+            }
+
+            try {
+                byte[] passForClient = SecurityUtil.hexStr2Bytes(passwd);
+                return SecurityUtil.scrambleServerAuth(passForClient, SecurityUtil.hexStr2Bytes(this.passwd), seed);
+            } catch (NoSuchAlgorithmException e) {
+                return false;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public String getRunningInstances() {
+        try {
+            CanalController controller = canalStater.getController();
+            if (controller != null) {
+                Map<String, InstanceConfig> instanceConfigs = controller.getInstanceConfigs();
+                if (instanceConfigs != null) {
+                    return Joiner.on(",").join(instanceConfigs.keySet());
+                }
+            }
+        } catch (Throwable e) {
+            logger.error(e.getMessage(), e);
+        }
+        return "";
+    }
+
+    @Override
+    public boolean checkInstance(String destination) {
+        Map<String, CanalInstance> instances = CanalServerWithEmbedded.instance().getCanalInstances();
+        if (instances == null || !instances.containsKey(destination)) {
+            return false;
+        } else {
+            CanalInstance instance = instances.get(destination);
+            return instance.isStart();
+        }
+    }
+
+    @Override
+    public boolean startInstance(String destination) {
+        try {
+            InstanceAction instanceAction = getInstanceAction(destination);
+            if (instanceAction != null) {
+                instanceAction.start(destination);
+                return true;
+            }
+        } catch (Throwable e) {
+            logger.error(e.getMessage(), e);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean stopInstance(String destination) {
+        try {
+            InstanceAction instanceAction = getInstanceAction(destination);
+            if (instanceAction != null) {
+                instanceAction.stop(destination);
+                return true;
+            }
+        } catch (Throwable e) {
+            logger.error(e.getMessage(), e);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean restartInstance(String destination) {
+        try {
+            InstanceAction instanceAction = getInstanceAction(destination);
+            if (instanceAction != null) {
+                instanceAction.reload(destination);
+                return true;
+            }
+        } catch (Throwable e) {
+            logger.error(e.getMessage(), e);
+        }
+        return false;
+    }
+
+    @Override
+    public String listCanalLog() {
+        Collection<File> files = org.apache.commons.io.FileUtils.listFiles(new File("../logs/canal/"),
+            TrueFileFilter.TRUE,
+            TrueFileFilter.TRUE);
+        List<String> names = files.stream().map(f -> f.getName()).collect(Collectors.toList());
+        return Joiner.on(",").join(names);
+    }
+
+    @Override
+    public String canalLog(int lines) {
+        return FileUtils.readFileFromOffset("../logs/canal/canal.log", lines, "UTF-8");
+    }
+
+    @Override
+    public String listInstanceLog(String destination) {
+        Collection<File> files = org.apache.commons.io.FileUtils.listFiles(new File("../logs/" + destination + "/"),
+            TrueFileFilter.TRUE,
+            TrueFileFilter.TRUE);
+        List<String> names = files.stream().map(f -> f.getName()).collect(Collectors.toList());
+        return Joiner.on(",").join(names);
+    }
+
+    @Override
+    public String instanceLog(String destination, String fileName, int lines) {
+        if (StringUtils.isEmpty(fileName)) {
+            fileName = destination + ".log";
+        }
+        return FileUtils.readFileFromOffset("../logs/" + destination + "/" + fileName, lines, "UTF-8");
+    }
+
+    private InstanceAction getInstanceAction(String destination) {
+        Map<InstanceConfig.InstanceMode, InstanceConfigMonitor> monitors = canalStater.getController()
+            .getInstanceConfigMonitors();
+        SpringInstanceConfigMonitor monitor = (SpringInstanceConfigMonitor) monitors.get(InstanceConfig.InstanceMode.SPRING);
+        Map<String, InstanceAction> instanceActions = monitor.getActions();
+        return instanceActions.get(destination);
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public void setPasswd(String passwd) {
+        this.passwd = passwd;
+    }
+
+    public void setCanalStater(CanalStater canalStater) {
+        this.canalStater = canalStater;
+    }
+
+}

+ 0 - 79
deployer/src/main/java/com/alibaba/otter/canal/deployer/mbean/CanalServerAgent.java

@@ -1,79 +0,0 @@
-package com.alibaba.otter.canal.deployer.mbean;
-
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.rmi.registry.LocateRegistry;
-
-import javax.management.MBeanServer;
-import javax.management.Notification;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-import javax.management.remote.JMXConnectorServer;
-import javax.management.remote.JMXConnectorServerFactory;
-import javax.management.remote.JMXServiceURL;
-
-/**
- * Canal Server Agent 用于远程JMX调用
- *
- * @author rewerma 2019-07-13 下午05:12:16
- * @version 1.0.0
- */
-public class CanalServerAgent implements NotificationListener {
-
-    private static final Logger         logger      = LoggerFactory.getLogger(CanalServerBean.class);
-
-    private MBeanServer                 mBeanServer = ManagementFactory.getPlatformMBeanServer();
-
-    private String                      ip          = "0.0.0.0";
-
-    private int                         port;
-
-    private CanalServerMXBean           canalServerMbean;
-
-    private volatile JMXConnectorServer cs;
-
-    public CanalServerAgent(String ip, int port, CanalServerMXBean canalServerMbean){
-        if (StringUtils.isNotEmpty(ip)) {
-            this.ip = ip;
-        }
-        this.port = port;
-        this.canalServerMbean = canalServerMbean;
-    }
-
-    @Override
-    public void handleNotification(Notification notification, Object handback) {
-
-    }
-
-    public synchronized void start() {
-        try {
-            if (cs == null) {
-                ObjectName name = new ObjectName("CanalServerAgent:type=CanalServerStatus");
-                mBeanServer.registerMBean(canalServerMbean, name);
-
-                LocateRegistry.createRegistry(port);
-
-                JMXServiceURL jmxServiceURL = new JMXServiceURL(
-                    "service:jmx:rmi:///jndi/rmi://" + ip + ":" + port + "/jmxrmi");
-                cs = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, null, mBeanServer);
-                cs.start();
-            }
-        } catch (Exception e) {
-            logger.error(e.getMessage(), e);
-        }
-    }
-
-    public synchronized void stop() {
-        if (cs != null) {
-            try {
-                cs.stop();
-            } catch (IOException e) {
-                logger.error(e.getMessage(), e);
-            }
-        }
-    }
-}

+ 0 - 156
deployer/src/main/java/com/alibaba/otter/canal/deployer/mbean/CanalServerBean.java

@@ -1,156 +0,0 @@
-package com.alibaba.otter.canal.deployer.mbean;
-
-import com.alibaba.otter.canal.common.utils.FileUtils;
-import com.alibaba.otter.canal.deployer.CanalLauncher;
-import com.alibaba.otter.canal.deployer.CanalStater;
-import com.alibaba.otter.canal.deployer.InstanceConfig;
-import com.alibaba.otter.canal.deployer.monitor.InstanceAction;
-import com.alibaba.otter.canal.deployer.monitor.InstanceConfigMonitor;
-import com.alibaba.otter.canal.deployer.monitor.SpringInstanceConfigMonitor;
-import com.google.common.base.Joiner;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.management.NotificationBroadcasterSupport;
-import java.util.Map;
-
-/**
- * Canal配置信息业务层
- *
- * @author rewerma 2019-07-13 下午05:12:16
- * @version 1.0.0
- */
-public class CanalServerBean extends NotificationBroadcasterSupport implements CanalServerMXBean {
-
-    private static final Logger logger = LoggerFactory.getLogger(CanalServerBean.class);
-
-    private volatile int        status;
-
-    private CanalStater         canalStater;
-
-    public CanalServerBean(CanalStater canalStater){
-        this.canalStater = canalStater;
-        this.status = canalStater.isRunning() ? 1 : 0;
-    }
-
-    @Override
-    public int getStatus() {
-        return status;
-    }
-
-    @Override
-    public synchronized boolean start() {
-        try {
-            if (!canalStater.isRunning()) {
-                canalStater.start();
-                status = 1;
-                return true;
-            }
-        } catch (Throwable e) {
-            logger.error(e.getMessage(), e);
-        }
-        return false;
-    }
-
-    @Override
-    public synchronized boolean stop() {
-        try {
-            if (canalStater.isRunning()) {
-                canalStater.stop();
-                status = 0;
-                return true;
-            }
-        } catch (Throwable e) {
-            logger.error(e.getMessage(), e);
-        }
-        return false;
-    }
-
-    @Override
-    public synchronized boolean restart() {
-        stop();
-        return start();
-    }
-
-    @Override
-    public synchronized boolean exit() {
-        stop();
-        CanalLauncher.runningLatch.countDown();
-        return true;
-    }
-
-    @Override
-    public synchronized boolean startInstance(String destination) {
-        try {
-            InstanceAction instanceAction = getInstanceAction(destination);
-            if (instanceAction != null) {
-                instanceAction.start(destination);
-                return true;
-            }
-        } catch (Throwable e) {
-            logger.error(e.getMessage(), e);
-        }
-        return false;
-    }
-
-    @Override
-    public synchronized boolean stopInstance(String destination) {
-        try {
-            InstanceAction instanceAction = getInstanceAction(destination);
-            if (instanceAction != null) {
-                instanceAction.stop(destination);
-                return true;
-            }
-        } catch (Throwable e) {
-            logger.error(e.getMessage(), e);
-        }
-        return false;
-    }
-
-    @Override
-    public synchronized boolean reloadInstance(String destination) {
-        try {
-            InstanceAction instanceAction = getInstanceAction(destination);
-            if (instanceAction != null) {
-                instanceAction.reload(destination);
-                return true;
-            }
-        } catch (Throwable e) {
-            logger.error(e.getMessage(), e);
-        }
-        return false;
-    }
-
-    @Override
-    public synchronized String getRunningInstances() {
-        try {
-            Map<String, InstanceConfig> instanceConfigs = canalStater.getController().getInstanceConfigs();
-            if (instanceConfigs != null) {
-                return Joiner.on(",").join(instanceConfigs.keySet());
-            }
-        } catch (Throwable e) {
-            logger.error(e.getMessage(), e);
-        }
-        return "";
-    }
-
-    @Override
-    public String canalLog() {
-        return FileUtils.readFileFromOffset("../logs/canal/canal.log", 100, "UTF-8");
-    }
-
-    @Override
-    public String instanceLog(String destination) {
-        return FileUtils.readFileFromOffset("../logs/" + destination + "/" + destination + ".log", 100, "UTF-8");
-    }
-
-    private InstanceAction getInstanceAction(String destination) {
-        Map<InstanceConfig.InstanceMode, InstanceConfigMonitor> monitors = canalStater.getController()
-            .getInstanceConfigMonitors();
-        SpringInstanceConfigMonitor monitor = (SpringInstanceConfigMonitor) monitors
-            .get(InstanceConfig.InstanceMode.SPRING);
-        Map<String, InstanceAction> instanceActions = monitor.getActions();
-        return instanceActions.get(destination);
-    }
-
-}

+ 0 - 90
deployer/src/main/java/com/alibaba/otter/canal/deployer/mbean/CanalServerMXBean.java

@@ -1,90 +0,0 @@
-package com.alibaba.otter.canal.deployer.mbean;
-
-/**
- * Canal Server JMX MBean
- *
- * @author rewerma 2019-07-13 下午05:12:16
- * @version 1.0.0
- */
-public interface CanalServerMXBean {
-
-    /**
-     * 获取Canal Server状态
-     *
-     * @return 状态代码
-     */
-    int getStatus();
-
-    /**
-     * 启动Canal Server
-     *
-     * @return 是否成功
-     */
-    boolean start();
-
-    /**
-     * 停止Canal Server
-     *
-     * @return 是否成功
-     */
-    boolean stop();
-
-    /**
-     * 重启Canal Server
-     *
-     * @return 是否成功
-     */
-    boolean restart();
-
-    /**
-     * 退出Canal Server(关闭进程)
-     *
-     * @return 是否成功
-     */
-    boolean exit();
-
-    /**
-     * 通过实例名启动实例
-     *
-     * @param destination 实例名
-     * @return 是否成功
-     */
-    boolean startInstance(String destination);
-
-    /**
-     * 通过实例名关闭实例
-     *
-     * @param destination 实例名
-     * @return 是否成功
-     */
-    boolean stopInstance(String destination);
-
-    /**
-     * 通过实例名重启实例
-     *
-     * @param destination 实例名
-     * @return 是否成功
-     */
-    boolean reloadInstance(String destination);
-
-    /**
-     * 获取所有当前节点下运行中的实例
-     *
-     * @return 实例信息
-     */
-    String getRunningInstances();
-
-    /**
-     * 获取Canal Server日志(末尾100行)
-     *
-     * @return 日志信息
-     */
-    String canalLog();
-
-    /**
-     * 通过实例名获取实例日志(末尾100行)
-     *
-     * @return 日志信息
-     */
-    String instanceLog(String destination);
-}

+ 10 - 2
deployer/src/main/resources/canal.properties

@@ -11,7 +11,15 @@ canal.ip =
 canal.register.ip =
 canal.port = 11111
 canal.metrics.pull.port = 11112
-canal.admin.jmx.port = 11113
+# canal instance user/passwd
+# canal.user = canal
+# canal.passwd = E3619321C1A937C46A0D8BD1DAC39F93B27D4458
+
+# canal admin config
+canal.admin.port = 11110
+canal.admin.user = admin
+canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441
+
 canal.zkServers =
 # flush data to zk
 canal.zookeeper.flush.period = 1000
@@ -131,4 +139,4 @@ canal.mq.accessChannel = local
 ##################################################
 canal.mq.kafka.kerberos.enable = false
 canal.mq.kafka.kerberos.krb5FilePath = "../conf/kerberos/krb5.conf"
-canal.mq.kafka.kerberos.jaasFilePath = "../conf/kerberos/jaas.conf"
+canal.mq.kafka.kerberos.jaasFilePath = "../conf/kerberos/jaas.conf"

+ 1 - 2
driver/src/test/java/com/alibaba/otter/canal/parse/driver/mysql/MysqlConnectorTest.java

@@ -4,11 +4,10 @@ import java.io.IOException;
 import java.net.InetSocketAddress;
 
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import com.alibaba.otter.canal.parse.driver.mysql.packets.server.ResultSetPacket;
-@Ignore
+
 public class MysqlConnectorTest {
 
     @Test

+ 5 - 0
example/src/main/java/com/alibaba/otter/canal/example/AbstractCanalClientTest.java

@@ -79,6 +79,11 @@ public class AbstractCanalClientTest extends BaseCanalClientTest {
                 }
             } catch (Exception e) {
                 logger.error("process error!", e);
+                try {
+                    Thread.sleep(1000L);
+                } catch (InterruptedException e1) {
+                    // ignore
+                }
             } finally {
                 connector.disconnect();
                 MDC.remove("destination");

+ 6 - 0
protocol/pom.xml

@@ -26,5 +26,11 @@
 			<groupId>commons-lang</groupId>
 			<artifactId>commons-lang</artifactId>
 		</dependency>
+		<!-- junit -->
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
 	</dependencies>
 </project>

+ 6253 - 0
protocol/src/main/java/com/alibaba/otter/canal/protocol/AdminPacket.java

@@ -0,0 +1,6253 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: AdminProtocol.proto
+
+package com.alibaba.otter.canal.protocol;
+
+public final class AdminPacket {
+  private AdminPacket() {}
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistryLite registry) {
+  }
+
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistry registry) {
+    registerAllExtensions(
+        (com.google.protobuf.ExtensionRegistryLite) registry);
+  }
+  /**
+   * Protobuf enum {@code com.alibaba.otter.canal.protocol.PacketType}
+   */
+  public enum PacketType
+      implements com.google.protobuf.ProtocolMessageEnum {
+    /**
+     * <pre>
+     *compatible
+     * </pre>
+     *
+     * <code>PACKAGETYPECOMPATIBLEPROTO2 = 0;</code>
+     */
+    PACKAGETYPECOMPATIBLEPROTO2(0),
+    /**
+     * <code>HANDSHAKE = 1;</code>
+     */
+    HANDSHAKE(1),
+    /**
+     * <code>CLIENTAUTHENTICATION = 2;</code>
+     */
+    CLIENTAUTHENTICATION(2),
+    /**
+     * <code>ACK = 3;</code>
+     */
+    ACK(3),
+    /**
+     * <code>SERVER = 4;</code>
+     */
+    SERVER(4),
+    /**
+     * <code>INSTANCE = 5;</code>
+     */
+    INSTANCE(5),
+    /**
+     * <code>LOG = 6;</code>
+     */
+    LOG(6),
+    UNRECOGNIZED(-1),
+    ;
+
+    /**
+     * <pre>
+     *compatible
+     * </pre>
+     *
+     * <code>PACKAGETYPECOMPATIBLEPROTO2 = 0;</code>
+     */
+    public static final int PACKAGETYPECOMPATIBLEPROTO2_VALUE = 0;
+    /**
+     * <code>HANDSHAKE = 1;</code>
+     */
+    public static final int HANDSHAKE_VALUE = 1;
+    /**
+     * <code>CLIENTAUTHENTICATION = 2;</code>
+     */
+    public static final int CLIENTAUTHENTICATION_VALUE = 2;
+    /**
+     * <code>ACK = 3;</code>
+     */
+    public static final int ACK_VALUE = 3;
+    /**
+     * <code>SERVER = 4;</code>
+     */
+    public static final int SERVER_VALUE = 4;
+    /**
+     * <code>INSTANCE = 5;</code>
+     */
+    public static final int INSTANCE_VALUE = 5;
+    /**
+     * <code>LOG = 6;</code>
+     */
+    public static final int LOG_VALUE = 6;
+
+
+    public final int getNumber() {
+      if (this == UNRECOGNIZED) {
+        throw new java.lang.IllegalArgumentException(
+            "Can't get the number of an unknown enum value.");
+      }
+      return value;
+    }
+
+    /**
+     * @deprecated Use {@link #forNumber(int)} instead.
+     */
+    @java.lang.Deprecated
+    public static PacketType valueOf(int value) {
+      return forNumber(value);
+    }
+
+    public static PacketType forNumber(int value) {
+      switch (value) {
+        case 0: return PACKAGETYPECOMPATIBLEPROTO2;
+        case 1: return HANDSHAKE;
+        case 2: return CLIENTAUTHENTICATION;
+        case 3: return ACK;
+        case 4: return SERVER;
+        case 5: return INSTANCE;
+        case 6: return LOG;
+        default: return null;
+      }
+    }
+
+    public static com.google.protobuf.Internal.EnumLiteMap<PacketType>
+        internalGetValueMap() {
+      return internalValueMap;
+    }
+    private static final com.google.protobuf.Internal.EnumLiteMap<
+        PacketType> internalValueMap =
+          new com.google.protobuf.Internal.EnumLiteMap<PacketType>() {
+            public PacketType findValueByNumber(int number) {
+              return PacketType.forNumber(number);
+            }
+          };
+
+    public final com.google.protobuf.Descriptors.EnumValueDescriptor
+        getValueDescriptor() {
+      return getDescriptor().getValues().get(ordinal());
+    }
+    public final com.google.protobuf.Descriptors.EnumDescriptor
+        getDescriptorForType() {
+      return getDescriptor();
+    }
+    public static final com.google.protobuf.Descriptors.EnumDescriptor
+        getDescriptor() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.getDescriptor().getEnumTypes().get(0);
+    }
+
+    private static final PacketType[] VALUES = values();
+
+    public static PacketType valueOf(
+        com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
+      if (desc.getType() != getDescriptor()) {
+        throw new java.lang.IllegalArgumentException(
+          "EnumValueDescriptor is not for this type.");
+      }
+      if (desc.getIndex() == -1) {
+        return UNRECOGNIZED;
+      }
+      return VALUES[desc.getIndex()];
+    }
+
+    private final int value;
+
+    private PacketType(int value) {
+      this.value = value;
+    }
+
+    // @@protoc_insertion_point(enum_scope:com.alibaba.otter.canal.protocol.PacketType)
+  }
+
+  public interface PacketOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Packet)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>int32 magic_number = 1;</code>
+     */
+    int getMagicNumber();
+
+    /**
+     * <code>int32 version = 2;</code>
+     */
+    int getVersion();
+
+    /**
+     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>
+     */
+    int getTypeValue();
+    /**
+     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>
+     */
+    com.alibaba.otter.canal.protocol.AdminPacket.PacketType getType();
+
+    /**
+     * <code>bytes body = 4;</code>
+     */
+    com.google.protobuf.ByteString getBody();
+
+    public com.alibaba.otter.canal.protocol.AdminPacket.Packet.MagicNumberPresentCase getMagicNumberPresentCase();
+
+    public com.alibaba.otter.canal.protocol.AdminPacket.Packet.VersionPresentCase getVersionPresentCase();
+  }
+  /**
+   * Protobuf type {@code com.alibaba.otter.canal.protocol.Packet}
+   */
+  public  static final class Packet extends
+      com.google.protobuf.GeneratedMessageV3 implements
+      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Packet)
+      PacketOrBuilder {
+  private static final long serialVersionUID = 0L;
+    // Use Packet.newBuilder() to construct.
+    private Packet(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+      super(builder);
+    }
+    private Packet() {
+      type_ = 0;
+      body_ = com.google.protobuf.ByteString.EMPTY;
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private Packet(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      this();
+      if (extensionRegistry == null) {
+        throw new java.lang.NullPointerException();
+      }
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            case 8: {
+              magicNumberPresentCase_ = 1;
+              magicNumberPresent_ = input.readInt32();
+              break;
+            }
+            case 16: {
+              versionPresentCase_ = 2;
+              versionPresent_ = input.readInt32();
+              break;
+            }
+            case 24: {
+              int rawValue = input.readEnum();
+
+              type_ = rawValue;
+              break;
+            }
+            case 34: {
+
+              body_ = input.readBytes();
+              break;
+            }
+            default: {
+              if (!parseUnknownFieldProto3(
+                  input, unknownFields, extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.alibaba.otter.canal.protocol.AdminPacket.Packet.class, com.alibaba.otter.canal.protocol.AdminPacket.Packet.Builder.class);
+    }
+
+    private int magicNumberPresentCase_ = 0;
+    private java.lang.Object magicNumberPresent_;
+    public enum MagicNumberPresentCase
+        implements com.google.protobuf.Internal.EnumLite {
+      MAGIC_NUMBER(1),
+      MAGICNUMBERPRESENT_NOT_SET(0);
+      private final int value;
+      private MagicNumberPresentCase(int value) {
+        this.value = value;
+      }
+      /**
+       * @deprecated Use {@link #forNumber(int)} instead.
+       */
+      @java.lang.Deprecated
+      public static MagicNumberPresentCase valueOf(int value) {
+        return forNumber(value);
+      }
+
+      public static MagicNumberPresentCase forNumber(int value) {
+        switch (value) {
+          case 1: return MAGIC_NUMBER;
+          case 0: return MAGICNUMBERPRESENT_NOT_SET;
+          default: return null;
+        }
+      }
+      public int getNumber() {
+        return this.value;
+      }
+    };
+
+    public MagicNumberPresentCase
+    getMagicNumberPresentCase() {
+      return MagicNumberPresentCase.forNumber(
+          magicNumberPresentCase_);
+    }
+
+    private int versionPresentCase_ = 0;
+    private java.lang.Object versionPresent_;
+    public enum VersionPresentCase
+        implements com.google.protobuf.Internal.EnumLite {
+      VERSION(2),
+      VERSIONPRESENT_NOT_SET(0);
+      private final int value;
+      private VersionPresentCase(int value) {
+        this.value = value;
+      }
+      /**
+       * @deprecated Use {@link #forNumber(int)} instead.
+       */
+      @java.lang.Deprecated
+      public static VersionPresentCase valueOf(int value) {
+        return forNumber(value);
+      }
+
+      public static VersionPresentCase forNumber(int value) {
+        switch (value) {
+          case 2: return VERSION;
+          case 0: return VERSIONPRESENT_NOT_SET;
+          default: return null;
+        }
+      }
+      public int getNumber() {
+        return this.value;
+      }
+    };
+
+    public VersionPresentCase
+    getVersionPresentCase() {
+      return VersionPresentCase.forNumber(
+          versionPresentCase_);
+    }
+
+    public static final int MAGIC_NUMBER_FIELD_NUMBER = 1;
+    /**
+     * <code>int32 magic_number = 1;</code>
+     */
+    public int getMagicNumber() {
+      if (magicNumberPresentCase_ == 1) {
+        return (java.lang.Integer) magicNumberPresent_;
+      }
+      return 0;
+    }
+
+    public static final int VERSION_FIELD_NUMBER = 2;
+    /**
+     * <code>int32 version = 2;</code>
+     */
+    public int getVersion() {
+      if (versionPresentCase_ == 2) {
+        return (java.lang.Integer) versionPresent_;
+      }
+      return 0;
+    }
+
+    public static final int TYPE_FIELD_NUMBER = 3;
+    private int type_;
+    /**
+     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>
+     */
+    public int getTypeValue() {
+      return type_;
+    }
+    /**
+     * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>
+     */
+    public com.alibaba.otter.canal.protocol.AdminPacket.PacketType getType() {
+      @SuppressWarnings("deprecation")
+      com.alibaba.otter.canal.protocol.AdminPacket.PacketType result = com.alibaba.otter.canal.protocol.AdminPacket.PacketType.valueOf(type_);
+      return result == null ? com.alibaba.otter.canal.protocol.AdminPacket.PacketType.UNRECOGNIZED : result;
+    }
+
+    public static final int BODY_FIELD_NUMBER = 4;
+    private com.google.protobuf.ByteString body_;
+    /**
+     * <code>bytes body = 4;</code>
+     */
+    public com.google.protobuf.ByteString getBody() {
+      return body_;
+    }
+
+    private byte memoizedIsInitialized = -1;
+    @java.lang.Override
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    @java.lang.Override
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      if (magicNumberPresentCase_ == 1) {
+        output.writeInt32(
+            1, (int)((java.lang.Integer) magicNumberPresent_));
+      }
+      if (versionPresentCase_ == 2) {
+        output.writeInt32(
+            2, (int)((java.lang.Integer) versionPresent_));
+      }
+      if (type_ != com.alibaba.otter.canal.protocol.AdminPacket.PacketType.PACKAGETYPECOMPATIBLEPROTO2.getNumber()) {
+        output.writeEnum(3, type_);
+      }
+      if (!body_.isEmpty()) {
+        output.writeBytes(4, body_);
+      }
+      unknownFields.writeTo(output);
+    }
+
+    @java.lang.Override
+    public int getSerializedSize() {
+      int size = memoizedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (magicNumberPresentCase_ == 1) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(
+              1, (int)((java.lang.Integer) magicNumberPresent_));
+      }
+      if (versionPresentCase_ == 2) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(
+              2, (int)((java.lang.Integer) versionPresent_));
+      }
+      if (type_ != com.alibaba.otter.canal.protocol.AdminPacket.PacketType.PACKAGETYPECOMPATIBLEPROTO2.getNumber()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeEnumSize(3, type_);
+      }
+      if (!body_.isEmpty()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(4, body_);
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSize = size;
+      return size;
+    }
+
+    @java.lang.Override
+    public boolean equals(final java.lang.Object obj) {
+      if (obj == this) {
+       return true;
+      }
+      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.Packet)) {
+        return super.equals(obj);
+      }
+      com.alibaba.otter.canal.protocol.AdminPacket.Packet other = (com.alibaba.otter.canal.protocol.AdminPacket.Packet) obj;
+
+      boolean result = true;
+      result = result && type_ == other.type_;
+      result = result && getBody()
+          .equals(other.getBody());
+      result = result && getMagicNumberPresentCase().equals(
+          other.getMagicNumberPresentCase());
+      if (!result) return false;
+      switch (magicNumberPresentCase_) {
+        case 1:
+          result = result && (getMagicNumber()
+              == other.getMagicNumber());
+          break;
+        case 0:
+        default:
+      }
+      result = result && getVersionPresentCase().equals(
+          other.getVersionPresentCase());
+      if (!result) return false;
+      switch (versionPresentCase_) {
+        case 2:
+          result = result && (getVersion()
+              == other.getVersion());
+          break;
+        case 0:
+        default:
+      }
+      result = result && unknownFields.equals(other.unknownFields);
+      return result;
+    }
+
+    @java.lang.Override
+    public int hashCode() {
+      if (memoizedHashCode != 0) {
+        return memoizedHashCode;
+      }
+      int hash = 41;
+      hash = (19 * hash) + getDescriptor().hashCode();
+      hash = (37 * hash) + TYPE_FIELD_NUMBER;
+      hash = (53 * hash) + type_;
+      hash = (37 * hash) + BODY_FIELD_NUMBER;
+      hash = (53 * hash) + getBody().hashCode();
+      switch (magicNumberPresentCase_) {
+        case 1:
+          hash = (37 * hash) + MAGIC_NUMBER_FIELD_NUMBER;
+          hash = (53 * hash) + getMagicNumber();
+          break;
+        case 0:
+        default:
+      }
+      switch (versionPresentCase_) {
+        case 2:
+          hash = (37 * hash) + VERSION_FIELD_NUMBER;
+          hash = (53 * hash) + getVersion();
+          break;
+        case 0:
+        default:
+      }
+      hash = (29 * hash) + unknownFields.hashCode();
+      memoizedHashCode = hash;
+      return hash;
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(
+        java.nio.ByteBuffer data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(
+        java.nio.ByteBuffer data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+
+    @java.lang.Override
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.Packet prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    @java.lang.Override
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code com.alibaba.otter.canal.protocol.Packet}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Packet)
+        com.alibaba.otter.canal.protocol.AdminPacket.PacketOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;
+      }
+
+      @java.lang.Override
+      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                com.alibaba.otter.canal.protocol.AdminPacket.Packet.class, com.alibaba.otter.canal.protocol.AdminPacket.Packet.Builder.class);
+      }
+
+      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.Packet.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessageV3
+                .alwaysUseFieldBuilders) {
+        }
+      }
+      @java.lang.Override
+      public Builder clear() {
+        super.clear();
+        type_ = 0;
+
+        body_ = com.google.protobuf.ByteString.EMPTY;
+
+        magicNumberPresentCase_ = 0;
+        magicNumberPresent_ = null;
+        versionPresentCase_ = 0;
+        versionPresent_ = null;
+        return this;
+      }
+
+      @java.lang.Override
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.Packet getDefaultInstanceForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.Packet.getDefaultInstance();
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.Packet build() {
+        com.alibaba.otter.canal.protocol.AdminPacket.Packet result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.Packet buildPartial() {
+        com.alibaba.otter.canal.protocol.AdminPacket.Packet result = new com.alibaba.otter.canal.protocol.AdminPacket.Packet(this);
+        if (magicNumberPresentCase_ == 1) {
+          result.magicNumberPresent_ = magicNumberPresent_;
+        }
+        if (versionPresentCase_ == 2) {
+          result.versionPresent_ = versionPresent_;
+        }
+        result.type_ = type_;
+        result.body_ = body_;
+        result.magicNumberPresentCase_ = magicNumberPresentCase_;
+        result.versionPresentCase_ = versionPresentCase_;
+        onBuilt();
+        return result;
+      }
+
+      @java.lang.Override
+      public Builder clone() {
+        return (Builder) super.clone();
+      }
+      @java.lang.Override
+      public Builder setField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.setField(field, value);
+      }
+      @java.lang.Override
+      public Builder clearField(
+          com.google.protobuf.Descriptors.FieldDescriptor field) {
+        return (Builder) super.clearField(field);
+      }
+      @java.lang.Override
+      public Builder clearOneof(
+          com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+        return (Builder) super.clearOneof(oneof);
+      }
+      @java.lang.Override
+      public Builder setRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          int index, java.lang.Object value) {
+        return (Builder) super.setRepeatedField(field, index, value);
+      }
+      @java.lang.Override
+      public Builder addRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.addRepeatedField(field, value);
+      }
+      @java.lang.Override
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.Packet) {
+          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.Packet)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.Packet other) {
+        if (other == com.alibaba.otter.canal.protocol.AdminPacket.Packet.getDefaultInstance()) return this;
+        if (other.type_ != 0) {
+          setTypeValue(other.getTypeValue());
+        }
+        if (other.getBody() != com.google.protobuf.ByteString.EMPTY) {
+          setBody(other.getBody());
+        }
+        switch (other.getMagicNumberPresentCase()) {
+          case MAGIC_NUMBER: {
+            setMagicNumber(other.getMagicNumber());
+            break;
+          }
+          case MAGICNUMBERPRESENT_NOT_SET: {
+            break;
+          }
+        }
+        switch (other.getVersionPresentCase()) {
+          case VERSION: {
+            setVersion(other.getVersion());
+            break;
+          }
+          case VERSIONPRESENT_NOT_SET: {
+            break;
+          }
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      @java.lang.Override
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      @java.lang.Override
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        com.alibaba.otter.canal.protocol.AdminPacket.Packet parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.Packet) e.getUnfinishedMessage();
+          throw e.unwrapIOException();
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int magicNumberPresentCase_ = 0;
+      private java.lang.Object magicNumberPresent_;
+      public MagicNumberPresentCase
+          getMagicNumberPresentCase() {
+        return MagicNumberPresentCase.forNumber(
+            magicNumberPresentCase_);
+      }
+
+      public Builder clearMagicNumberPresent() {
+        magicNumberPresentCase_ = 0;
+        magicNumberPresent_ = null;
+        onChanged();
+        return this;
+      }
+
+      private int versionPresentCase_ = 0;
+      private java.lang.Object versionPresent_;
+      public VersionPresentCase
+          getVersionPresentCase() {
+        return VersionPresentCase.forNumber(
+            versionPresentCase_);
+      }
+
+      public Builder clearVersionPresent() {
+        versionPresentCase_ = 0;
+        versionPresent_ = null;
+        onChanged();
+        return this;
+      }
+
+
+      /**
+       * <code>int32 magic_number = 1;</code>
+       */
+      public int getMagicNumber() {
+        if (magicNumberPresentCase_ == 1) {
+          return (java.lang.Integer) magicNumberPresent_;
+        }
+        return 0;
+      }
+      /**
+       * <code>int32 magic_number = 1;</code>
+       */
+      public Builder setMagicNumber(int value) {
+        magicNumberPresentCase_ = 1;
+        magicNumberPresent_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>int32 magic_number = 1;</code>
+       */
+      public Builder clearMagicNumber() {
+        if (magicNumberPresentCase_ == 1) {
+          magicNumberPresentCase_ = 0;
+          magicNumberPresent_ = null;
+          onChanged();
+        }
+        return this;
+      }
+
+      /**
+       * <code>int32 version = 2;</code>
+       */
+      public int getVersion() {
+        if (versionPresentCase_ == 2) {
+          return (java.lang.Integer) versionPresent_;
+        }
+        return 0;
+      }
+      /**
+       * <code>int32 version = 2;</code>
+       */
+      public Builder setVersion(int value) {
+        versionPresentCase_ = 2;
+        versionPresent_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>int32 version = 2;</code>
+       */
+      public Builder clearVersion() {
+        if (versionPresentCase_ == 2) {
+          versionPresentCase_ = 0;
+          versionPresent_ = null;
+          onChanged();
+        }
+        return this;
+      }
+
+      private int type_ = 0;
+      /**
+       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>
+       */
+      public int getTypeValue() {
+        return type_;
+      }
+      /**
+       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>
+       */
+      public Builder setTypeValue(int value) {
+        type_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>
+       */
+      public com.alibaba.otter.canal.protocol.AdminPacket.PacketType getType() {
+        @SuppressWarnings("deprecation")
+        com.alibaba.otter.canal.protocol.AdminPacket.PacketType result = com.alibaba.otter.canal.protocol.AdminPacket.PacketType.valueOf(type_);
+        return result == null ? com.alibaba.otter.canal.protocol.AdminPacket.PacketType.UNRECOGNIZED : result;
+      }
+      /**
+       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>
+       */
+      public Builder setType(com.alibaba.otter.canal.protocol.AdminPacket.PacketType value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        
+        type_ = value.getNumber();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>.com.alibaba.otter.canal.protocol.PacketType type = 3;</code>
+       */
+      public Builder clearType() {
+        
+        type_ = 0;
+        onChanged();
+        return this;
+      }
+
+      private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY;
+      /**
+       * <code>bytes body = 4;</code>
+       */
+      public com.google.protobuf.ByteString getBody() {
+        return body_;
+      }
+      /**
+       * <code>bytes body = 4;</code>
+       */
+      public Builder setBody(com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        body_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>bytes body = 4;</code>
+       */
+      public Builder clearBody() {
+        
+        body_ = getDefaultInstance().getBody();
+        onChanged();
+        return this;
+      }
+      @java.lang.Override
+      public final Builder setUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.setUnknownFieldsProto3(unknownFields);
+      }
+
+      @java.lang.Override
+      public final Builder mergeUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.mergeUnknownFields(unknownFields);
+      }
+
+
+      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Packet)
+    }
+
+    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Packet)
+    private static final com.alibaba.otter.canal.protocol.AdminPacket.Packet DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.Packet();
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Packet getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    private static final com.google.protobuf.Parser<Packet>
+        PARSER = new com.google.protobuf.AbstractParser<Packet>() {
+      @java.lang.Override
+      public Packet parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new Packet(input, extensionRegistry);
+      }
+    };
+
+    public static com.google.protobuf.Parser<Packet> parser() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<Packet> getParserForType() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.alibaba.otter.canal.protocol.AdminPacket.Packet getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  public interface AckOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Ack)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>int32 code = 1;</code>
+     */
+    int getCode();
+
+    /**
+     * <pre>
+     * if something like compression is not supported, erorr_message will tell about it.
+     * </pre>
+     *
+     * <code>string message = 2;</code>
+     */
+    java.lang.String getMessage();
+    /**
+     * <pre>
+     * if something like compression is not supported, erorr_message will tell about it.
+     * </pre>
+     *
+     * <code>string message = 2;</code>
+     */
+    com.google.protobuf.ByteString
+        getMessageBytes();
+
+    public com.alibaba.otter.canal.protocol.AdminPacket.Ack.ErrorCodePresentCase getErrorCodePresentCase();
+  }
+  /**
+   * Protobuf type {@code com.alibaba.otter.canal.protocol.Ack}
+   */
+  public  static final class Ack extends
+      com.google.protobuf.GeneratedMessageV3 implements
+      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Ack)
+      AckOrBuilder {
+  private static final long serialVersionUID = 0L;
+    // Use Ack.newBuilder() to construct.
+    private Ack(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+      super(builder);
+    }
+    private Ack() {
+      message_ = "";
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private Ack(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      this();
+      if (extensionRegistry == null) {
+        throw new java.lang.NullPointerException();
+      }
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            case 8: {
+              errorCodePresentCase_ = 1;
+              errorCodePresent_ = input.readInt32();
+              break;
+            }
+            case 18: {
+              java.lang.String s = input.readStringRequireUtf8();
+
+              message_ = s;
+              break;
+            }
+            default: {
+              if (!parseUnknownFieldProto3(
+                  input, unknownFields, extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.alibaba.otter.canal.protocol.AdminPacket.Ack.class, com.alibaba.otter.canal.protocol.AdminPacket.Ack.Builder.class);
+    }
+
+    private int errorCodePresentCase_ = 0;
+    private java.lang.Object errorCodePresent_;
+    public enum ErrorCodePresentCase
+        implements com.google.protobuf.Internal.EnumLite {
+      CODE(1),
+      ERRORCODEPRESENT_NOT_SET(0);
+      private final int value;
+      private ErrorCodePresentCase(int value) {
+        this.value = value;
+      }
+      /**
+       * @deprecated Use {@link #forNumber(int)} instead.
+       */
+      @java.lang.Deprecated
+      public static ErrorCodePresentCase valueOf(int value) {
+        return forNumber(value);
+      }
+
+      public static ErrorCodePresentCase forNumber(int value) {
+        switch (value) {
+          case 1: return CODE;
+          case 0: return ERRORCODEPRESENT_NOT_SET;
+          default: return null;
+        }
+      }
+      public int getNumber() {
+        return this.value;
+      }
+    };
+
+    public ErrorCodePresentCase
+    getErrorCodePresentCase() {
+      return ErrorCodePresentCase.forNumber(
+          errorCodePresentCase_);
+    }
+
+    public static final int CODE_FIELD_NUMBER = 1;
+    /**
+     * <code>int32 code = 1;</code>
+     */
+    public int getCode() {
+      if (errorCodePresentCase_ == 1) {
+        return (java.lang.Integer) errorCodePresent_;
+      }
+      return 0;
+    }
+
+    public static final int MESSAGE_FIELD_NUMBER = 2;
+    private volatile java.lang.Object message_;
+    /**
+     * <pre>
+     * if something like compression is not supported, erorr_message will tell about it.
+     * </pre>
+     *
+     * <code>string message = 2;</code>
+     */
+    public java.lang.String getMessage() {
+      java.lang.Object ref = message_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        message_ = s;
+        return s;
+      }
+    }
+    /**
+     * <pre>
+     * if something like compression is not supported, erorr_message will tell about it.
+     * </pre>
+     *
+     * <code>string message = 2;</code>
+     */
+    public com.google.protobuf.ByteString
+        getMessageBytes() {
+      java.lang.Object ref = message_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        message_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    private byte memoizedIsInitialized = -1;
+    @java.lang.Override
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    @java.lang.Override
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      if (errorCodePresentCase_ == 1) {
+        output.writeInt32(
+            1, (int)((java.lang.Integer) errorCodePresent_));
+      }
+      if (!getMessageBytes().isEmpty()) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, message_);
+      }
+      unknownFields.writeTo(output);
+    }
+
+    @java.lang.Override
+    public int getSerializedSize() {
+      int size = memoizedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (errorCodePresentCase_ == 1) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(
+              1, (int)((java.lang.Integer) errorCodePresent_));
+      }
+      if (!getMessageBytes().isEmpty()) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, message_);
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSize = size;
+      return size;
+    }
+
+    @java.lang.Override
+    public boolean equals(final java.lang.Object obj) {
+      if (obj == this) {
+       return true;
+      }
+      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.Ack)) {
+        return super.equals(obj);
+      }
+      com.alibaba.otter.canal.protocol.AdminPacket.Ack other = (com.alibaba.otter.canal.protocol.AdminPacket.Ack) obj;
+
+      boolean result = true;
+      result = result && getMessage()
+          .equals(other.getMessage());
+      result = result && getErrorCodePresentCase().equals(
+          other.getErrorCodePresentCase());
+      if (!result) return false;
+      switch (errorCodePresentCase_) {
+        case 1:
+          result = result && (getCode()
+              == other.getCode());
+          break;
+        case 0:
+        default:
+      }
+      result = result && unknownFields.equals(other.unknownFields);
+      return result;
+    }
+
+    @java.lang.Override
+    public int hashCode() {
+      if (memoizedHashCode != 0) {
+        return memoizedHashCode;
+      }
+      int hash = 41;
+      hash = (19 * hash) + getDescriptor().hashCode();
+      hash = (37 * hash) + MESSAGE_FIELD_NUMBER;
+      hash = (53 * hash) + getMessage().hashCode();
+      switch (errorCodePresentCase_) {
+        case 1:
+          hash = (37 * hash) + CODE_FIELD_NUMBER;
+          hash = (53 * hash) + getCode();
+          break;
+        case 0:
+        default:
+      }
+      hash = (29 * hash) + unknownFields.hashCode();
+      memoizedHashCode = hash;
+      return hash;
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(
+        java.nio.ByteBuffer data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(
+        java.nio.ByteBuffer data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+
+    @java.lang.Override
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.Ack prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    @java.lang.Override
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code com.alibaba.otter.canal.protocol.Ack}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Ack)
+        com.alibaba.otter.canal.protocol.AdminPacket.AckOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;
+      }
+
+      @java.lang.Override
+      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                com.alibaba.otter.canal.protocol.AdminPacket.Ack.class, com.alibaba.otter.canal.protocol.AdminPacket.Ack.Builder.class);
+      }
+
+      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.Ack.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessageV3
+                .alwaysUseFieldBuilders) {
+        }
+      }
+      @java.lang.Override
+      public Builder clear() {
+        super.clear();
+        message_ = "";
+
+        errorCodePresentCase_ = 0;
+        errorCodePresent_ = null;
+        return this;
+      }
+
+      @java.lang.Override
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.Ack getDefaultInstanceForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.Ack.getDefaultInstance();
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.Ack build() {
+        com.alibaba.otter.canal.protocol.AdminPacket.Ack result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.Ack buildPartial() {
+        com.alibaba.otter.canal.protocol.AdminPacket.Ack result = new com.alibaba.otter.canal.protocol.AdminPacket.Ack(this);
+        if (errorCodePresentCase_ == 1) {
+          result.errorCodePresent_ = errorCodePresent_;
+        }
+        result.message_ = message_;
+        result.errorCodePresentCase_ = errorCodePresentCase_;
+        onBuilt();
+        return result;
+      }
+
+      @java.lang.Override
+      public Builder clone() {
+        return (Builder) super.clone();
+      }
+      @java.lang.Override
+      public Builder setField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.setField(field, value);
+      }
+      @java.lang.Override
+      public Builder clearField(
+          com.google.protobuf.Descriptors.FieldDescriptor field) {
+        return (Builder) super.clearField(field);
+      }
+      @java.lang.Override
+      public Builder clearOneof(
+          com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+        return (Builder) super.clearOneof(oneof);
+      }
+      @java.lang.Override
+      public Builder setRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          int index, java.lang.Object value) {
+        return (Builder) super.setRepeatedField(field, index, value);
+      }
+      @java.lang.Override
+      public Builder addRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.addRepeatedField(field, value);
+      }
+      @java.lang.Override
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.Ack) {
+          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.Ack)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.Ack other) {
+        if (other == com.alibaba.otter.canal.protocol.AdminPacket.Ack.getDefaultInstance()) return this;
+        if (!other.getMessage().isEmpty()) {
+          message_ = other.message_;
+          onChanged();
+        }
+        switch (other.getErrorCodePresentCase()) {
+          case CODE: {
+            setCode(other.getCode());
+            break;
+          }
+          case ERRORCODEPRESENT_NOT_SET: {
+            break;
+          }
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      @java.lang.Override
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      @java.lang.Override
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        com.alibaba.otter.canal.protocol.AdminPacket.Ack parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.Ack) e.getUnfinishedMessage();
+          throw e.unwrapIOException();
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int errorCodePresentCase_ = 0;
+      private java.lang.Object errorCodePresent_;
+      public ErrorCodePresentCase
+          getErrorCodePresentCase() {
+        return ErrorCodePresentCase.forNumber(
+            errorCodePresentCase_);
+      }
+
+      public Builder clearErrorCodePresent() {
+        errorCodePresentCase_ = 0;
+        errorCodePresent_ = null;
+        onChanged();
+        return this;
+      }
+
+
+      /**
+       * <code>int32 code = 1;</code>
+       */
+      public int getCode() {
+        if (errorCodePresentCase_ == 1) {
+          return (java.lang.Integer) errorCodePresent_;
+        }
+        return 0;
+      }
+      /**
+       * <code>int32 code = 1;</code>
+       */
+      public Builder setCode(int value) {
+        errorCodePresentCase_ = 1;
+        errorCodePresent_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>int32 code = 1;</code>
+       */
+      public Builder clearCode() {
+        if (errorCodePresentCase_ == 1) {
+          errorCodePresentCase_ = 0;
+          errorCodePresent_ = null;
+          onChanged();
+        }
+        return this;
+      }
+
+      private java.lang.Object message_ = "";
+      /**
+       * <pre>
+       * if something like compression is not supported, erorr_message will tell about it.
+       * </pre>
+       *
+       * <code>string message = 2;</code>
+       */
+      public java.lang.String getMessage() {
+        java.lang.Object ref = message_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          message_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <pre>
+       * if something like compression is not supported, erorr_message will tell about it.
+       * </pre>
+       *
+       * <code>string message = 2;</code>
+       */
+      public com.google.protobuf.ByteString
+          getMessageBytes() {
+        java.lang.Object ref = message_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          message_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <pre>
+       * if something like compression is not supported, erorr_message will tell about it.
+       * </pre>
+       *
+       * <code>string message = 2;</code>
+       */
+      public Builder setMessage(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        message_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * if something like compression is not supported, erorr_message will tell about it.
+       * </pre>
+       *
+       * <code>string message = 2;</code>
+       */
+      public Builder clearMessage() {
+        
+        message_ = getDefaultInstance().getMessage();
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * if something like compression is not supported, erorr_message will tell about it.
+       * </pre>
+       *
+       * <code>string message = 2;</code>
+       */
+      public Builder setMessageBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+        
+        message_ = value;
+        onChanged();
+        return this;
+      }
+      @java.lang.Override
+      public final Builder setUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.setUnknownFieldsProto3(unknownFields);
+      }
+
+      @java.lang.Override
+      public final Builder mergeUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.mergeUnknownFields(unknownFields);
+      }
+
+
+      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Ack)
+    }
+
+    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Ack)
+    private static final com.alibaba.otter.canal.protocol.AdminPacket.Ack DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.Ack();
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Ack getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    private static final com.google.protobuf.Parser<Ack>
+        PARSER = new com.google.protobuf.AbstractParser<Ack>() {
+      @java.lang.Override
+      public Ack parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new Ack(input, extensionRegistry);
+      }
+    };
+
+    public static com.google.protobuf.Parser<Ack> parser() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<Ack> getParserForType() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.alibaba.otter.canal.protocol.AdminPacket.Ack getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  public interface HandshakeOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.Handshake)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>string communication_encoding = 1;</code>
+     */
+    java.lang.String getCommunicationEncoding();
+    /**
+     * <code>string communication_encoding = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getCommunicationEncodingBytes();
+
+    /**
+     * <code>bytes seeds = 2;</code>
+     */
+    com.google.protobuf.ByteString getSeeds();
+
+    public com.alibaba.otter.canal.protocol.AdminPacket.Handshake.CommunicationEncodingPresentCase getCommunicationEncodingPresentCase();
+  }
+  /**
+   * Protobuf type {@code com.alibaba.otter.canal.protocol.Handshake}
+   */
+  public  static final class Handshake extends
+      com.google.protobuf.GeneratedMessageV3 implements
+      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.Handshake)
+      HandshakeOrBuilder {
+  private static final long serialVersionUID = 0L;
+    // Use Handshake.newBuilder() to construct.
+    private Handshake(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+      super(builder);
+    }
+    private Handshake() {
+      seeds_ = com.google.protobuf.ByteString.EMPTY;
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private Handshake(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      this();
+      if (extensionRegistry == null) {
+        throw new java.lang.NullPointerException();
+      }
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            case 10: {
+              java.lang.String s = input.readStringRequireUtf8();
+              communicationEncodingPresentCase_ = 1;
+              communicationEncodingPresent_ = s;
+              break;
+            }
+            case 18: {
+
+              seeds_ = input.readBytes();
+              break;
+            }
+            default: {
+              if (!parseUnknownFieldProto3(
+                  input, unknownFields, extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.alibaba.otter.canal.protocol.AdminPacket.Handshake.class, com.alibaba.otter.canal.protocol.AdminPacket.Handshake.Builder.class);
+    }
+
+    private int communicationEncodingPresentCase_ = 0;
+    private java.lang.Object communicationEncodingPresent_;
+    public enum CommunicationEncodingPresentCase
+        implements com.google.protobuf.Internal.EnumLite {
+      COMMUNICATION_ENCODING(1),
+      COMMUNICATIONENCODINGPRESENT_NOT_SET(0);
+      private final int value;
+      private CommunicationEncodingPresentCase(int value) {
+        this.value = value;
+      }
+      /**
+       * @deprecated Use {@link #forNumber(int)} instead.
+       */
+      @java.lang.Deprecated
+      public static CommunicationEncodingPresentCase valueOf(int value) {
+        return forNumber(value);
+      }
+
+      public static CommunicationEncodingPresentCase forNumber(int value) {
+        switch (value) {
+          case 1: return COMMUNICATION_ENCODING;
+          case 0: return COMMUNICATIONENCODINGPRESENT_NOT_SET;
+          default: return null;
+        }
+      }
+      public int getNumber() {
+        return this.value;
+      }
+    };
+
+    public CommunicationEncodingPresentCase
+    getCommunicationEncodingPresentCase() {
+      return CommunicationEncodingPresentCase.forNumber(
+          communicationEncodingPresentCase_);
+    }
+
+    public static final int COMMUNICATION_ENCODING_FIELD_NUMBER = 1;
+    /**
+     * <code>string communication_encoding = 1;</code>
+     */
+    public java.lang.String getCommunicationEncoding() {
+      java.lang.Object ref = "";
+      if (communicationEncodingPresentCase_ == 1) {
+        ref = communicationEncodingPresent_;
+      }
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (communicationEncodingPresentCase_ == 1) {
+          communicationEncodingPresent_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>string communication_encoding = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getCommunicationEncodingBytes() {
+      java.lang.Object ref = "";
+      if (communicationEncodingPresentCase_ == 1) {
+        ref = communicationEncodingPresent_;
+      }
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        if (communicationEncodingPresentCase_ == 1) {
+          communicationEncodingPresent_ = b;
+        }
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int SEEDS_FIELD_NUMBER = 2;
+    private com.google.protobuf.ByteString seeds_;
+    /**
+     * <code>bytes seeds = 2;</code>
+     */
+    public com.google.protobuf.ByteString getSeeds() {
+      return seeds_;
+    }
+
+    private byte memoizedIsInitialized = -1;
+    @java.lang.Override
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    @java.lang.Override
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      if (communicationEncodingPresentCase_ == 1) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, communicationEncodingPresent_);
+      }
+      if (!seeds_.isEmpty()) {
+        output.writeBytes(2, seeds_);
+      }
+      unknownFields.writeTo(output);
+    }
+
+    @java.lang.Override
+    public int getSerializedSize() {
+      int size = memoizedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (communicationEncodingPresentCase_ == 1) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, communicationEncodingPresent_);
+      }
+      if (!seeds_.isEmpty()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(2, seeds_);
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSize = size;
+      return size;
+    }
+
+    @java.lang.Override
+    public boolean equals(final java.lang.Object obj) {
+      if (obj == this) {
+       return true;
+      }
+      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.Handshake)) {
+        return super.equals(obj);
+      }
+      com.alibaba.otter.canal.protocol.AdminPacket.Handshake other = (com.alibaba.otter.canal.protocol.AdminPacket.Handshake) obj;
+
+      boolean result = true;
+      result = result && getSeeds()
+          .equals(other.getSeeds());
+      result = result && getCommunicationEncodingPresentCase().equals(
+          other.getCommunicationEncodingPresentCase());
+      if (!result) return false;
+      switch (communicationEncodingPresentCase_) {
+        case 1:
+          result = result && getCommunicationEncoding()
+              .equals(other.getCommunicationEncoding());
+          break;
+        case 0:
+        default:
+      }
+      result = result && unknownFields.equals(other.unknownFields);
+      return result;
+    }
+
+    @java.lang.Override
+    public int hashCode() {
+      if (memoizedHashCode != 0) {
+        return memoizedHashCode;
+      }
+      int hash = 41;
+      hash = (19 * hash) + getDescriptor().hashCode();
+      hash = (37 * hash) + SEEDS_FIELD_NUMBER;
+      hash = (53 * hash) + getSeeds().hashCode();
+      switch (communicationEncodingPresentCase_) {
+        case 1:
+          hash = (37 * hash) + COMMUNICATION_ENCODING_FIELD_NUMBER;
+          hash = (53 * hash) + getCommunicationEncoding().hashCode();
+          break;
+        case 0:
+        default:
+      }
+      hash = (29 * hash) + unknownFields.hashCode();
+      memoizedHashCode = hash;
+      return hash;
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(
+        java.nio.ByteBuffer data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(
+        java.nio.ByteBuffer data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+
+    @java.lang.Override
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.Handshake prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    @java.lang.Override
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code com.alibaba.otter.canal.protocol.Handshake}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.Handshake)
+        com.alibaba.otter.canal.protocol.AdminPacket.HandshakeOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;
+      }
+
+      @java.lang.Override
+      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                com.alibaba.otter.canal.protocol.AdminPacket.Handshake.class, com.alibaba.otter.canal.protocol.AdminPacket.Handshake.Builder.class);
+      }
+
+      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.Handshake.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessageV3
+                .alwaysUseFieldBuilders) {
+        }
+      }
+      @java.lang.Override
+      public Builder clear() {
+        super.clear();
+        seeds_ = com.google.protobuf.ByteString.EMPTY;
+
+        communicationEncodingPresentCase_ = 0;
+        communicationEncodingPresent_ = null;
+        return this;
+      }
+
+      @java.lang.Override
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.Handshake getDefaultInstanceForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.Handshake.getDefaultInstance();
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.Handshake build() {
+        com.alibaba.otter.canal.protocol.AdminPacket.Handshake result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.Handshake buildPartial() {
+        com.alibaba.otter.canal.protocol.AdminPacket.Handshake result = new com.alibaba.otter.canal.protocol.AdminPacket.Handshake(this);
+        if (communicationEncodingPresentCase_ == 1) {
+          result.communicationEncodingPresent_ = communicationEncodingPresent_;
+        }
+        result.seeds_ = seeds_;
+        result.communicationEncodingPresentCase_ = communicationEncodingPresentCase_;
+        onBuilt();
+        return result;
+      }
+
+      @java.lang.Override
+      public Builder clone() {
+        return (Builder) super.clone();
+      }
+      @java.lang.Override
+      public Builder setField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.setField(field, value);
+      }
+      @java.lang.Override
+      public Builder clearField(
+          com.google.protobuf.Descriptors.FieldDescriptor field) {
+        return (Builder) super.clearField(field);
+      }
+      @java.lang.Override
+      public Builder clearOneof(
+          com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+        return (Builder) super.clearOneof(oneof);
+      }
+      @java.lang.Override
+      public Builder setRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          int index, java.lang.Object value) {
+        return (Builder) super.setRepeatedField(field, index, value);
+      }
+      @java.lang.Override
+      public Builder addRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.addRepeatedField(field, value);
+      }
+      @java.lang.Override
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.Handshake) {
+          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.Handshake)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.Handshake other) {
+        if (other == com.alibaba.otter.canal.protocol.AdminPacket.Handshake.getDefaultInstance()) return this;
+        if (other.getSeeds() != com.google.protobuf.ByteString.EMPTY) {
+          setSeeds(other.getSeeds());
+        }
+        switch (other.getCommunicationEncodingPresentCase()) {
+          case COMMUNICATION_ENCODING: {
+            communicationEncodingPresentCase_ = 1;
+            communicationEncodingPresent_ = other.communicationEncodingPresent_;
+            onChanged();
+            break;
+          }
+          case COMMUNICATIONENCODINGPRESENT_NOT_SET: {
+            break;
+          }
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      @java.lang.Override
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      @java.lang.Override
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        com.alibaba.otter.canal.protocol.AdminPacket.Handshake parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.Handshake) e.getUnfinishedMessage();
+          throw e.unwrapIOException();
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int communicationEncodingPresentCase_ = 0;
+      private java.lang.Object communicationEncodingPresent_;
+      public CommunicationEncodingPresentCase
+          getCommunicationEncodingPresentCase() {
+        return CommunicationEncodingPresentCase.forNumber(
+            communicationEncodingPresentCase_);
+      }
+
+      public Builder clearCommunicationEncodingPresent() {
+        communicationEncodingPresentCase_ = 0;
+        communicationEncodingPresent_ = null;
+        onChanged();
+        return this;
+      }
+
+
+      /**
+       * <code>string communication_encoding = 1;</code>
+       */
+      public java.lang.String getCommunicationEncoding() {
+        java.lang.Object ref = "";
+        if (communicationEncodingPresentCase_ == 1) {
+          ref = communicationEncodingPresent_;
+        }
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (communicationEncodingPresentCase_ == 1) {
+            communicationEncodingPresent_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>string communication_encoding = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getCommunicationEncodingBytes() {
+        java.lang.Object ref = "";
+        if (communicationEncodingPresentCase_ == 1) {
+          ref = communicationEncodingPresent_;
+        }
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          if (communicationEncodingPresentCase_ == 1) {
+            communicationEncodingPresent_ = b;
+          }
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>string communication_encoding = 1;</code>
+       */
+      public Builder setCommunicationEncoding(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  communicationEncodingPresentCase_ = 1;
+        communicationEncodingPresent_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>string communication_encoding = 1;</code>
+       */
+      public Builder clearCommunicationEncoding() {
+        if (communicationEncodingPresentCase_ == 1) {
+          communicationEncodingPresentCase_ = 0;
+          communicationEncodingPresent_ = null;
+          onChanged();
+        }
+        return this;
+      }
+      /**
+       * <code>string communication_encoding = 1;</code>
+       */
+      public Builder setCommunicationEncodingBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+        communicationEncodingPresentCase_ = 1;
+        communicationEncodingPresent_ = value;
+        onChanged();
+        return this;
+      }
+
+      private com.google.protobuf.ByteString seeds_ = com.google.protobuf.ByteString.EMPTY;
+      /**
+       * <code>bytes seeds = 2;</code>
+       */
+      public com.google.protobuf.ByteString getSeeds() {
+        return seeds_;
+      }
+      /**
+       * <code>bytes seeds = 2;</code>
+       */
+      public Builder setSeeds(com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        seeds_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>bytes seeds = 2;</code>
+       */
+      public Builder clearSeeds() {
+        
+        seeds_ = getDefaultInstance().getSeeds();
+        onChanged();
+        return this;
+      }
+      @java.lang.Override
+      public final Builder setUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.setUnknownFieldsProto3(unknownFields);
+      }
+
+      @java.lang.Override
+      public final Builder mergeUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.mergeUnknownFields(unknownFields);
+      }
+
+
+      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.Handshake)
+    }
+
+    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.Handshake)
+    private static final com.alibaba.otter.canal.protocol.AdminPacket.Handshake DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.Handshake();
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.Handshake getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    private static final com.google.protobuf.Parser<Handshake>
+        PARSER = new com.google.protobuf.AbstractParser<Handshake>() {
+      @java.lang.Override
+      public Handshake parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new Handshake(input, extensionRegistry);
+      }
+    };
+
+    public static com.google.protobuf.Parser<Handshake> parser() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<Handshake> getParserForType() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.alibaba.otter.canal.protocol.AdminPacket.Handshake getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  public interface ClientAuthOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.ClientAuth)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>string username = 1;</code>
+     */
+    java.lang.String getUsername();
+    /**
+     * <code>string username = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getUsernameBytes();
+
+    /**
+     * <pre>
+     * hashed password with seeds from Handshake message
+     * </pre>
+     *
+     * <code>bytes password = 2;</code>
+     */
+    com.google.protobuf.ByteString getPassword();
+
+    /**
+     * <pre>
+     * in seconds
+     * </pre>
+     *
+     * <code>int32 net_read_timeout = 3;</code>
+     */
+    int getNetReadTimeout();
+
+    /**
+     * <pre>
+     * in seconds
+     * </pre>
+     *
+     * <code>int32 net_write_timeout = 4;</code>
+     */
+    int getNetWriteTimeout();
+
+    public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.NetReadTimeoutPresentCase getNetReadTimeoutPresentCase();
+
+    public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.NetWriteTimeoutPresentCase getNetWriteTimeoutPresentCase();
+  }
+  /**
+   * <pre>
+   * client authentication
+   * </pre>
+   *
+   * Protobuf type {@code com.alibaba.otter.canal.protocol.ClientAuth}
+   */
+  public  static final class ClientAuth extends
+      com.google.protobuf.GeneratedMessageV3 implements
+      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.ClientAuth)
+      ClientAuthOrBuilder {
+  private static final long serialVersionUID = 0L;
+    // Use ClientAuth.newBuilder() to construct.
+    private ClientAuth(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+      super(builder);
+    }
+    private ClientAuth() {
+      username_ = "";
+      password_ = com.google.protobuf.ByteString.EMPTY;
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private ClientAuth(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      this();
+      if (extensionRegistry == null) {
+        throw new java.lang.NullPointerException();
+      }
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            case 10: {
+              java.lang.String s = input.readStringRequireUtf8();
+
+              username_ = s;
+              break;
+            }
+            case 18: {
+
+              password_ = input.readBytes();
+              break;
+            }
+            case 24: {
+              netReadTimeoutPresentCase_ = 3;
+              netReadTimeoutPresent_ = input.readInt32();
+              break;
+            }
+            case 32: {
+              netWriteTimeoutPresentCase_ = 4;
+              netWriteTimeoutPresent_ = input.readInt32();
+              break;
+            }
+            default: {
+              if (!parseUnknownFieldProto3(
+                  input, unknownFields, extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.class, com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.Builder.class);
+    }
+
+    private int netReadTimeoutPresentCase_ = 0;
+    private java.lang.Object netReadTimeoutPresent_;
+    public enum NetReadTimeoutPresentCase
+        implements com.google.protobuf.Internal.EnumLite {
+      NET_READ_TIMEOUT(3),
+      NETREADTIMEOUTPRESENT_NOT_SET(0);
+      private final int value;
+      private NetReadTimeoutPresentCase(int value) {
+        this.value = value;
+      }
+      /**
+       * @deprecated Use {@link #forNumber(int)} instead.
+       */
+      @java.lang.Deprecated
+      public static NetReadTimeoutPresentCase valueOf(int value) {
+        return forNumber(value);
+      }
+
+      public static NetReadTimeoutPresentCase forNumber(int value) {
+        switch (value) {
+          case 3: return NET_READ_TIMEOUT;
+          case 0: return NETREADTIMEOUTPRESENT_NOT_SET;
+          default: return null;
+        }
+      }
+      public int getNumber() {
+        return this.value;
+      }
+    };
+
+    public NetReadTimeoutPresentCase
+    getNetReadTimeoutPresentCase() {
+      return NetReadTimeoutPresentCase.forNumber(
+          netReadTimeoutPresentCase_);
+    }
+
+    private int netWriteTimeoutPresentCase_ = 0;
+    private java.lang.Object netWriteTimeoutPresent_;
+    public enum NetWriteTimeoutPresentCase
+        implements com.google.protobuf.Internal.EnumLite {
+      NET_WRITE_TIMEOUT(4),
+      NETWRITETIMEOUTPRESENT_NOT_SET(0);
+      private final int value;
+      private NetWriteTimeoutPresentCase(int value) {
+        this.value = value;
+      }
+      /**
+       * @deprecated Use {@link #forNumber(int)} instead.
+       */
+      @java.lang.Deprecated
+      public static NetWriteTimeoutPresentCase valueOf(int value) {
+        return forNumber(value);
+      }
+
+      public static NetWriteTimeoutPresentCase forNumber(int value) {
+        switch (value) {
+          case 4: return NET_WRITE_TIMEOUT;
+          case 0: return NETWRITETIMEOUTPRESENT_NOT_SET;
+          default: return null;
+        }
+      }
+      public int getNumber() {
+        return this.value;
+      }
+    };
+
+    public NetWriteTimeoutPresentCase
+    getNetWriteTimeoutPresentCase() {
+      return NetWriteTimeoutPresentCase.forNumber(
+          netWriteTimeoutPresentCase_);
+    }
+
+    public static final int USERNAME_FIELD_NUMBER = 1;
+    private volatile java.lang.Object username_;
+    /**
+     * <code>string username = 1;</code>
+     */
+    public java.lang.String getUsername() {
+      java.lang.Object ref = username_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        username_ = s;
+        return s;
+      }
+    }
+    /**
+     * <code>string username = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getUsernameBytes() {
+      java.lang.Object ref = username_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        username_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int PASSWORD_FIELD_NUMBER = 2;
+    private com.google.protobuf.ByteString password_;
+    /**
+     * <pre>
+     * hashed password with seeds from Handshake message
+     * </pre>
+     *
+     * <code>bytes password = 2;</code>
+     */
+    public com.google.protobuf.ByteString getPassword() {
+      return password_;
+    }
+
+    public static final int NET_READ_TIMEOUT_FIELD_NUMBER = 3;
+    /**
+     * <pre>
+     * in seconds
+     * </pre>
+     *
+     * <code>int32 net_read_timeout = 3;</code>
+     */
+    public int getNetReadTimeout() {
+      if (netReadTimeoutPresentCase_ == 3) {
+        return (java.lang.Integer) netReadTimeoutPresent_;
+      }
+      return 0;
+    }
+
+    public static final int NET_WRITE_TIMEOUT_FIELD_NUMBER = 4;
+    /**
+     * <pre>
+     * in seconds
+     * </pre>
+     *
+     * <code>int32 net_write_timeout = 4;</code>
+     */
+    public int getNetWriteTimeout() {
+      if (netWriteTimeoutPresentCase_ == 4) {
+        return (java.lang.Integer) netWriteTimeoutPresent_;
+      }
+      return 0;
+    }
+
+    private byte memoizedIsInitialized = -1;
+    @java.lang.Override
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    @java.lang.Override
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      if (!getUsernameBytes().isEmpty()) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, username_);
+      }
+      if (!password_.isEmpty()) {
+        output.writeBytes(2, password_);
+      }
+      if (netReadTimeoutPresentCase_ == 3) {
+        output.writeInt32(
+            3, (int)((java.lang.Integer) netReadTimeoutPresent_));
+      }
+      if (netWriteTimeoutPresentCase_ == 4) {
+        output.writeInt32(
+            4, (int)((java.lang.Integer) netWriteTimeoutPresent_));
+      }
+      unknownFields.writeTo(output);
+    }
+
+    @java.lang.Override
+    public int getSerializedSize() {
+      int size = memoizedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (!getUsernameBytes().isEmpty()) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, username_);
+      }
+      if (!password_.isEmpty()) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(2, password_);
+      }
+      if (netReadTimeoutPresentCase_ == 3) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(
+              3, (int)((java.lang.Integer) netReadTimeoutPresent_));
+      }
+      if (netWriteTimeoutPresentCase_ == 4) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(
+              4, (int)((java.lang.Integer) netWriteTimeoutPresent_));
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSize = size;
+      return size;
+    }
+
+    @java.lang.Override
+    public boolean equals(final java.lang.Object obj) {
+      if (obj == this) {
+       return true;
+      }
+      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth)) {
+        return super.equals(obj);
+      }
+      com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth other = (com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth) obj;
+
+      boolean result = true;
+      result = result && getUsername()
+          .equals(other.getUsername());
+      result = result && getPassword()
+          .equals(other.getPassword());
+      result = result && getNetReadTimeoutPresentCase().equals(
+          other.getNetReadTimeoutPresentCase());
+      if (!result) return false;
+      switch (netReadTimeoutPresentCase_) {
+        case 3:
+          result = result && (getNetReadTimeout()
+              == other.getNetReadTimeout());
+          break;
+        case 0:
+        default:
+      }
+      result = result && getNetWriteTimeoutPresentCase().equals(
+          other.getNetWriteTimeoutPresentCase());
+      if (!result) return false;
+      switch (netWriteTimeoutPresentCase_) {
+        case 4:
+          result = result && (getNetWriteTimeout()
+              == other.getNetWriteTimeout());
+          break;
+        case 0:
+        default:
+      }
+      result = result && unknownFields.equals(other.unknownFields);
+      return result;
+    }
+
+    @java.lang.Override
+    public int hashCode() {
+      if (memoizedHashCode != 0) {
+        return memoizedHashCode;
+      }
+      int hash = 41;
+      hash = (19 * hash) + getDescriptor().hashCode();
+      hash = (37 * hash) + USERNAME_FIELD_NUMBER;
+      hash = (53 * hash) + getUsername().hashCode();
+      hash = (37 * hash) + PASSWORD_FIELD_NUMBER;
+      hash = (53 * hash) + getPassword().hashCode();
+      switch (netReadTimeoutPresentCase_) {
+        case 3:
+          hash = (37 * hash) + NET_READ_TIMEOUT_FIELD_NUMBER;
+          hash = (53 * hash) + getNetReadTimeout();
+          break;
+        case 0:
+        default:
+      }
+      switch (netWriteTimeoutPresentCase_) {
+        case 4:
+          hash = (37 * hash) + NET_WRITE_TIMEOUT_FIELD_NUMBER;
+          hash = (53 * hash) + getNetWriteTimeout();
+          break;
+        case 0:
+        default:
+      }
+      hash = (29 * hash) + unknownFields.hashCode();
+      memoizedHashCode = hash;
+      return hash;
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(
+        java.nio.ByteBuffer data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(
+        java.nio.ByteBuffer data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+
+    @java.lang.Override
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    @java.lang.Override
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * <pre>
+     * client authentication
+     * </pre>
+     *
+     * Protobuf type {@code com.alibaba.otter.canal.protocol.ClientAuth}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.ClientAuth)
+        com.alibaba.otter.canal.protocol.AdminPacket.ClientAuthOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;
+      }
+
+      @java.lang.Override
+      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.class, com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.Builder.class);
+      }
+
+      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessageV3
+                .alwaysUseFieldBuilders) {
+        }
+      }
+      @java.lang.Override
+      public Builder clear() {
+        super.clear();
+        username_ = "";
+
+        password_ = com.google.protobuf.ByteString.EMPTY;
+
+        netReadTimeoutPresentCase_ = 0;
+        netReadTimeoutPresent_ = null;
+        netWriteTimeoutPresentCase_ = 0;
+        netWriteTimeoutPresent_ = null;
+        return this;
+      }
+
+      @java.lang.Override
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth getDefaultInstanceForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.getDefaultInstance();
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth build() {
+        com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth buildPartial() {
+        com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth result = new com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth(this);
+        result.username_ = username_;
+        result.password_ = password_;
+        if (netReadTimeoutPresentCase_ == 3) {
+          result.netReadTimeoutPresent_ = netReadTimeoutPresent_;
+        }
+        if (netWriteTimeoutPresentCase_ == 4) {
+          result.netWriteTimeoutPresent_ = netWriteTimeoutPresent_;
+        }
+        result.netReadTimeoutPresentCase_ = netReadTimeoutPresentCase_;
+        result.netWriteTimeoutPresentCase_ = netWriteTimeoutPresentCase_;
+        onBuilt();
+        return result;
+      }
+
+      @java.lang.Override
+      public Builder clone() {
+        return (Builder) super.clone();
+      }
+      @java.lang.Override
+      public Builder setField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.setField(field, value);
+      }
+      @java.lang.Override
+      public Builder clearField(
+          com.google.protobuf.Descriptors.FieldDescriptor field) {
+        return (Builder) super.clearField(field);
+      }
+      @java.lang.Override
+      public Builder clearOneof(
+          com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+        return (Builder) super.clearOneof(oneof);
+      }
+      @java.lang.Override
+      public Builder setRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          int index, java.lang.Object value) {
+        return (Builder) super.setRepeatedField(field, index, value);
+      }
+      @java.lang.Override
+      public Builder addRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.addRepeatedField(field, value);
+      }
+      @java.lang.Override
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth) {
+          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth other) {
+        if (other == com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth.getDefaultInstance()) return this;
+        if (!other.getUsername().isEmpty()) {
+          username_ = other.username_;
+          onChanged();
+        }
+        if (other.getPassword() != com.google.protobuf.ByteString.EMPTY) {
+          setPassword(other.getPassword());
+        }
+        switch (other.getNetReadTimeoutPresentCase()) {
+          case NET_READ_TIMEOUT: {
+            setNetReadTimeout(other.getNetReadTimeout());
+            break;
+          }
+          case NETREADTIMEOUTPRESENT_NOT_SET: {
+            break;
+          }
+        }
+        switch (other.getNetWriteTimeoutPresentCase()) {
+          case NET_WRITE_TIMEOUT: {
+            setNetWriteTimeout(other.getNetWriteTimeout());
+            break;
+          }
+          case NETWRITETIMEOUTPRESENT_NOT_SET: {
+            break;
+          }
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      @java.lang.Override
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      @java.lang.Override
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth) e.getUnfinishedMessage();
+          throw e.unwrapIOException();
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int netReadTimeoutPresentCase_ = 0;
+      private java.lang.Object netReadTimeoutPresent_;
+      public NetReadTimeoutPresentCase
+          getNetReadTimeoutPresentCase() {
+        return NetReadTimeoutPresentCase.forNumber(
+            netReadTimeoutPresentCase_);
+      }
+
+      public Builder clearNetReadTimeoutPresent() {
+        netReadTimeoutPresentCase_ = 0;
+        netReadTimeoutPresent_ = null;
+        onChanged();
+        return this;
+      }
+
+      private int netWriteTimeoutPresentCase_ = 0;
+      private java.lang.Object netWriteTimeoutPresent_;
+      public NetWriteTimeoutPresentCase
+          getNetWriteTimeoutPresentCase() {
+        return NetWriteTimeoutPresentCase.forNumber(
+            netWriteTimeoutPresentCase_);
+      }
+
+      public Builder clearNetWriteTimeoutPresent() {
+        netWriteTimeoutPresentCase_ = 0;
+        netWriteTimeoutPresent_ = null;
+        onChanged();
+        return this;
+      }
+
+
+      private java.lang.Object username_ = "";
+      /**
+       * <code>string username = 1;</code>
+       */
+      public java.lang.String getUsername() {
+        java.lang.Object ref = username_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          username_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>string username = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getUsernameBytes() {
+        java.lang.Object ref = username_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          username_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>string username = 1;</code>
+       */
+      public Builder setUsername(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        username_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>string username = 1;</code>
+       */
+      public Builder clearUsername() {
+        
+        username_ = getDefaultInstance().getUsername();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>string username = 1;</code>
+       */
+      public Builder setUsernameBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+        
+        username_ = value;
+        onChanged();
+        return this;
+      }
+
+      private com.google.protobuf.ByteString password_ = com.google.protobuf.ByteString.EMPTY;
+      /**
+       * <pre>
+       * hashed password with seeds from Handshake message
+       * </pre>
+       *
+       * <code>bytes password = 2;</code>
+       */
+      public com.google.protobuf.ByteString getPassword() {
+        return password_;
+      }
+      /**
+       * <pre>
+       * hashed password with seeds from Handshake message
+       * </pre>
+       *
+       * <code>bytes password = 2;</code>
+       */
+      public Builder setPassword(com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        password_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * hashed password with seeds from Handshake message
+       * </pre>
+       *
+       * <code>bytes password = 2;</code>
+       */
+      public Builder clearPassword() {
+        
+        password_ = getDefaultInstance().getPassword();
+        onChanged();
+        return this;
+      }
+
+      /**
+       * <pre>
+       * in seconds
+       * </pre>
+       *
+       * <code>int32 net_read_timeout = 3;</code>
+       */
+      public int getNetReadTimeout() {
+        if (netReadTimeoutPresentCase_ == 3) {
+          return (java.lang.Integer) netReadTimeoutPresent_;
+        }
+        return 0;
+      }
+      /**
+       * <pre>
+       * in seconds
+       * </pre>
+       *
+       * <code>int32 net_read_timeout = 3;</code>
+       */
+      public Builder setNetReadTimeout(int value) {
+        netReadTimeoutPresentCase_ = 3;
+        netReadTimeoutPresent_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * in seconds
+       * </pre>
+       *
+       * <code>int32 net_read_timeout = 3;</code>
+       */
+      public Builder clearNetReadTimeout() {
+        if (netReadTimeoutPresentCase_ == 3) {
+          netReadTimeoutPresentCase_ = 0;
+          netReadTimeoutPresent_ = null;
+          onChanged();
+        }
+        return this;
+      }
+
+      /**
+       * <pre>
+       * in seconds
+       * </pre>
+       *
+       * <code>int32 net_write_timeout = 4;</code>
+       */
+      public int getNetWriteTimeout() {
+        if (netWriteTimeoutPresentCase_ == 4) {
+          return (java.lang.Integer) netWriteTimeoutPresent_;
+        }
+        return 0;
+      }
+      /**
+       * <pre>
+       * in seconds
+       * </pre>
+       *
+       * <code>int32 net_write_timeout = 4;</code>
+       */
+      public Builder setNetWriteTimeout(int value) {
+        netWriteTimeoutPresentCase_ = 4;
+        netWriteTimeoutPresent_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * in seconds
+       * </pre>
+       *
+       * <code>int32 net_write_timeout = 4;</code>
+       */
+      public Builder clearNetWriteTimeout() {
+        if (netWriteTimeoutPresentCase_ == 4) {
+          netWriteTimeoutPresentCase_ = 0;
+          netWriteTimeoutPresent_ = null;
+          onChanged();
+        }
+        return this;
+      }
+      @java.lang.Override
+      public final Builder setUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.setUnknownFieldsProto3(unknownFields);
+      }
+
+      @java.lang.Override
+      public final Builder mergeUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.mergeUnknownFields(unknownFields);
+      }
+
+
+      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.ClientAuth)
+    }
+
+    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.ClientAuth)
+    private static final com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth();
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    private static final com.google.protobuf.Parser<ClientAuth>
+        PARSER = new com.google.protobuf.AbstractParser<ClientAuth>() {
+      @java.lang.Override
+      public ClientAuth parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new ClientAuth(input, extensionRegistry);
+      }
+    };
+
+    public static com.google.protobuf.Parser<ClientAuth> parser() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<ClientAuth> getParserForType() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  public interface ServerAdminOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.ServerAdmin)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <pre>
+     * check/start/stop/restart/list
+     * </pre>
+     *
+     * <code>string action = 1;</code>
+     */
+    java.lang.String getAction();
+    /**
+     * <pre>
+     * check/start/stop/restart/list
+     * </pre>
+     *
+     * <code>string action = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getActionBytes();
+  }
+  /**
+   * Protobuf type {@code com.alibaba.otter.canal.protocol.ServerAdmin}
+   */
+  public  static final class ServerAdmin extends
+      com.google.protobuf.GeneratedMessageV3 implements
+      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.ServerAdmin)
+      ServerAdminOrBuilder {
+  private static final long serialVersionUID = 0L;
+    // Use ServerAdmin.newBuilder() to construct.
+    private ServerAdmin(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+      super(builder);
+    }
+    private ServerAdmin() {
+      action_ = "";
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private ServerAdmin(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      this();
+      if (extensionRegistry == null) {
+        throw new java.lang.NullPointerException();
+      }
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            case 10: {
+              java.lang.String s = input.readStringRequireUtf8();
+
+              action_ = s;
+              break;
+            }
+            default: {
+              if (!parseUnknownFieldProto3(
+                  input, unknownFields, extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.Builder.class);
+    }
+
+    public static final int ACTION_FIELD_NUMBER = 1;
+    private volatile java.lang.Object action_;
+    /**
+     * <pre>
+     * check/start/stop/restart/list
+     * </pre>
+     *
+     * <code>string action = 1;</code>
+     */
+    public java.lang.String getAction() {
+      java.lang.Object ref = action_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        action_ = s;
+        return s;
+      }
+    }
+    /**
+     * <pre>
+     * check/start/stop/restart/list
+     * </pre>
+     *
+     * <code>string action = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getActionBytes() {
+      java.lang.Object ref = action_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        action_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    private byte memoizedIsInitialized = -1;
+    @java.lang.Override
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    @java.lang.Override
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      if (!getActionBytes().isEmpty()) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, action_);
+      }
+      unknownFields.writeTo(output);
+    }
+
+    @java.lang.Override
+    public int getSerializedSize() {
+      int size = memoizedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (!getActionBytes().isEmpty()) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, action_);
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSize = size;
+      return size;
+    }
+
+    @java.lang.Override
+    public boolean equals(final java.lang.Object obj) {
+      if (obj == this) {
+       return true;
+      }
+      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin)) {
+        return super.equals(obj);
+      }
+      com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin other = (com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin) obj;
+
+      boolean result = true;
+      result = result && getAction()
+          .equals(other.getAction());
+      result = result && unknownFields.equals(other.unknownFields);
+      return result;
+    }
+
+    @java.lang.Override
+    public int hashCode() {
+      if (memoizedHashCode != 0) {
+        return memoizedHashCode;
+      }
+      int hash = 41;
+      hash = (19 * hash) + getDescriptor().hashCode();
+      hash = (37 * hash) + ACTION_FIELD_NUMBER;
+      hash = (53 * hash) + getAction().hashCode();
+      hash = (29 * hash) + unknownFields.hashCode();
+      memoizedHashCode = hash;
+      return hash;
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(
+        java.nio.ByteBuffer data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(
+        java.nio.ByteBuffer data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+
+    @java.lang.Override
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    @java.lang.Override
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code com.alibaba.otter.canal.protocol.ServerAdmin}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.ServerAdmin)
+        com.alibaba.otter.canal.protocol.AdminPacket.ServerAdminOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor;
+      }
+
+      @java.lang.Override
+      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.Builder.class);
+      }
+
+      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessageV3
+                .alwaysUseFieldBuilders) {
+        }
+      }
+      @java.lang.Override
+      public Builder clear() {
+        super.clear();
+        action_ = "";
+
+        return this;
+      }
+
+      @java.lang.Override
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin getDefaultInstanceForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.getDefaultInstance();
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin build() {
+        com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin buildPartial() {
+        com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin result = new com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin(this);
+        result.action_ = action_;
+        onBuilt();
+        return result;
+      }
+
+      @java.lang.Override
+      public Builder clone() {
+        return (Builder) super.clone();
+      }
+      @java.lang.Override
+      public Builder setField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.setField(field, value);
+      }
+      @java.lang.Override
+      public Builder clearField(
+          com.google.protobuf.Descriptors.FieldDescriptor field) {
+        return (Builder) super.clearField(field);
+      }
+      @java.lang.Override
+      public Builder clearOneof(
+          com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+        return (Builder) super.clearOneof(oneof);
+      }
+      @java.lang.Override
+      public Builder setRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          int index, java.lang.Object value) {
+        return (Builder) super.setRepeatedField(field, index, value);
+      }
+      @java.lang.Override
+      public Builder addRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.addRepeatedField(field, value);
+      }
+      @java.lang.Override
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin) {
+          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin other) {
+        if (other == com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin.getDefaultInstance()) return this;
+        if (!other.getAction().isEmpty()) {
+          action_ = other.action_;
+          onChanged();
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      @java.lang.Override
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      @java.lang.Override
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin) e.getUnfinishedMessage();
+          throw e.unwrapIOException();
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+
+      private java.lang.Object action_ = "";
+      /**
+       * <pre>
+       * check/start/stop/restart/list
+       * </pre>
+       *
+       * <code>string action = 1;</code>
+       */
+      public java.lang.String getAction() {
+        java.lang.Object ref = action_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          action_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <pre>
+       * check/start/stop/restart/list
+       * </pre>
+       *
+       * <code>string action = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getActionBytes() {
+        java.lang.Object ref = action_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          action_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <pre>
+       * check/start/stop/restart/list
+       * </pre>
+       *
+       * <code>string action = 1;</code>
+       */
+      public Builder setAction(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        action_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * check/start/stop/restart/list
+       * </pre>
+       *
+       * <code>string action = 1;</code>
+       */
+      public Builder clearAction() {
+        
+        action_ = getDefaultInstance().getAction();
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * check/start/stop/restart/list
+       * </pre>
+       *
+       * <code>string action = 1;</code>
+       */
+      public Builder setActionBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+        
+        action_ = value;
+        onChanged();
+        return this;
+      }
+      @java.lang.Override
+      public final Builder setUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.setUnknownFieldsProto3(unknownFields);
+      }
+
+      @java.lang.Override
+      public final Builder mergeUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.mergeUnknownFields(unknownFields);
+      }
+
+
+      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.ServerAdmin)
+    }
+
+    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.ServerAdmin)
+    private static final com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin();
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    private static final com.google.protobuf.Parser<ServerAdmin>
+        PARSER = new com.google.protobuf.AbstractParser<ServerAdmin>() {
+      @java.lang.Override
+      public ServerAdmin parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new ServerAdmin(input, extensionRegistry);
+      }
+    };
+
+    public static com.google.protobuf.Parser<ServerAdmin> parser() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<ServerAdmin> getParserForType() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  public interface InstanceAdminOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.InstanceAdmin)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>string destination = 1;</code>
+     */
+    java.lang.String getDestination();
+    /**
+     * <code>string destination = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getDestinationBytes();
+
+    /**
+     * <pre>
+     * check/start/stop/reload
+     * </pre>
+     *
+     * <code>string action = 2;</code>
+     */
+    java.lang.String getAction();
+    /**
+     * <pre>
+     * check/start/stop/reload
+     * </pre>
+     *
+     * <code>string action = 2;</code>
+     */
+    com.google.protobuf.ByteString
+        getActionBytes();
+  }
+  /**
+   * Protobuf type {@code com.alibaba.otter.canal.protocol.InstanceAdmin}
+   */
+  public  static final class InstanceAdmin extends
+      com.google.protobuf.GeneratedMessageV3 implements
+      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.InstanceAdmin)
+      InstanceAdminOrBuilder {
+  private static final long serialVersionUID = 0L;
+    // Use InstanceAdmin.newBuilder() to construct.
+    private InstanceAdmin(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+      super(builder);
+    }
+    private InstanceAdmin() {
+      destination_ = "";
+      action_ = "";
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private InstanceAdmin(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      this();
+      if (extensionRegistry == null) {
+        throw new java.lang.NullPointerException();
+      }
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            case 10: {
+              java.lang.String s = input.readStringRequireUtf8();
+
+              destination_ = s;
+              break;
+            }
+            case 18: {
+              java.lang.String s = input.readStringRequireUtf8();
+
+              action_ = s;
+              break;
+            }
+            default: {
+              if (!parseUnknownFieldProto3(
+                  input, unknownFields, extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.Builder.class);
+    }
+
+    public static final int DESTINATION_FIELD_NUMBER = 1;
+    private volatile java.lang.Object destination_;
+    /**
+     * <code>string destination = 1;</code>
+     */
+    public java.lang.String getDestination() {
+      java.lang.Object ref = destination_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        destination_ = s;
+        return s;
+      }
+    }
+    /**
+     * <code>string destination = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getDestinationBytes() {
+      java.lang.Object ref = destination_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        destination_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int ACTION_FIELD_NUMBER = 2;
+    private volatile java.lang.Object action_;
+    /**
+     * <pre>
+     * check/start/stop/reload
+     * </pre>
+     *
+     * <code>string action = 2;</code>
+     */
+    public java.lang.String getAction() {
+      java.lang.Object ref = action_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        action_ = s;
+        return s;
+      }
+    }
+    /**
+     * <pre>
+     * check/start/stop/reload
+     * </pre>
+     *
+     * <code>string action = 2;</code>
+     */
+    public com.google.protobuf.ByteString
+        getActionBytes() {
+      java.lang.Object ref = action_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        action_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    private byte memoizedIsInitialized = -1;
+    @java.lang.Override
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    @java.lang.Override
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      if (!getDestinationBytes().isEmpty()) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, destination_);
+      }
+      if (!getActionBytes().isEmpty()) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, action_);
+      }
+      unknownFields.writeTo(output);
+    }
+
+    @java.lang.Override
+    public int getSerializedSize() {
+      int size = memoizedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (!getDestinationBytes().isEmpty()) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, destination_);
+      }
+      if (!getActionBytes().isEmpty()) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, action_);
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSize = size;
+      return size;
+    }
+
+    @java.lang.Override
+    public boolean equals(final java.lang.Object obj) {
+      if (obj == this) {
+       return true;
+      }
+      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin)) {
+        return super.equals(obj);
+      }
+      com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin other = (com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin) obj;
+
+      boolean result = true;
+      result = result && getDestination()
+          .equals(other.getDestination());
+      result = result && getAction()
+          .equals(other.getAction());
+      result = result && unknownFields.equals(other.unknownFields);
+      return result;
+    }
+
+    @java.lang.Override
+    public int hashCode() {
+      if (memoizedHashCode != 0) {
+        return memoizedHashCode;
+      }
+      int hash = 41;
+      hash = (19 * hash) + getDescriptor().hashCode();
+      hash = (37 * hash) + DESTINATION_FIELD_NUMBER;
+      hash = (53 * hash) + getDestination().hashCode();
+      hash = (37 * hash) + ACTION_FIELD_NUMBER;
+      hash = (53 * hash) + getAction().hashCode();
+      hash = (29 * hash) + unknownFields.hashCode();
+      memoizedHashCode = hash;
+      return hash;
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(
+        java.nio.ByteBuffer data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(
+        java.nio.ByteBuffer data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+
+    @java.lang.Override
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    @java.lang.Override
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code com.alibaba.otter.canal.protocol.InstanceAdmin}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.InstanceAdmin)
+        com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdminOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor;
+      }
+
+      @java.lang.Override
+      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.Builder.class);
+      }
+
+      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessageV3
+                .alwaysUseFieldBuilders) {
+        }
+      }
+      @java.lang.Override
+      public Builder clear() {
+        super.clear();
+        destination_ = "";
+
+        action_ = "";
+
+        return this;
+      }
+
+      @java.lang.Override
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin getDefaultInstanceForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.getDefaultInstance();
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin build() {
+        com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin buildPartial() {
+        com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin result = new com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin(this);
+        result.destination_ = destination_;
+        result.action_ = action_;
+        onBuilt();
+        return result;
+      }
+
+      @java.lang.Override
+      public Builder clone() {
+        return (Builder) super.clone();
+      }
+      @java.lang.Override
+      public Builder setField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.setField(field, value);
+      }
+      @java.lang.Override
+      public Builder clearField(
+          com.google.protobuf.Descriptors.FieldDescriptor field) {
+        return (Builder) super.clearField(field);
+      }
+      @java.lang.Override
+      public Builder clearOneof(
+          com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+        return (Builder) super.clearOneof(oneof);
+      }
+      @java.lang.Override
+      public Builder setRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          int index, java.lang.Object value) {
+        return (Builder) super.setRepeatedField(field, index, value);
+      }
+      @java.lang.Override
+      public Builder addRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.addRepeatedField(field, value);
+      }
+      @java.lang.Override
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin) {
+          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin other) {
+        if (other == com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin.getDefaultInstance()) return this;
+        if (!other.getDestination().isEmpty()) {
+          destination_ = other.destination_;
+          onChanged();
+        }
+        if (!other.getAction().isEmpty()) {
+          action_ = other.action_;
+          onChanged();
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      @java.lang.Override
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      @java.lang.Override
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin) e.getUnfinishedMessage();
+          throw e.unwrapIOException();
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+
+      private java.lang.Object destination_ = "";
+      /**
+       * <code>string destination = 1;</code>
+       */
+      public java.lang.String getDestination() {
+        java.lang.Object ref = destination_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          destination_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>string destination = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getDestinationBytes() {
+        java.lang.Object ref = destination_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          destination_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>string destination = 1;</code>
+       */
+      public Builder setDestination(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        destination_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>string destination = 1;</code>
+       */
+      public Builder clearDestination() {
+        
+        destination_ = getDefaultInstance().getDestination();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>string destination = 1;</code>
+       */
+      public Builder setDestinationBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+        
+        destination_ = value;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object action_ = "";
+      /**
+       * <pre>
+       * check/start/stop/reload
+       * </pre>
+       *
+       * <code>string action = 2;</code>
+       */
+      public java.lang.String getAction() {
+        java.lang.Object ref = action_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          action_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <pre>
+       * check/start/stop/reload
+       * </pre>
+       *
+       * <code>string action = 2;</code>
+       */
+      public com.google.protobuf.ByteString
+          getActionBytes() {
+        java.lang.Object ref = action_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          action_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <pre>
+       * check/start/stop/reload
+       * </pre>
+       *
+       * <code>string action = 2;</code>
+       */
+      public Builder setAction(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        action_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * check/start/stop/reload
+       * </pre>
+       *
+       * <code>string action = 2;</code>
+       */
+      public Builder clearAction() {
+        
+        action_ = getDefaultInstance().getAction();
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * check/start/stop/reload
+       * </pre>
+       *
+       * <code>string action = 2;</code>
+       */
+      public Builder setActionBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+        
+        action_ = value;
+        onChanged();
+        return this;
+      }
+      @java.lang.Override
+      public final Builder setUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.setUnknownFieldsProto3(unknownFields);
+      }
+
+      @java.lang.Override
+      public final Builder mergeUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.mergeUnknownFields(unknownFields);
+      }
+
+
+      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.InstanceAdmin)
+    }
+
+    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.InstanceAdmin)
+    private static final com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin();
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    private static final com.google.protobuf.Parser<InstanceAdmin>
+        PARSER = new com.google.protobuf.AbstractParser<InstanceAdmin>() {
+      @java.lang.Override
+      public InstanceAdmin parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new InstanceAdmin(input, extensionRegistry);
+      }
+    };
+
+    public static com.google.protobuf.Parser<InstanceAdmin> parser() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<InstanceAdmin> getParserForType() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  public interface LogAdminOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:com.alibaba.otter.canal.protocol.LogAdmin)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <pre>
+     * canal/instance
+     * </pre>
+     *
+     * <code>string type = 1;</code>
+     */
+    java.lang.String getType();
+    /**
+     * <pre>
+     * canal/instance
+     * </pre>
+     *
+     * <code>string type = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getTypeBytes();
+
+    /**
+     * <code>string action = 2;</code>
+     */
+    java.lang.String getAction();
+    /**
+     * <code>string action = 2;</code>
+     */
+    com.google.protobuf.ByteString
+        getActionBytes();
+
+    /**
+     * <code>string destination = 3;</code>
+     */
+    java.lang.String getDestination();
+    /**
+     * <code>string destination = 3;</code>
+     */
+    com.google.protobuf.ByteString
+        getDestinationBytes();
+
+    /**
+     * <code>string file = 4;</code>
+     */
+    java.lang.String getFile();
+    /**
+     * <code>string file = 4;</code>
+     */
+    com.google.protobuf.ByteString
+        getFileBytes();
+
+    /**
+     * <pre>
+     * 默认tail 100行,最大不超过4MB
+     * </pre>
+     *
+     * <code>int32 count = 5;</code>
+     */
+    int getCount();
+
+    public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.DestinationPresentCase getDestinationPresentCase();
+
+    public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.FilePresentCase getFilePresentCase();
+
+    public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.CountPresentCase getCountPresentCase();
+  }
+  /**
+   * Protobuf type {@code com.alibaba.otter.canal.protocol.LogAdmin}
+   */
+  public  static final class LogAdmin extends
+      com.google.protobuf.GeneratedMessageV3 implements
+      // @@protoc_insertion_point(message_implements:com.alibaba.otter.canal.protocol.LogAdmin)
+      LogAdminOrBuilder {
+  private static final long serialVersionUID = 0L;
+    // Use LogAdmin.newBuilder() to construct.
+    private LogAdmin(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+      super(builder);
+    }
+    private LogAdmin() {
+      type_ = "";
+      action_ = "";
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private LogAdmin(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      this();
+      if (extensionRegistry == null) {
+        throw new java.lang.NullPointerException();
+      }
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            case 10: {
+              java.lang.String s = input.readStringRequireUtf8();
+
+              type_ = s;
+              break;
+            }
+            case 18: {
+              java.lang.String s = input.readStringRequireUtf8();
+
+              action_ = s;
+              break;
+            }
+            case 26: {
+              java.lang.String s = input.readStringRequireUtf8();
+              destinationPresentCase_ = 3;
+              destinationPresent_ = s;
+              break;
+            }
+            case 34: {
+              java.lang.String s = input.readStringRequireUtf8();
+              filePresentCase_ = 4;
+              filePresent_ = s;
+              break;
+            }
+            case 40: {
+              countPresentCase_ = 5;
+              countPresent_ = input.readInt32();
+              break;
+            }
+            default: {
+              if (!parseUnknownFieldProto3(
+                  input, unknownFields, extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_LogAdmin_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.Builder.class);
+    }
+
+    private int destinationPresentCase_ = 0;
+    private java.lang.Object destinationPresent_;
+    public enum DestinationPresentCase
+        implements com.google.protobuf.Internal.EnumLite {
+      DESTINATION(3),
+      DESTINATIONPRESENT_NOT_SET(0);
+      private final int value;
+      private DestinationPresentCase(int value) {
+        this.value = value;
+      }
+      /**
+       * @deprecated Use {@link #forNumber(int)} instead.
+       */
+      @java.lang.Deprecated
+      public static DestinationPresentCase valueOf(int value) {
+        return forNumber(value);
+      }
+
+      public static DestinationPresentCase forNumber(int value) {
+        switch (value) {
+          case 3: return DESTINATION;
+          case 0: return DESTINATIONPRESENT_NOT_SET;
+          default: return null;
+        }
+      }
+      public int getNumber() {
+        return this.value;
+      }
+    };
+
+    public DestinationPresentCase
+    getDestinationPresentCase() {
+      return DestinationPresentCase.forNumber(
+          destinationPresentCase_);
+    }
+
+    private int filePresentCase_ = 0;
+    private java.lang.Object filePresent_;
+    public enum FilePresentCase
+        implements com.google.protobuf.Internal.EnumLite {
+      FILE(4),
+      FILEPRESENT_NOT_SET(0);
+      private final int value;
+      private FilePresentCase(int value) {
+        this.value = value;
+      }
+      /**
+       * @deprecated Use {@link #forNumber(int)} instead.
+       */
+      @java.lang.Deprecated
+      public static FilePresentCase valueOf(int value) {
+        return forNumber(value);
+      }
+
+      public static FilePresentCase forNumber(int value) {
+        switch (value) {
+          case 4: return FILE;
+          case 0: return FILEPRESENT_NOT_SET;
+          default: return null;
+        }
+      }
+      public int getNumber() {
+        return this.value;
+      }
+    };
+
+    public FilePresentCase
+    getFilePresentCase() {
+      return FilePresentCase.forNumber(
+          filePresentCase_);
+    }
+
+    private int countPresentCase_ = 0;
+    private java.lang.Object countPresent_;
+    public enum CountPresentCase
+        implements com.google.protobuf.Internal.EnumLite {
+      COUNT(5),
+      COUNTPRESENT_NOT_SET(0);
+      private final int value;
+      private CountPresentCase(int value) {
+        this.value = value;
+      }
+      /**
+       * @deprecated Use {@link #forNumber(int)} instead.
+       */
+      @java.lang.Deprecated
+      public static CountPresentCase valueOf(int value) {
+        return forNumber(value);
+      }
+
+      public static CountPresentCase forNumber(int value) {
+        switch (value) {
+          case 5: return COUNT;
+          case 0: return COUNTPRESENT_NOT_SET;
+          default: return null;
+        }
+      }
+      public int getNumber() {
+        return this.value;
+      }
+    };
+
+    public CountPresentCase
+    getCountPresentCase() {
+      return CountPresentCase.forNumber(
+          countPresentCase_);
+    }
+
+    public static final int TYPE_FIELD_NUMBER = 1;
+    private volatile java.lang.Object type_;
+    /**
+     * <pre>
+     * canal/instance
+     * </pre>
+     *
+     * <code>string type = 1;</code>
+     */
+    public java.lang.String getType() {
+      java.lang.Object ref = type_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        type_ = s;
+        return s;
+      }
+    }
+    /**
+     * <pre>
+     * canal/instance
+     * </pre>
+     *
+     * <code>string type = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getTypeBytes() {
+      java.lang.Object ref = type_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        type_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int ACTION_FIELD_NUMBER = 2;
+    private volatile java.lang.Object action_;
+    /**
+     * <code>string action = 2;</code>
+     */
+    public java.lang.String getAction() {
+      java.lang.Object ref = action_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        action_ = s;
+        return s;
+      }
+    }
+    /**
+     * <code>string action = 2;</code>
+     */
+    public com.google.protobuf.ByteString
+        getActionBytes() {
+      java.lang.Object ref = action_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        action_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int DESTINATION_FIELD_NUMBER = 3;
+    /**
+     * <code>string destination = 3;</code>
+     */
+    public java.lang.String getDestination() {
+      java.lang.Object ref = "";
+      if (destinationPresentCase_ == 3) {
+        ref = destinationPresent_;
+      }
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (destinationPresentCase_ == 3) {
+          destinationPresent_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>string destination = 3;</code>
+     */
+    public com.google.protobuf.ByteString
+        getDestinationBytes() {
+      java.lang.Object ref = "";
+      if (destinationPresentCase_ == 3) {
+        ref = destinationPresent_;
+      }
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        if (destinationPresentCase_ == 3) {
+          destinationPresent_ = b;
+        }
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int FILE_FIELD_NUMBER = 4;
+    /**
+     * <code>string file = 4;</code>
+     */
+    public java.lang.String getFile() {
+      java.lang.Object ref = "";
+      if (filePresentCase_ == 4) {
+        ref = filePresent_;
+      }
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (filePresentCase_ == 4) {
+          filePresent_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>string file = 4;</code>
+     */
+    public com.google.protobuf.ByteString
+        getFileBytes() {
+      java.lang.Object ref = "";
+      if (filePresentCase_ == 4) {
+        ref = filePresent_;
+      }
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        if (filePresentCase_ == 4) {
+          filePresent_ = b;
+        }
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int COUNT_FIELD_NUMBER = 5;
+    /**
+     * <pre>
+     * 默认tail 100行,最大不超过4MB
+     * </pre>
+     *
+     * <code>int32 count = 5;</code>
+     */
+    public int getCount() {
+      if (countPresentCase_ == 5) {
+        return (java.lang.Integer) countPresent_;
+      }
+      return 0;
+    }
+
+    private byte memoizedIsInitialized = -1;
+    @java.lang.Override
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    @java.lang.Override
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      if (!getTypeBytes().isEmpty()) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, type_);
+      }
+      if (!getActionBytes().isEmpty()) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, action_);
+      }
+      if (destinationPresentCase_ == 3) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 3, destinationPresent_);
+      }
+      if (filePresentCase_ == 4) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 4, filePresent_);
+      }
+      if (countPresentCase_ == 5) {
+        output.writeInt32(
+            5, (int)((java.lang.Integer) countPresent_));
+      }
+      unknownFields.writeTo(output);
+    }
+
+    @java.lang.Override
+    public int getSerializedSize() {
+      int size = memoizedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (!getTypeBytes().isEmpty()) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, type_);
+      }
+      if (!getActionBytes().isEmpty()) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, action_);
+      }
+      if (destinationPresentCase_ == 3) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, destinationPresent_);
+      }
+      if (filePresentCase_ == 4) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, filePresent_);
+      }
+      if (countPresentCase_ == 5) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(
+              5, (int)((java.lang.Integer) countPresent_));
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSize = size;
+      return size;
+    }
+
+    @java.lang.Override
+    public boolean equals(final java.lang.Object obj) {
+      if (obj == this) {
+       return true;
+      }
+      if (!(obj instanceof com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin)) {
+        return super.equals(obj);
+      }
+      com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin other = (com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin) obj;
+
+      boolean result = true;
+      result = result && getType()
+          .equals(other.getType());
+      result = result && getAction()
+          .equals(other.getAction());
+      result = result && getDestinationPresentCase().equals(
+          other.getDestinationPresentCase());
+      if (!result) return false;
+      switch (destinationPresentCase_) {
+        case 3:
+          result = result && getDestination()
+              .equals(other.getDestination());
+          break;
+        case 0:
+        default:
+      }
+      result = result && getFilePresentCase().equals(
+          other.getFilePresentCase());
+      if (!result) return false;
+      switch (filePresentCase_) {
+        case 4:
+          result = result && getFile()
+              .equals(other.getFile());
+          break;
+        case 0:
+        default:
+      }
+      result = result && getCountPresentCase().equals(
+          other.getCountPresentCase());
+      if (!result) return false;
+      switch (countPresentCase_) {
+        case 5:
+          result = result && (getCount()
+              == other.getCount());
+          break;
+        case 0:
+        default:
+      }
+      result = result && unknownFields.equals(other.unknownFields);
+      return result;
+    }
+
+    @java.lang.Override
+    public int hashCode() {
+      if (memoizedHashCode != 0) {
+        return memoizedHashCode;
+      }
+      int hash = 41;
+      hash = (19 * hash) + getDescriptor().hashCode();
+      hash = (37 * hash) + TYPE_FIELD_NUMBER;
+      hash = (53 * hash) + getType().hashCode();
+      hash = (37 * hash) + ACTION_FIELD_NUMBER;
+      hash = (53 * hash) + getAction().hashCode();
+      switch (destinationPresentCase_) {
+        case 3:
+          hash = (37 * hash) + DESTINATION_FIELD_NUMBER;
+          hash = (53 * hash) + getDestination().hashCode();
+          break;
+        case 0:
+        default:
+      }
+      switch (filePresentCase_) {
+        case 4:
+          hash = (37 * hash) + FILE_FIELD_NUMBER;
+          hash = (53 * hash) + getFile().hashCode();
+          break;
+        case 0:
+        default:
+      }
+      switch (countPresentCase_) {
+        case 5:
+          hash = (37 * hash) + COUNT_FIELD_NUMBER;
+          hash = (53 * hash) + getCount();
+          break;
+        case 0:
+        default:
+      }
+      hash = (29 * hash) + unknownFields.hashCode();
+      memoizedHashCode = hash;
+      return hash;
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(
+        java.nio.ByteBuffer data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(
+        java.nio.ByteBuffer data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input);
+    }
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return com.google.protobuf.GeneratedMessageV3
+          .parseWithIOException(PARSER, input, extensionRegistry);
+    }
+
+    @java.lang.Override
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    @java.lang.Override
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code com.alibaba.otter.canal.protocol.LogAdmin}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:com.alibaba.otter.canal.protocol.LogAdmin)
+        com.alibaba.otter.canal.protocol.AdminPacket.LogAdminOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor;
+      }
+
+      @java.lang.Override
+      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_LogAdmin_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.class, com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.Builder.class);
+      }
+
+      // Construct using com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessageV3
+                .alwaysUseFieldBuilders) {
+        }
+      }
+      @java.lang.Override
+      public Builder clear() {
+        super.clear();
+        type_ = "";
+
+        action_ = "";
+
+        destinationPresentCase_ = 0;
+        destinationPresent_ = null;
+        filePresentCase_ = 0;
+        filePresent_ = null;
+        countPresentCase_ = 0;
+        countPresent_ = null;
+        return this;
+      }
+
+      @java.lang.Override
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin getDefaultInstanceForType() {
+        return com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.getDefaultInstance();
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin build() {
+        com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      @java.lang.Override
+      public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin buildPartial() {
+        com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin result = new com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin(this);
+        result.type_ = type_;
+        result.action_ = action_;
+        if (destinationPresentCase_ == 3) {
+          result.destinationPresent_ = destinationPresent_;
+        }
+        if (filePresentCase_ == 4) {
+          result.filePresent_ = filePresent_;
+        }
+        if (countPresentCase_ == 5) {
+          result.countPresent_ = countPresent_;
+        }
+        result.destinationPresentCase_ = destinationPresentCase_;
+        result.filePresentCase_ = filePresentCase_;
+        result.countPresentCase_ = countPresentCase_;
+        onBuilt();
+        return result;
+      }
+
+      @java.lang.Override
+      public Builder clone() {
+        return (Builder) super.clone();
+      }
+      @java.lang.Override
+      public Builder setField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.setField(field, value);
+      }
+      @java.lang.Override
+      public Builder clearField(
+          com.google.protobuf.Descriptors.FieldDescriptor field) {
+        return (Builder) super.clearField(field);
+      }
+      @java.lang.Override
+      public Builder clearOneof(
+          com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+        return (Builder) super.clearOneof(oneof);
+      }
+      @java.lang.Override
+      public Builder setRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          int index, java.lang.Object value) {
+        return (Builder) super.setRepeatedField(field, index, value);
+      }
+      @java.lang.Override
+      public Builder addRepeatedField(
+          com.google.protobuf.Descriptors.FieldDescriptor field,
+          java.lang.Object value) {
+        return (Builder) super.addRepeatedField(field, value);
+      }
+      @java.lang.Override
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin) {
+          return mergeFrom((com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin other) {
+        if (other == com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin.getDefaultInstance()) return this;
+        if (!other.getType().isEmpty()) {
+          type_ = other.type_;
+          onChanged();
+        }
+        if (!other.getAction().isEmpty()) {
+          action_ = other.action_;
+          onChanged();
+        }
+        switch (other.getDestinationPresentCase()) {
+          case DESTINATION: {
+            destinationPresentCase_ = 3;
+            destinationPresent_ = other.destinationPresent_;
+            onChanged();
+            break;
+          }
+          case DESTINATIONPRESENT_NOT_SET: {
+            break;
+          }
+        }
+        switch (other.getFilePresentCase()) {
+          case FILE: {
+            filePresentCase_ = 4;
+            filePresent_ = other.filePresent_;
+            onChanged();
+            break;
+          }
+          case FILEPRESENT_NOT_SET: {
+            break;
+          }
+        }
+        switch (other.getCountPresentCase()) {
+          case COUNT: {
+            setCount(other.getCount());
+            break;
+          }
+          case COUNTPRESENT_NOT_SET: {
+            break;
+          }
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      @java.lang.Override
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      @java.lang.Override
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin) e.getUnfinishedMessage();
+          throw e.unwrapIOException();
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int destinationPresentCase_ = 0;
+      private java.lang.Object destinationPresent_;
+      public DestinationPresentCase
+          getDestinationPresentCase() {
+        return DestinationPresentCase.forNumber(
+            destinationPresentCase_);
+      }
+
+      public Builder clearDestinationPresent() {
+        destinationPresentCase_ = 0;
+        destinationPresent_ = null;
+        onChanged();
+        return this;
+      }
+
+      private int filePresentCase_ = 0;
+      private java.lang.Object filePresent_;
+      public FilePresentCase
+          getFilePresentCase() {
+        return FilePresentCase.forNumber(
+            filePresentCase_);
+      }
+
+      public Builder clearFilePresent() {
+        filePresentCase_ = 0;
+        filePresent_ = null;
+        onChanged();
+        return this;
+      }
+
+      private int countPresentCase_ = 0;
+      private java.lang.Object countPresent_;
+      public CountPresentCase
+          getCountPresentCase() {
+        return CountPresentCase.forNumber(
+            countPresentCase_);
+      }
+
+      public Builder clearCountPresent() {
+        countPresentCase_ = 0;
+        countPresent_ = null;
+        onChanged();
+        return this;
+      }
+
+
+      private java.lang.Object type_ = "";
+      /**
+       * <pre>
+       * canal/instance
+       * </pre>
+       *
+       * <code>string type = 1;</code>
+       */
+      public java.lang.String getType() {
+        java.lang.Object ref = type_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          type_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <pre>
+       * canal/instance
+       * </pre>
+       *
+       * <code>string type = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getTypeBytes() {
+        java.lang.Object ref = type_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          type_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <pre>
+       * canal/instance
+       * </pre>
+       *
+       * <code>string type = 1;</code>
+       */
+      public Builder setType(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        type_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * canal/instance
+       * </pre>
+       *
+       * <code>string type = 1;</code>
+       */
+      public Builder clearType() {
+        
+        type_ = getDefaultInstance().getType();
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * canal/instance
+       * </pre>
+       *
+       * <code>string type = 1;</code>
+       */
+      public Builder setTypeBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+        
+        type_ = value;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object action_ = "";
+      /**
+       * <code>string action = 2;</code>
+       */
+      public java.lang.String getAction() {
+        java.lang.Object ref = action_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          action_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>string action = 2;</code>
+       */
+      public com.google.protobuf.ByteString
+          getActionBytes() {
+        java.lang.Object ref = action_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          action_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>string action = 2;</code>
+       */
+      public Builder setAction(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        action_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>string action = 2;</code>
+       */
+      public Builder clearAction() {
+        
+        action_ = getDefaultInstance().getAction();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>string action = 2;</code>
+       */
+      public Builder setActionBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+        
+        action_ = value;
+        onChanged();
+        return this;
+      }
+
+      /**
+       * <code>string destination = 3;</code>
+       */
+      public java.lang.String getDestination() {
+        java.lang.Object ref = "";
+        if (destinationPresentCase_ == 3) {
+          ref = destinationPresent_;
+        }
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (destinationPresentCase_ == 3) {
+            destinationPresent_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>string destination = 3;</code>
+       */
+      public com.google.protobuf.ByteString
+          getDestinationBytes() {
+        java.lang.Object ref = "";
+        if (destinationPresentCase_ == 3) {
+          ref = destinationPresent_;
+        }
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          if (destinationPresentCase_ == 3) {
+            destinationPresent_ = b;
+          }
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>string destination = 3;</code>
+       */
+      public Builder setDestination(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  destinationPresentCase_ = 3;
+        destinationPresent_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>string destination = 3;</code>
+       */
+      public Builder clearDestination() {
+        if (destinationPresentCase_ == 3) {
+          destinationPresentCase_ = 0;
+          destinationPresent_ = null;
+          onChanged();
+        }
+        return this;
+      }
+      /**
+       * <code>string destination = 3;</code>
+       */
+      public Builder setDestinationBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+        destinationPresentCase_ = 3;
+        destinationPresent_ = value;
+        onChanged();
+        return this;
+      }
+
+      /**
+       * <code>string file = 4;</code>
+       */
+      public java.lang.String getFile() {
+        java.lang.Object ref = "";
+        if (filePresentCase_ == 4) {
+          ref = filePresent_;
+        }
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (filePresentCase_ == 4) {
+            filePresent_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>string file = 4;</code>
+       */
+      public com.google.protobuf.ByteString
+          getFileBytes() {
+        java.lang.Object ref = "";
+        if (filePresentCase_ == 4) {
+          ref = filePresent_;
+        }
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          if (filePresentCase_ == 4) {
+            filePresent_ = b;
+          }
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>string file = 4;</code>
+       */
+      public Builder setFile(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  filePresentCase_ = 4;
+        filePresent_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>string file = 4;</code>
+       */
+      public Builder clearFile() {
+        if (filePresentCase_ == 4) {
+          filePresentCase_ = 0;
+          filePresent_ = null;
+          onChanged();
+        }
+        return this;
+      }
+      /**
+       * <code>string file = 4;</code>
+       */
+      public Builder setFileBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+        filePresentCase_ = 4;
+        filePresent_ = value;
+        onChanged();
+        return this;
+      }
+
+      /**
+       * <pre>
+       * 默认tail 100行,最大不超过4MB
+       * </pre>
+       *
+       * <code>int32 count = 5;</code>
+       */
+      public int getCount() {
+        if (countPresentCase_ == 5) {
+          return (java.lang.Integer) countPresent_;
+        }
+        return 0;
+      }
+      /**
+       * <pre>
+       * 默认tail 100行,最大不超过4MB
+       * </pre>
+       *
+       * <code>int32 count = 5;</code>
+       */
+      public Builder setCount(int value) {
+        countPresentCase_ = 5;
+        countPresent_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * 默认tail 100行,最大不超过4MB
+       * </pre>
+       *
+       * <code>int32 count = 5;</code>
+       */
+      public Builder clearCount() {
+        if (countPresentCase_ == 5) {
+          countPresentCase_ = 0;
+          countPresent_ = null;
+          onChanged();
+        }
+        return this;
+      }
+      @java.lang.Override
+      public final Builder setUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.setUnknownFieldsProto3(unknownFields);
+      }
+
+      @java.lang.Override
+      public final Builder mergeUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return super.mergeUnknownFields(unknownFields);
+      }
+
+
+      // @@protoc_insertion_point(builder_scope:com.alibaba.otter.canal.protocol.LogAdmin)
+    }
+
+    // @@protoc_insertion_point(class_scope:com.alibaba.otter.canal.protocol.LogAdmin)
+    private static final com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin();
+    }
+
+    public static com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    private static final com.google.protobuf.Parser<LogAdmin>
+        PARSER = new com.google.protobuf.AbstractParser<LogAdmin>() {
+      @java.lang.Override
+      public LogAdmin parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new LogAdmin(input, extensionRegistry);
+      }
+    };
+
+    public static com.google.protobuf.Parser<LogAdmin> parser() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<LogAdmin> getParserForType() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor;
+  private static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable;
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor;
+  private static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable;
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor;
+  private static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable;
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor;
+  private static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable;
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor;
+  private static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_fieldAccessorTable;
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor;
+  private static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_fieldAccessorTable;
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor;
+  private static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_com_alibaba_otter_canal_protocol_LogAdmin_fieldAccessorTable;
+
+  public static com.google.protobuf.Descriptors.FileDescriptor
+      getDescriptor() {
+    return descriptor;
+  }
+  private static  com.google.protobuf.Descriptors.FileDescriptor
+      descriptor;
+  static {
+    java.lang.String[] descriptorData = {
+      "\n\023AdminProtocol.proto\022 com.alibaba.otter" +
+      ".canal.protocol\"\250\001\n\006Packet\022\026\n\014magic_numb" +
+      "er\030\001 \001(\005H\000\022\021\n\007version\030\002 \001(\005H\001\022:\n\004type\030\003 " +
+      "\001(\0162,.com.alibaba.otter.canal.protocol.P" +
+      "acketType\022\014\n\004body\030\004 \001(\014B\026\n\024magic_number_" +
+      "presentB\021\n\017version_present\"<\n\003Ack\022\016\n\004cod" +
+      "e\030\001 \001(\005H\000\022\017\n\007message\030\002 \001(\tB\024\n\022error_code" +
+      "_present\"^\n\tHandshake\022 \n\026communication_e" +
+      "ncoding\030\001 \001(\tH\000\022\r\n\005seeds\030\002 \001(\014B \n\036commun" +
+      "ication_encoding_present\"\242\001\n\nClientAuth\022" +
+      "\020\n\010username\030\001 \001(\t\022\020\n\010password\030\002 \001(\014\022\032\n\020n" +
+      "et_read_timeout\030\003 \001(\005H\000\022\033\n\021net_write_tim" +
+      "eout\030\004 \001(\005H\001B\032\n\030net_read_timeout_present" +
+      "B\033\n\031net_write_timeout_present\"\035\n\013ServerA" +
+      "dmin\022\016\n\006action\030\001 \001(\t\"4\n\rInstanceAdmin\022\023\n" +
+      "\013destination\030\001 \001(\t\022\016\n\006action\030\002 \001(\t\"\230\001\n\010L" +
+      "ogAdmin\022\014\n\004type\030\001 \001(\t\022\016\n\006action\030\002 \001(\t\022\025\n" +
+      "\013destination\030\003 \001(\tH\000\022\016\n\004file\030\004 \001(\tH\001\022\017\n\005" +
+      "count\030\005 \001(\005H\002B\025\n\023destination_presentB\016\n\014" +
+      "file_presentB\017\n\rcount_present*\202\001\n\nPacket" +
+      "Type\022\037\n\033PACKAGETYPECOMPATIBLEPROTO2\020\000\022\r\n" +
+      "\tHANDSHAKE\020\001\022\030\n\024CLIENTAUTHENTICATION\020\002\022\007" +
+      "\n\003ACK\020\003\022\n\n\006SERVER\020\004\022\014\n\010INSTANCE\020\005\022\007\n\003LOG" +
+      "\020\006B1\n com.alibaba.otter.canal.protocolB\013" +
+      "AdminPacketH\001b\006proto3"
+    };
+    com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
+        new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {
+          public com.google.protobuf.ExtensionRegistry assignDescriptors(
+              com.google.protobuf.Descriptors.FileDescriptor root) {
+            descriptor = root;
+            return null;
+          }
+        };
+    com.google.protobuf.Descriptors.FileDescriptor
+      .internalBuildGeneratedFileFrom(descriptorData,
+        new com.google.protobuf.Descriptors.FileDescriptor[] {
+        }, assigner);
+    internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor =
+      getDescriptor().getMessageTypes().get(0);
+    internal_static_com_alibaba_otter_canal_protocol_Packet_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_com_alibaba_otter_canal_protocol_Packet_descriptor,
+        new java.lang.String[] { "MagicNumber", "Version", "Type", "Body", "MagicNumberPresent", "VersionPresent", });
+    internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor =
+      getDescriptor().getMessageTypes().get(1);
+    internal_static_com_alibaba_otter_canal_protocol_Ack_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_com_alibaba_otter_canal_protocol_Ack_descriptor,
+        new java.lang.String[] { "Code", "Message", "ErrorCodePresent", });
+    internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor =
+      getDescriptor().getMessageTypes().get(2);
+    internal_static_com_alibaba_otter_canal_protocol_Handshake_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_com_alibaba_otter_canal_protocol_Handshake_descriptor,
+        new java.lang.String[] { "CommunicationEncoding", "Seeds", "CommunicationEncodingPresent", });
+    internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor =
+      getDescriptor().getMessageTypes().get(3);
+    internal_static_com_alibaba_otter_canal_protocol_ClientAuth_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_com_alibaba_otter_canal_protocol_ClientAuth_descriptor,
+        new java.lang.String[] { "Username", "Password", "NetReadTimeout", "NetWriteTimeout", "NetReadTimeoutPresent", "NetWriteTimeoutPresent", });
+    internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor =
+      getDescriptor().getMessageTypes().get(4);
+    internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_com_alibaba_otter_canal_protocol_ServerAdmin_descriptor,
+        new java.lang.String[] { "Action", });
+    internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor =
+      getDescriptor().getMessageTypes().get(5);
+    internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_com_alibaba_otter_canal_protocol_InstanceAdmin_descriptor,
+        new java.lang.String[] { "Destination", "Action", });
+    internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor =
+      getDescriptor().getMessageTypes().get(6);
+    internal_static_com_alibaba_otter_canal_protocol_LogAdmin_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_com_alibaba_otter_canal_protocol_LogAdmin_descriptor,
+        new java.lang.String[] { "Type", "Action", "Destination", "File", "Count", "DestinationPresent", "FilePresent", "CountPresent", });
+  }
+
+  // @@protoc_insertion_point(outer_class_scope)
+}

+ 83 - 0
protocol/src/main/java/com/alibaba/otter/canal/protocol/AdminProtocol.proto

@@ -0,0 +1,83 @@
+syntax = "proto3";
+package com.alibaba.otter.canal.protocol;
+
+option java_package = "com.alibaba.otter.canal.protocol";
+option java_outer_classname = "AdminPacket";
+option optimize_for = SPEED;
+
+enum PacketType {
+    //compatible
+    PACKAGETYPECOMPATIBLEPROTO2 = 0;
+    HANDSHAKE = 1;
+    CLIENTAUTHENTICATION = 2;
+    ACK = 3;
+    SERVER = 4;
+    INSTANCE = 5;
+    LOG = 6;
+}
+
+message Packet {
+     //[default = 17];
+     oneof magic_number_present {
+         int32 magic_number = 1;
+     }
+     // [default = 1]
+     oneof version_present {
+          int32 version = 2;
+     };
+     PacketType type = 3;
+     bytes body = 4;
+}
+
+message Ack {
+    // [default = 0]
+    oneof error_code_present {
+        int32 code = 1;
+    }
+    string message = 2; // if something like compression is not supported, erorr_message will tell about it.
+}
+
+message Handshake {
+    //  [default = "utf8"];
+    oneof communication_encoding_present {
+        string communication_encoding = 1;
+    }
+    bytes seeds = 2;
+}
+
+// client authentication
+message ClientAuth {
+    string username = 1;
+    bytes password = 2; // hashed password with seeds from Handshake message
+    // [default = 0]
+    oneof net_read_timeout_present {
+         int32 net_read_timeout = 3; // in seconds
+    }
+    // [default = 0];
+    oneof net_write_timeout_present {
+        int32 net_write_timeout = 4; // in seconds
+    }
+}
+
+message ServerAdmin {
+    string action = 1; // check/start/stop/restart/list
+}
+
+message InstanceAdmin {
+    string destination = 1;
+    string action = 2; // check/start/stop/reload
+}
+
+message LogAdmin {
+	string type = 1; // canal/instance
+	string action = 2;
+	oneof destination_present {
+		string destination = 3;
+	}
+	oneof file_present {
+		string file = 4;
+	}
+	oneof count_present {
+		int32 count = 5; // 默认tail 100行,最大不超过4MB
+	}
+}

+ 5 - 5
protocol/src/main/java/com/alibaba/otter/canal/protocol/CanalPacket.java

@@ -630,7 +630,7 @@ public final class CanalPacket {
       if (versionPresentCase_ == 2) {
         return (java.lang.Integer) versionPresent_;
       }
-      return 1;
+      return 0;
     }
 
     public static final int TYPE_FIELD_NUMBER = 3;
@@ -658,7 +658,7 @@ public final class CanalPacket {
       if (compressionPresentCase_ == 4) {
         return (java.lang.Integer) compressionPresent_;
       }
-      return Compression.NONE_VALUE;
+      return 0;
     }
     /**
      * <code>.com.alibaba.otter.canal.protocol.Compression compression = 4;</code>
@@ -1180,7 +1180,7 @@ public final class CanalPacket {
         if (magicNumberPresentCase_ == 1) {
           return (java.lang.Integer) magicNumberPresent_;
         }
-        return 17;
+        return 0;
       }
       /**
        * <code>int32 magic_number = 1;</code>
@@ -7731,7 +7731,7 @@ public final class CanalPacket {
       if (timeoutPresentCase_ == 4) {
         return (java.lang.Long) timeoutPresent_;
       }
-      return -1L;
+      return 0L;
     }
 
     public static final int UNIT_FIELD_NUMBER = 5;
@@ -7746,7 +7746,7 @@ public final class CanalPacket {
       if (unitPresentCase_ == 5) {
         return (java.lang.Integer) unitPresent_;
       }
-      return 2;
+      return 0;
     }
 
     public static final int AUTO_ACK_FIELD_NUMBER = 6;

+ 223 - 0
protocol/src/main/java/com/alibaba/otter/canal/protocol/SecurityUtil.java

@@ -0,0 +1,223 @@
+package com.alibaba.otter.canal.protocol;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/**
+ * <pre>
+ * 1、client
+ *    stage1_hash = SHA1(明文密码).
+ *    token = SHA1(scramble + SHA1(stage1_hash)) XOR stage1_hash
+ * 2. server
+ *    token = SHA1(token XOR SHA1(scramble + password))
+ * 3. checktoken vs password
+ * </pre>
+ * 
+ * @author agapple 2019年8月26日 下午4:58:15
+ * @since 1.1.4
+ */
+public class SecurityUtil {
+
+    public static final String scrambleGenPass(byte[] pass) throws NoSuchAlgorithmException {
+        MessageDigest md = MessageDigest.getInstance("SHA-1");
+        byte[] pass1 = md.digest(pass);
+        md.reset();
+        byte[] pass2 = md.digest(pass1);
+        return SecurityUtil.byte2HexStr(pass2);
+    }
+
+    /**
+     * server auth check
+     */
+    public static final boolean scrambleServerAuth(byte[] token, byte[] pass, byte[] seed)
+                                                                                          throws NoSuchAlgorithmException {
+        MessageDigest md = MessageDigest.getInstance("SHA-1");
+        md.update(seed);
+        byte[] pass1 = md.digest(pass);
+        for (int i = 0; i < pass1.length; i++) {
+            pass1[i] = (byte) (token[i] ^ pass1[i]);
+        }
+
+        md = MessageDigest.getInstance("SHA-1");
+        byte[] pass2 = md.digest(pass1);
+        return Arrays.equals(pass, pass2);
+    }
+
+    public static final byte[] scramble411(byte[] pass, byte[] seed) throws NoSuchAlgorithmException {
+        MessageDigest md = MessageDigest.getInstance("SHA-1");
+        byte[] pass1 = md.digest(pass);
+        md.reset();
+        byte[] pass2 = md.digest(pass1);
+        md.reset();
+        md.update(seed);
+        byte[] pass3 = md.digest(pass2);
+        for (int i = 0; i < pass3.length; i++) {
+            pass3[i] = (byte) (pass3[i] ^ pass1[i]);
+        }
+        return pass3;
+    }
+
+    /**
+     * bytes转换成十六进制字符串
+     */
+    public static String byte2HexStr(byte[] b) {
+        StringBuilder hs = new StringBuilder();
+        for (int n = 0; n < b.length; n++) {
+            String hex = (Integer.toHexString(b[n] & 0XFF));
+            if (hex.length() == 1) {
+                hs.append("0" + hex);
+            } else {
+                hs.append(hex);
+            }
+        }
+
+        return hs.toString();
+    }
+
+    /**
+     * bytes转换成十六进制字符串
+     */
+    public static byte[] hexStr2Bytes(String src) {
+        if (src == null) {
+            return null;
+        }
+        int offset = 0;
+        int length = src.length();
+        if (length == 0) {
+            return new byte[0];
+        }
+
+        boolean odd = length << 31 == Integer.MIN_VALUE;
+        byte[] bs = new byte[odd ? (length + 1) >> 1 : length >> 1];
+        for (int i = offset, limit = offset + length; i < limit; ++i) {
+            char high, low;
+            if (i == offset && odd) {
+                high = '0';
+                low = src.charAt(i);
+            } else {
+                high = src.charAt(i);
+                low = src.charAt(++i);
+            }
+            int b;
+            switch (high) {
+                case '0':
+                    b = 0;
+                    break;
+                case '1':
+                    b = 0x10;
+                    break;
+                case '2':
+                    b = 0x20;
+                    break;
+                case '3':
+                    b = 0x30;
+                    break;
+                case '4':
+                    b = 0x40;
+                    break;
+                case '5':
+                    b = 0x50;
+                    break;
+                case '6':
+                    b = 0x60;
+                    break;
+                case '7':
+                    b = 0x70;
+                    break;
+                case '8':
+                    b = 0x80;
+                    break;
+                case '9':
+                    b = 0x90;
+                    break;
+                case 'a':
+                case 'A':
+                    b = 0xa0;
+                    break;
+                case 'b':
+                case 'B':
+                    b = 0xb0;
+                    break;
+                case 'c':
+                case 'C':
+                    b = 0xc0;
+                    break;
+                case 'd':
+                case 'D':
+                    b = 0xd0;
+                    break;
+                case 'e':
+                case 'E':
+                    b = 0xe0;
+                    break;
+                case 'f':
+                case 'F':
+                    b = 0xf0;
+                    break;
+                default:
+                    throw new IllegalArgumentException("illegal hex-string: " + src);
+            }
+            switch (low) {
+                case '0':
+                    break;
+                case '1':
+                    b += 1;
+                    break;
+                case '2':
+                    b += 2;
+                    break;
+                case '3':
+                    b += 3;
+                    break;
+                case '4':
+                    b += 4;
+                    break;
+                case '5':
+                    b += 5;
+                    break;
+                case '6':
+                    b += 6;
+                    break;
+                case '7':
+                    b += 7;
+                    break;
+                case '8':
+                    b += 8;
+                    break;
+                case '9':
+                    b += 9;
+                    break;
+                case 'a':
+                case 'A':
+                    b += 10;
+                    break;
+                case 'b':
+                case 'B':
+                    b += 11;
+                    break;
+                case 'c':
+                case 'C':
+                    b += 12;
+                    break;
+                case 'd':
+                case 'D':
+                    b += 13;
+                    break;
+                case 'e':
+                case 'E':
+                    b += 14;
+                    break;
+                case 'f':
+                case 'F':
+                    b += 15;
+                    break;
+                default:
+                    throw new IllegalArgumentException("illegal hex-string: " + src);
+            }
+            bs[(i - offset) >> 1] = (byte) b;
+        }
+        return bs;
+    }
+
+}

+ 39 - 19
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/jmx/CanalServerMXBean.java → server/src/main/java/com/alibaba/otter/canal/admin/CanalAdmin.java

@@ -1,19 +1,24 @@
-package com.alibaba.otter.canal.admin.jmx;
+package com.alibaba.otter.canal.admin;
 
 /**
- * Canal Server JMX MBean
- *
- * @author rewerma 2019-07-13 下午05:12:16
- * @version 1.0.0
+ * Canal Admin动态管理接口
+ * 
+ * @author agapple 2019年8月24日 下午9:45:49
+ * @since 1.1.4
  */
-public interface CanalServerMXBean {
+public interface CanalAdmin {
 
     /**
-     * 获取Canal Server状态
+     * 校验账号密码
+     */
+    boolean auth(String user, String passwd, byte[] seed);
+
+    /**
+     * 获取Canal Server状态, 1代表运行/0代表不运行
      *
      * @return 状态代码
      */
-    int getStatus();
+    boolean check();
 
     /**
      * 启动Canal Server
@@ -37,11 +42,19 @@ public interface CanalServerMXBean {
     boolean restart();
 
     /**
-     * 退出Canal Server(关闭进程)
+     * 获取所有当前节点下运行中的实例
      *
-     * @return 是否成功
+     * @return 实例信息
      */
-    boolean exit();
+    String getRunningInstances();
+
+    /**
+     * 通过实例名检查
+     * 
+     * @param destination
+     * @return
+     */
+    boolean checkInstance(String destination);
 
     /**
      * 通过实例名启动实例
@@ -65,26 +78,33 @@ public interface CanalServerMXBean {
      * @param destination 实例名
      * @return 是否成功
      */
-    boolean reloadInstance(String destination);
+    boolean restartInstance(String destination);
 
     /**
-     * 获取所有当前节点下运行中的实例
+     * 获取Canal Server日志列表
      *
-     * @return 实例信息
+     * @return 日志信息
      */
-    String getRunningInstances();
+    String listCanalLog();
 
     /**
-     * 获取Canal Server日志(末尾100行)
+     * 获取Canal Server日志
      *
      * @return 日志信息
      */
-    String canalLog();
+    String canalLog(int lines);
+
+    /**
+     * 获取Instance的机器日志列表
+     * 
+     * @param destination
+     */
+    String listInstanceLog(String destination);
 
     /**
-     * 通过实例名获取实例日志(末尾100行)
+     * 通过实例名获取实例日志
      *
      * @return 日志信息
      */
-    String instanceLog(String destination);
+    String instanceLog(String destination, String fileName, int lines);
 }

+ 119 - 0
server/src/main/java/com/alibaba/otter/canal/admin/handler/ClientAuthenticationHandler.java

@@ -0,0 +1,119 @@
+package com.alibaba.otter.canal.admin.handler;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.ChannelFuture;
+import org.jboss.netty.channel.ChannelFutureListener;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.channel.SimpleChannelHandler;
+import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
+import org.jboss.netty.handler.timeout.IdleStateEvent;
+import org.jboss.netty.handler.timeout.IdleStateHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.helpers.MessageFormatter;
+
+import com.alibaba.otter.canal.admin.CanalAdmin;
+import com.alibaba.otter.canal.admin.netty.AdminNettyUtils;
+import com.alibaba.otter.canal.protocol.AdminPacket.ClientAuth;
+import com.alibaba.otter.canal.protocol.AdminPacket.Packet;
+import com.alibaba.otter.canal.server.netty.NettyUtils;
+
+/**
+ * 客户端身份认证处理
+ * 
+ * @author agapple 2019年8月24日 下午10:58:53
+ * @since 1.1.4
+ */
+public class ClientAuthenticationHandler extends SimpleChannelHandler {
+
+    private static final Logger logger                                  = LoggerFactory.getLogger(ClientAuthenticationHandler.class);
+    private final int           SUPPORTED_VERSION                       = 3;
+    private final int           defaultSubscriptorDisconnectIdleTimeout = 60 * 60 * 1000;
+    private CanalAdmin          canalAdmin;
+    private byte[]              seed;
+
+    public ClientAuthenticationHandler(){
+
+    }
+
+    public ClientAuthenticationHandler(CanalAdmin canalAdmin){
+        this.canalAdmin = canalAdmin;
+    }
+
+    public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
+        final Packet packet = Packet.parseFrom(buffer.readBytes(buffer.readableBytes()).array());
+        switch (packet.getVersion()) {
+            case SUPPORTED_VERSION:
+            default:
+                final ClientAuth clientAuth = ClientAuth.parseFrom(packet.getBody());
+                if (seed == null) {
+                    byte[] errorBytes = AdminNettyUtils.errorPacket(300,
+                        MessageFormatter.format("auth failed for seed is null", clientAuth.getUsername()).getMessage());
+                    AdminNettyUtils.write(ctx.getChannel(), errorBytes);
+                }
+
+                if (!canalAdmin.auth(clientAuth.getUsername(), clientAuth.getPassword().toStringUtf8(), seed)) {
+                    byte[] errorBytes = AdminNettyUtils.errorPacket(300,
+                        MessageFormatter.format("auth failed for user:{}", clientAuth.getUsername()).getMessage());
+                    AdminNettyUtils.write(ctx.getChannel(), errorBytes);
+                }
+
+                byte[] ackBytes = AdminNettyUtils.ackPacket();
+                AdminNettyUtils.write(ctx.getChannel(), ackBytes, new ChannelFutureListener() {
+
+                    public void operationComplete(ChannelFuture future) throws Exception {
+                        logger.info("remove unused channel handlers after authentication is done successfully.");
+                        ctx.getPipeline().remove(HandshakeInitializationHandler.class.getName());
+                        ctx.getPipeline().remove(ClientAuthenticationHandler.class.getName());
+
+                        int readTimeout = defaultSubscriptorDisconnectIdleTimeout;
+                        int writeTimeout = defaultSubscriptorDisconnectIdleTimeout;
+                        if (clientAuth.getNetReadTimeout() > 0) {
+                            readTimeout = clientAuth.getNetReadTimeout();
+                        }
+                        if (clientAuth.getNetWriteTimeout() > 0) {
+                            writeTimeout = clientAuth.getNetWriteTimeout();
+                        }
+                        // fix bug: soTimeout parameter's unit from connector is
+                        // millseconds.
+                        IdleStateHandler idleStateHandler = new IdleStateHandler(NettyUtils.hashedWheelTimer,
+                            readTimeout,
+                            writeTimeout,
+                            0,
+                            TimeUnit.MILLISECONDS);
+                        ctx.getPipeline().addBefore(SessionHandler.class.getName(),
+                            IdleStateHandler.class.getName(),
+                            idleStateHandler);
+
+                        IdleStateAwareChannelHandler idleStateAwareChannelHandler = new IdleStateAwareChannelHandler() {
+
+                            public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {
+                                logger.warn("channel:{} idle timeout exceeds, close channel to save server resources...",
+                                    ctx.getChannel());
+                                ctx.getChannel().close();
+                            }
+
+                        };
+                        ctx.getPipeline().addBefore(SessionHandler.class.getName(),
+                            IdleStateAwareChannelHandler.class.getName(),
+                            idleStateAwareChannelHandler);
+                    }
+
+                });
+                break;
+        }
+    }
+
+    public void setCanalAdmin(CanalAdmin canalAdmin) {
+        this.canalAdmin = canalAdmin;
+    }
+
+    public void setSeed(byte[] seed) {
+        this.seed = seed;
+    }
+
+}

+ 62 - 0
server/src/main/java/com/alibaba/otter/canal/admin/handler/HandshakeInitializationHandler.java

@@ -0,0 +1,62 @@
+package com.alibaba.otter.canal.admin.handler;
+
+import org.jboss.netty.channel.ChannelFuture;
+import org.jboss.netty.channel.ChannelFutureListener;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.SimpleChannelHandler;
+import org.jboss.netty.channel.group.ChannelGroup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.alibaba.otter.canal.admin.netty.AdminNettyUtils;
+import com.alibaba.otter.canal.protocol.AdminPacket;
+import com.alibaba.otter.canal.protocol.AdminPacket.Handshake;
+import com.alibaba.otter.canal.protocol.AdminPacket.Packet;
+import com.google.protobuf.ByteString;
+
+/**
+ * handshake交互
+ * 
+ * @author agapple 2019年8月24日 下午10:58:34
+ * @since 1.1.4
+ */
+public class HandshakeInitializationHandler extends SimpleChannelHandler {
+
+    // support to maintain socket channel.
+    private ChannelGroup childGroups;
+
+    public HandshakeInitializationHandler(ChannelGroup childGroups){
+        this.childGroups = childGroups;
+    }
+
+    private static final Logger logger = LoggerFactory.getLogger(HandshakeInitializationHandler.class);
+
+    public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
+        // add new socket channel in channel container, used to manage sockets.
+        if (childGroups != null) {
+            childGroups.add(ctx.getChannel());
+        }
+
+        final byte[] seed = org.apache.commons.lang3.RandomUtils.nextBytes(8);
+        byte[] body = Packet.newBuilder()
+            .setType(AdminPacket.PacketType.HANDSHAKE)
+            .setVersion(AdminNettyUtils.VERSION)
+            .setBody(Handshake.newBuilder().setSeeds(ByteString.copyFrom(seed)).build().toByteString())
+            .build()
+            .toByteArray();
+
+        AdminNettyUtils.write(ctx.getChannel(), body, new ChannelFutureListener() {
+
+            public void operationComplete(ChannelFuture future) throws Exception {
+                logger.info("remove unused channel handlers after authentication is done successfully.");
+                ctx.getPipeline().get(HandshakeInitializationHandler.class.getName());
+                ClientAuthenticationHandler handler = (ClientAuthenticationHandler) ctx.getPipeline()
+                    .get(ClientAuthenticationHandler.class.getName());
+                handler.setSeed(seed);
+            }
+
+        });
+        logger.info("send handshake initialization packet to : {}", ctx.getChannel());
+    }
+}

+ 154 - 0
server/src/main/java/com/alibaba/otter/canal/admin/handler/SessionHandler.java

@@ -0,0 +1,154 @@
+package com.alibaba.otter.canal.admin.handler;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.ExceptionEvent;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.channel.SimpleChannelHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.helpers.MessageFormatter;
+
+import com.alibaba.otter.canal.admin.CanalAdmin;
+import com.alibaba.otter.canal.admin.netty.AdminNettyUtils;
+import com.alibaba.otter.canal.protocol.AdminPacket.InstanceAdmin;
+import com.alibaba.otter.canal.protocol.AdminPacket.LogAdmin;
+import com.alibaba.otter.canal.protocol.AdminPacket.Packet;
+import com.alibaba.otter.canal.protocol.AdminPacket.ServerAdmin;
+
+public class SessionHandler extends SimpleChannelHandler {
+
+    private static final Logger logger = LoggerFactory.getLogger(SessionHandler.class);
+    private CanalAdmin          canalAdmin;
+
+    public SessionHandler(){
+    }
+
+    public SessionHandler(CanalAdmin canalAdmin){
+        this.canalAdmin = canalAdmin;
+    }
+
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        logger.info("message receives in session handler...");
+        ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
+        Packet packet = Packet.parseFrom(buffer.readBytes(buffer.readableBytes()).array());
+        try {
+            String action = null;
+            String message = null;
+            String destination = null;
+            switch (packet.getType()) {
+                case SERVER:
+                    ServerAdmin serverAdmin = ServerAdmin.parseFrom(packet.getBody());
+                    action = serverAdmin.getAction();
+                    switch (action) {
+                        case "check":
+                            message = canalAdmin.check() ? "1" : "0";
+                            break;
+                        case "start":
+                            message = canalAdmin.start() ? "1" : "0";
+                            break;
+                        case "stop":
+                            message = canalAdmin.stop() ? "1" : "0";
+                            break;
+                        case "restart":
+                            message = canalAdmin.restart() ? "1" : "0";
+                            break;
+                        case "list":
+                            message = canalAdmin.getRunningInstances();
+                            break;
+                        default:
+                            byte[] errorBytes = AdminNettyUtils.errorPacket(301,
+                                MessageFormatter.format("ServerAdmin action={} is unknown", action).getMessage());
+                            AdminNettyUtils.write(ctx.getChannel(), errorBytes);
+                            break;
+                    }
+                    AdminNettyUtils.write(ctx.getChannel(), AdminNettyUtils.ackPacket(message));
+                    break;
+                case INSTANCE:
+                    InstanceAdmin instanceAdmin = InstanceAdmin.parseFrom(packet.getBody());
+                    destination = instanceAdmin.getDestination();
+                    action = instanceAdmin.getAction();
+                    switch (action) {
+                        case "check":
+                            message = canalAdmin.checkInstance(destination) ? "1" : "0";
+                            break;
+                        case "start":
+                            message = canalAdmin.startInstance(destination) ? "1" : "0";
+                            break;
+                        case "stop":
+                            message = canalAdmin.stopInstance(destination) ? "1" : "0";
+                            break;
+                        case "restart":
+                            message = canalAdmin.restartInstance(destination) ? "1" : "0";
+                            break;
+                        default:
+                            byte[] errorBytes = AdminNettyUtils.errorPacket(301,
+                                MessageFormatter.format("InstanceAdmin action={} is unknown", action).getMessage());
+                            AdminNettyUtils.write(ctx.getChannel(), errorBytes);
+                            break;
+                    }
+                    AdminNettyUtils.write(ctx.getChannel(), AdminNettyUtils.ackPacket(message));
+                    break;
+                case LOG:
+                    LogAdmin logAdmin = LogAdmin.parseFrom(packet.getBody());
+                    action = logAdmin.getAction();
+                    destination = logAdmin.getDestination();
+                    String type = logAdmin.getType();
+                    String file = logAdmin.getFile();
+                    int count = logAdmin.getCount();
+                    switch (type) {
+                        case "server":
+                            if ("list".equalsIgnoreCase(action)) {
+                                message = canalAdmin.listCanalLog();
+                            } else {
+                                message = canalAdmin.canalLog(count);
+                            }
+                            break;
+                        case "instance":
+                            if ("list".equalsIgnoreCase(action)) {
+                                message = canalAdmin.listInstanceLog(destination);
+                            } else {
+                                message = canalAdmin.instanceLog(destination, file, count);
+                            }
+                            break;
+                        default:
+                            byte[] errorBytes = AdminNettyUtils.errorPacket(301,
+                                MessageFormatter.format("LogAdmin type={} is unknown", type).getMessage());
+                            AdminNettyUtils.write(ctx.getChannel(), errorBytes);
+                            break;
+                    }
+                    AdminNettyUtils.write(ctx.getChannel(), AdminNettyUtils.ackPacket(message));
+                    break;
+                default:
+                    byte[] errorBytes = AdminNettyUtils.errorPacket(300,
+                        MessageFormatter.format("packet type={} is NOT supported!", packet.getType()).getMessage());
+                    AdminNettyUtils.write(ctx.getChannel(), errorBytes);
+                    break;
+            }
+        } catch (Throwable exception) {
+            byte[] errorBytes = AdminNettyUtils.errorPacket(400,
+                MessageFormatter.format("something goes wrong with channel:{}, exception={}",
+                    ctx.getChannel(),
+                    ExceptionUtils.getStackTrace(exception)).getMessage());
+            AdminNettyUtils.write(ctx.getChannel(), errorBytes);
+        }
+    }
+
+    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
+        logger.error("something goes wrong with channel:{}, exception={}",
+            ctx.getChannel(),
+            ExceptionUtils.getStackTrace(e.getCause()));
+
+        ctx.getChannel().close();
+    }
+
+    public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
+    }
+
+    public void setCanalAdmin(CanalAdmin canalAdmin) {
+        this.canalAdmin = canalAdmin;
+    }
+
+}

+ 63 - 0
server/src/main/java/com/alibaba/otter/canal/admin/netty/AdminNettyUtils.java

@@ -0,0 +1,63 @@
+package com.alibaba.otter.canal.admin.netty;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.buffer.CompositeChannelBuffer;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelFutureListener;
+import org.jboss.netty.channel.Channels;
+
+import com.alibaba.otter.canal.protocol.AdminPacket;
+import com.alibaba.otter.canal.protocol.AdminPacket.Ack;
+import com.alibaba.otter.canal.protocol.AdminPacket.Packet;
+
+public class AdminNettyUtils {
+
+    public static int HEADER_LENGTH = 4;
+    public static int VERSION       = 1;
+
+    public static void write(Channel channel, ByteBuffer body) {
+        byte[] header = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN).putInt(body.limit()).array();
+        List<ChannelBuffer> components = new ArrayList<ChannelBuffer>(2);
+        components.add(ChannelBuffers.wrappedBuffer(ByteOrder.BIG_ENDIAN, header));
+        components.add(ChannelBuffers.wrappedBuffer(body));
+        Channels.write(channel, new CompositeChannelBuffer(ByteOrder.BIG_ENDIAN, components));
+    }
+
+    public static void write(Channel channel, byte[] body) {
+        byte[] header = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN).putInt(body.length).array();
+        Channels.write(channel, ChannelBuffers.wrappedBuffer(header, body));
+    }
+
+    public static void write(Channel channel, byte[] body, ChannelFutureListener channelFutureListner) {
+        byte[] header = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN).putInt(body.length).array();
+        Channels.write(channel, ChannelBuffers.wrappedBuffer(header, body)).addListener(channelFutureListner);
+    }
+
+    public static byte[] ackPacket() {
+        return ackPacket(null);
+    }
+
+    public static byte[] ackPacket(String message) {
+        return Packet.newBuilder()
+            .setType(AdminPacket.PacketType.ACK)
+            .setVersion(VERSION)
+            .setBody(Ack.newBuilder().setCode(0).setMessage(message == null ? "" : message).build().toByteString())
+            .build()
+            .toByteArray();
+    }
+
+    public static byte[] errorPacket(int errorCode, String errorMessage) {
+        return Packet.newBuilder()
+            .setType(AdminPacket.PacketType.ACK)
+            .setVersion(VERSION)
+            .setBody(Ack.newBuilder().setCode(errorCode).setMessage(errorMessage).build().toByteString())
+            .build()
+            .toByteArray();
+    }
+}

+ 127 - 0
server/src/main/java/com/alibaba/otter/canal/admin/netty/CanalAdminWithNetty.java

@@ -0,0 +1,127 @@
+package com.alibaba.otter.canal.admin.netty;
+
+import java.net.InetSocketAddress;
+import java.util.concurrent.Executors;
+
+import org.apache.commons.lang.StringUtils;
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.channel.ChannelPipelineFactory;
+import org.jboss.netty.channel.Channels;
+import org.jboss.netty.channel.group.ChannelGroup;
+import org.jboss.netty.channel.group.DefaultChannelGroup;
+import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
+
+import com.alibaba.otter.canal.admin.CanalAdmin;
+import com.alibaba.otter.canal.admin.handler.ClientAuthenticationHandler;
+import com.alibaba.otter.canal.admin.handler.HandshakeInitializationHandler;
+import com.alibaba.otter.canal.admin.handler.SessionHandler;
+import com.alibaba.otter.canal.common.AbstractCanalLifeCycle;
+import com.alibaba.otter.canal.server.netty.handler.FixedHeaderFrameDecoder;
+
+/**
+ * 基于netty网络服务的server实现
+ * 
+ * @author jianghang 2012-7-12 下午01:34:49
+ * @version 1.0.0
+ */
+public class CanalAdminWithNetty extends AbstractCanalLifeCycle {
+
+    private String          ip;
+    private int             port;
+    private Channel         serverChannel = null;
+    private ServerBootstrap bootstrap     = null;
+    private ChannelGroup    childGroups   = null; // socket channel
+                                                  // container, used to
+                                                  // close sockets
+                                                  // explicitly.
+    private CanalAdmin      canalAdmin;
+
+    private static class SingletonHolder {
+
+        private static final CanalAdminWithNetty CANAL_ADMIN_WITH_NETTY = new CanalAdminWithNetty();
+    }
+
+    private CanalAdminWithNetty(){
+        this.childGroups = new DefaultChannelGroup();
+    }
+
+    public static CanalAdminWithNetty instance() {
+        return SingletonHolder.CANAL_ADMIN_WITH_NETTY;
+    }
+
+    public void start() {
+        super.start();
+
+        this.bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),
+            Executors.newCachedThreadPool()));
+        /*
+         * enable keep-alive mechanism, handle abnormal network connection
+         * scenarios on OS level. the threshold parameters are depended on OS.
+         * e.g. On Linux: net.ipv4.tcp_keepalive_time = 300
+         * net.ipv4.tcp_keepalive_probes = 2 net.ipv4.tcp_keepalive_intvl = 30
+         */
+        bootstrap.setOption("child.keepAlive", true);
+        /*
+         * optional parameter.
+         */
+        bootstrap.setOption("child.tcpNoDelay", true);
+
+        // 构造对应的pipeline
+        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
+
+            public ChannelPipeline getPipeline() throws Exception {
+                ChannelPipeline pipelines = Channels.pipeline();
+                pipelines.addLast(FixedHeaderFrameDecoder.class.getName(), new FixedHeaderFrameDecoder());
+                // support to maintain child socket channel.
+                pipelines.addLast(HandshakeInitializationHandler.class.getName(),
+                    new HandshakeInitializationHandler(childGroups));
+                pipelines.addLast(ClientAuthenticationHandler.class.getName(),
+                    new ClientAuthenticationHandler(canalAdmin));
+
+                SessionHandler sessionHandler = new SessionHandler(canalAdmin);
+                pipelines.addLast(SessionHandler.class.getName(), sessionHandler);
+                return pipelines;
+            }
+        });
+
+        // 启动
+        if (StringUtils.isNotEmpty(ip)) {
+            this.serverChannel = bootstrap.bind(new InetSocketAddress(this.ip, this.port));
+        } else {
+            this.serverChannel = bootstrap.bind(new InetSocketAddress(this.port));
+        }
+    }
+
+    public void stop() {
+        super.stop();
+
+        if (this.serverChannel != null) {
+            this.serverChannel.close().awaitUninterruptibly(1000);
+        }
+
+        // close sockets explicitly to reduce socket channel hung in complicated
+        // network environment.
+        if (this.childGroups != null) {
+            this.childGroups.close().awaitUninterruptibly(5000);
+        }
+
+        if (this.bootstrap != null) {
+            this.bootstrap.releaseExternalResources();
+        }
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public void setCanalAdmin(CanalAdmin canalAdmin) {
+        this.canalAdmin = canalAdmin;
+    }
+
+}

+ 2 - 0
server/src/main/java/com/alibaba/otter/canal/common/CanalMessageSerializer.java

@@ -9,6 +9,7 @@ import com.alibaba.otter.canal.protocol.CanalEntry;
 import com.alibaba.otter.canal.protocol.CanalPacket;
 import com.alibaba.otter.canal.protocol.CanalPacket.PacketType;
 import com.alibaba.otter.canal.protocol.Message;
+import com.alibaba.otter.canal.server.netty.NettyUtils;
 import com.google.protobuf.ByteString;
 import com.google.protobuf.CodedOutputStream;
 import com.google.protobuf.WireFormat;
@@ -66,6 +67,7 @@ public class CanalMessageSerializer {
 
                         CanalPacket.Packet.Builder packetBuilder = CanalPacket.Packet.newBuilder();
                         packetBuilder.setType(PacketType.MESSAGES);
+                        packetBuilder.setVersion(NettyUtils.VERSION);
                         packetBuilder.setBody(messageBuilder.build().toByteString());
                         return packetBuilder.build().toByteArray();
                     }

+ 35 - 0
server/src/main/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded.java

@@ -1,12 +1,15 @@
 package com.alibaba.otter.canal.server.embedded;
 
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.ServiceLoader;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
@@ -18,6 +21,7 @@ import com.alibaba.otter.canal.instance.core.CanalInstanceGenerator;
 import com.alibaba.otter.canal.protocol.CanalEntry;
 import com.alibaba.otter.canal.protocol.ClientIdentity;
 import com.alibaba.otter.canal.protocol.Message;
+import com.alibaba.otter.canal.protocol.SecurityUtil;
 import com.alibaba.otter.canal.protocol.position.LogPosition;
 import com.alibaba.otter.canal.protocol.position.Position;
 import com.alibaba.otter.canal.protocol.position.PositionRange;
@@ -52,6 +56,8 @@ public class CanalServerWithEmbedded extends AbstractCanalLifeCycle implements C
     private CanalInstanceGenerator     canalInstanceGenerator;
     private int                        metricsPort;
     private CanalMetricsService        metrics = NopCanalMetricsService.NOP;
+    private String                     user;
+    private String                     passwd;
 
     private static class SingletonHolder {
 
@@ -106,6 +112,27 @@ public class CanalServerWithEmbedded extends AbstractCanalLifeCycle implements C
         metrics.terminate();
     }
 
+    public boolean auth(String user, String passwd, byte[] seed) {
+        // 如果user/passwd密码为空,则任何用户账户都能登录
+        if ((StringUtils.isEmpty(this.user) || StringUtils.equals(this.user, user))) {
+            if (StringUtils.isEmpty(this.passwd)) {
+                return true;
+            } else if (StringUtils.isEmpty(passwd)) {
+                // 如果server密码有配置,客户端密码为空,则拒绝
+                return false;
+            }
+
+            try {
+                byte[] passForClient = SecurityUtil.hexStr2Bytes(passwd);
+                return SecurityUtil.scrambleServerAuth(passForClient, SecurityUtil.hexStr2Bytes(this.passwd), seed);
+            } catch (NoSuchAlgorithmException e) {
+                return false;
+            }
+        }
+
+        return false;
+    }
+
     public void start(final String destination) {
         final CanalInstance canalInstance = canalInstances.get(destination);
         if (!canalInstance.isStart()) {
@@ -572,4 +599,12 @@ public class CanalServerWithEmbedded extends AbstractCanalLifeCycle implements C
         this.metricsPort = metricsPort;
     }
 
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public void setPasswd(String passwd) {
+        this.passwd = passwd;
+    }
+
 }

+ 13 - 8
server/src/main/java/com/alibaba/otter/canal/server/netty/NettyUtils.java

@@ -25,6 +25,7 @@ public class NettyUtils {
     private static final Logger logger           = LoggerFactory.getLogger(NettyUtils.class);
     public static int           HEADER_LENGTH    = 4;
     public static Timer         hashedWheelTimer = new HashedWheelTimer();
+    public static int           VERSION          = 1;
 
     public static void write(Channel channel, ByteBuffer body, ChannelFutureListener channelFutureListner) {
         byte[] header = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN).putInt(body.limit()).array();
@@ -53,6 +54,7 @@ public class NettyUtils {
         write(channel,
             Packet.newBuilder()
                 .setType(CanalPacket.PacketType.ACK)
+                .setVersion(VERSION)
                 .setBody(Ack.newBuilder().build().toByteString())
                 .build()
                 .toByteArray(),
@@ -69,6 +71,7 @@ public class NettyUtils {
         write(channel,
             Packet.newBuilder()
                 .setType(CanalPacket.PacketType.ACK)
+                .setVersion(VERSION)
                 .setBody(Ack.newBuilder().setErrorCode(errorCode).setErrorMessage(errorMessage).build().toByteString())
                 .build()
                 .toByteArray(),
@@ -77,17 +80,19 @@ public class NettyUtils {
 
     public static byte[] ackPacket() {
         return Packet.newBuilder()
-                .setType(CanalPacket.PacketType.ACK)
-                .setBody(Ack.newBuilder().build().toByteString())
-                .build()
-                .toByteArray();
+            .setType(CanalPacket.PacketType.ACK)
+            .setVersion(VERSION)
+            .setBody(Ack.newBuilder().build().toByteString())
+            .build()
+            .toByteArray();
     }
 
     public static byte[] errorPacket(int errorCode, String errorMessage) {
         return Packet.newBuilder()
-                .setType(CanalPacket.PacketType.ACK)
-                .setBody(Ack.newBuilder().setErrorCode(errorCode).setErrorMessage(errorMessage).build().toByteString())
-                .build()
-                .toByteArray();
+            .setType(CanalPacket.PacketType.ACK)
+            .setVersion(VERSION)
+            .setBody(Ack.newBuilder().setErrorCode(errorCode).setErrorMessage(errorMessage).build().toByteString())
+            .build()
+            .toByteArray();
     }
 }

+ 18 - 1
server/src/main/java/com/alibaba/otter/canal/server/netty/handler/ClientAuthenticationHandler.java

@@ -15,6 +15,7 @@ import org.jboss.netty.handler.timeout.IdleStateHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
+import org.slf4j.helpers.MessageFormatter;
 
 import com.alibaba.otter.canal.common.zookeeper.running.ServerRunningMonitor;
 import com.alibaba.otter.canal.common.zookeeper.running.ServerRunningMonitors;
@@ -36,6 +37,7 @@ public class ClientAuthenticationHandler extends SimpleChannelHandler {
     private final int               SUPPORTED_VERSION                       = 3;
     private final int               defaultSubscriptorDisconnectIdleTimeout = 60 * 60 * 1000;
     private CanalServerWithEmbedded embeddedServer;
+    private byte[]                  seed;
 
     public ClientAuthenticationHandler(){
 
@@ -52,6 +54,18 @@ public class ClientAuthenticationHandler extends SimpleChannelHandler {
             case SUPPORTED_VERSION:
             default:
                 final ClientAuth clientAuth = ClientAuth.parseFrom(packet.getBody());
+                if (seed == null) {
+                    byte[] errorBytes = NettyUtils.errorPacket(400,
+                        MessageFormatter.format("auth failed for seed is null", clientAuth.getUsername()).getMessage());
+                    NettyUtils.write(ctx.getChannel(), errorBytes, null);
+                }
+
+                if (!embeddedServer.auth(clientAuth.getUsername(), clientAuth.getPassword().toStringUtf8(), seed)) {
+                    byte[] errorBytes = NettyUtils.errorPacket(400,
+                        MessageFormatter.format("auth failed for user:{}", clientAuth.getUsername()).getMessage());
+                    NettyUtils.write(ctx.getChannel(), errorBytes, null);
+                }
+
                 // 如果存在订阅信息
                 if (StringUtils.isNotEmpty(clientAuth.getDestination())
                     && StringUtils.isNotEmpty(clientAuth.getClientId())) {
@@ -61,7 +75,6 @@ public class ClientAuthenticationHandler extends SimpleChannelHandler {
                     try {
                         MDC.put("destination", clientIdentity.getDestination());
                         embeddedServer.subscribe(clientIdentity);
-                        ctx.setAttachment(clientIdentity);// 设置状态数据
                         // 尝试启动,如果已经启动,忽略
                         if (!embeddedServer.isStart(clientIdentity.getDestination())) {
                             ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(clientIdentity.getDestination());
@@ -123,4 +136,8 @@ public class ClientAuthenticationHandler extends SimpleChannelHandler {
         this.embeddedServer = embeddedServer;
     }
 
+    public void setSeed(byte[] seed) {
+        this.seed = seed;
+    }
+
 }

+ 17 - 2
server/src/main/java/com/alibaba/otter/canal/server/netty/handler/HandshakeInitializationHandler.java

@@ -1,5 +1,7 @@
 package com.alibaba.otter.canal.server.netty.handler;
 
+import org.jboss.netty.channel.ChannelFuture;
+import org.jboss.netty.channel.ChannelFutureListener;
 import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.channel.ChannelStateEvent;
 import org.jboss.netty.channel.SimpleChannelHandler;
@@ -11,6 +13,7 @@ import com.alibaba.otter.canal.protocol.CanalPacket;
 import com.alibaba.otter.canal.protocol.CanalPacket.Handshake;
 import com.alibaba.otter.canal.protocol.CanalPacket.Packet;
 import com.alibaba.otter.canal.server.netty.NettyUtils;
+import com.google.protobuf.ByteString;
 
 /**
  * handshake交互
@@ -35,12 +38,24 @@ public class HandshakeInitializationHandler extends SimpleChannelHandler {
             childGroups.add(ctx.getChannel());
         }
 
+        final byte[] seed = org.apache.commons.lang3.RandomUtils.nextBytes(8);
         byte[] body = Packet.newBuilder()
             .setType(CanalPacket.PacketType.HANDSHAKE)
-            .setBody(Handshake.newBuilder().build().toByteString())
+            .setVersion(NettyUtils.VERSION)
+            .setBody(Handshake.newBuilder().setSeeds(ByteString.copyFrom(seed)).build().toByteString())
             .build()
             .toByteArray();
-        NettyUtils.write(ctx.getChannel(), body, null);
+
+        NettyUtils.write(ctx.getChannel(), body, new ChannelFutureListener() {
+
+            public void operationComplete(ChannelFuture future) throws Exception {
+                ctx.getPipeline().get(HandshakeInitializationHandler.class.getName());
+                ClientAuthenticationHandler handler = (ClientAuthenticationHandler) ctx.getPipeline()
+                    .get(ClientAuthenticationHandler.class.getName());
+                handler.setSeed(seed);
+            }
+
+        });
         logger.info("send handshake initialization packet to : {}", ctx.getChannel());
     }
 }

+ 107 - 34
server/src/main/java/com/alibaba/otter/canal/server/netty/handler/SessionHandler.java

@@ -79,11 +79,21 @@ public class SessionHandler extends SimpleChannelHandler {
                         // ctx.setAttachment(clientIdentity);// 设置状态数据
                         byte[] ackBytes = NettyUtils.ackPacket();
                         NettyUtils.write(ctx.getChannel(), ackBytes, new ChannelFutureAggregator(sub.getDestination(),
-                                sub, packet.getType(), ackBytes.length, System.nanoTime() - start));
+                            sub,
+                            packet.getType(),
+                            ackBytes.length,
+                            System.nanoTime() - start));
                     } else {
-                        byte[] errorBytes = NettyUtils.errorPacket(401, MessageFormatter.format("destination or clientId is null", sub.toString()).getMessage());
-                        NettyUtils.write(ctx.getChannel(), errorBytes ,new ChannelFutureAggregator(sub.getDestination(),
-                                sub, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 401));
+                        byte[] errorBytes = NettyUtils.errorPacket(401,
+                            MessageFormatter.format("destination or clientId is null", sub.toString()).getMessage());
+                        NettyUtils.write(ctx.getChannel(),
+                            errorBytes,
+                            new ChannelFutureAggregator(sub.getDestination(),
+                                sub,
+                                packet.getType(),
+                                errorBytes.length,
+                                System.nanoTime() - start,
+                                (short) 401));
                     }
                     break;
                 case UNSUBSCRIPTION:
@@ -96,12 +106,24 @@ public class SessionHandler extends SimpleChannelHandler {
                         embeddedServer.unsubscribe(clientIdentity);
                         stopCanalInstanceIfNecessary(clientIdentity);// 尝试关闭
                         byte[] ackBytes = NettyUtils.ackPacket();
-                        NettyUtils.write(ctx.getChannel(), ackBytes, new ChannelFutureAggregator(unsub.getDestination(),
-                                unsub, packet.getType(), ackBytes.length, System.nanoTime() - start));
+                        NettyUtils.write(ctx.getChannel(),
+                            ackBytes,
+                            new ChannelFutureAggregator(unsub.getDestination(),
+                                unsub,
+                                packet.getType(),
+                                ackBytes.length,
+                                System.nanoTime() - start));
                     } else {
-                        byte[] errorBytes = NettyUtils.errorPacket(401, MessageFormatter.format("destination or clientId is null", unsub.toString()).getMessage());
-                        NettyUtils.write(ctx.getChannel(), errorBytes, new ChannelFutureAggregator(unsub.getDestination(),
-                                unsub, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 401));
+                        byte[] errorBytes = NettyUtils.errorPacket(401,
+                            MessageFormatter.format("destination or clientId is null", unsub.toString()).getMessage());
+                        NettyUtils.write(ctx.getChannel(),
+                            errorBytes,
+                            new ChannelFutureAggregator(unsub.getDestination(),
+                                unsub,
+                                packet.getType(),
+                                errorBytes.length,
+                                System.nanoTime() - start,
+                                (short) 401));
                     }
                     break;
                 case GET:
@@ -177,15 +199,19 @@ public class SessionHandler extends SimpleChannelHandler {
                             }
                             output.checkNoSpaceLeft();
                             NettyUtils.write(ctx.getChannel(), body, new ChannelFutureAggregator(get.getDestination(),
-                                    get, packet.getType(), body.length, System.nanoTime() - start, message.getId() == -1));
-                            
+                                get,
+                                packet.getType(),
+                                body.length,
+                                System.nanoTime() - start,
+                                message.getId() == -1));
+
                             // output.flush();
                             // byteBuffer.flip();
                             // NettyUtils.write(ctx.getChannel(), byteBuffer,
                             // null);
                         } else {
                             Packet.Builder packetBuilder = CanalPacket.Packet.newBuilder();
-                            packetBuilder.setType(PacketType.MESSAGES);
+                            packetBuilder.setType(PacketType.MESSAGES).setVersion(NettyUtils.VERSION);
 
                             Messages.Builder messageBuilder = CanalPacket.Messages.newBuilder();
                             messageBuilder.setBatchId(message.getId());
@@ -198,14 +224,27 @@ public class SessionHandler extends SimpleChannelHandler {
                                     }
                                 }
                             }
-                            byte[] body = packetBuilder.setBody(messageBuilder.build().toByteString()).build().toByteArray();
+                            byte[] body = packetBuilder.setBody(messageBuilder.build().toByteString())
+                                .build()
+                                .toByteArray();
                             NettyUtils.write(ctx.getChannel(), body, new ChannelFutureAggregator(get.getDestination(),
-                                    get, packet.getType(), body.length, System.nanoTime() - start, message.getId() == -1));// 输出数据
+                                get,
+                                packet.getType(),
+                                body.length,
+                                System.nanoTime() - start,
+                                message.getId() == -1));// 输出数据
                         }
                     } else {
-                        byte[] errorBytes = NettyUtils.errorPacket(401, MessageFormatter.format("destination or clientId is null", get.toString()).getMessage());
-                        NettyUtils.write(ctx.getChannel(), errorBytes, new ChannelFutureAggregator(get.getDestination(),
-                                get, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 401));
+                        byte[] errorBytes = NettyUtils.errorPacket(401,
+                            MessageFormatter.format("destination or clientId is null", get.toString()).getMessage());
+                        NettyUtils.write(ctx.getChannel(),
+                            errorBytes,
+                            new ChannelFutureAggregator(get.getDestination(),
+                                get,
+                                packet.getType(),
+                                errorBytes.length,
+                                System.nanoTime() - start,
+                                (short) 401));
                     }
                     break;
                 case CLIENTACK:
@@ -213,20 +252,38 @@ public class SessionHandler extends SimpleChannelHandler {
                     MDC.put("destination", ack.getDestination());
                     if (StringUtils.isNotEmpty(ack.getDestination()) && StringUtils.isNotEmpty(ack.getClientId())) {
                         if (ack.getBatchId() == 0L) {
-                            byte[] errorBytes = NettyUtils.errorPacket(402, MessageFormatter.format("batchId should assign value", ack.toString()).getMessage());
-                            NettyUtils.write(ctx.getChannel(), errorBytes, new ChannelFutureAggregator(ack.getDestination(),
-                                    ack, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 402));
+                            byte[] errorBytes = NettyUtils.errorPacket(402,
+                                MessageFormatter.format("batchId should assign value", ack.toString()).getMessage());
+                            NettyUtils.write(ctx.getChannel(),
+                                errorBytes,
+                                new ChannelFutureAggregator(ack.getDestination(),
+                                    ack,
+                                    packet.getType(),
+                                    errorBytes.length,
+                                    System.nanoTime() - start,
+                                    (short) 402));
                         } else if (ack.getBatchId() == -1L) { // -1代表上一次get没有数据,直接忽略之
                             // donothing
                         } else {
                             clientIdentity = new ClientIdentity(ack.getDestination(), Short.valueOf(ack.getClientId()));
                             embeddedServer.ack(clientIdentity, ack.getBatchId());
-                            new ChannelFutureAggregator(ack.getDestination(), ack, packet.getType(), 0, System.nanoTime() - start).operationComplete(null);
+                            new ChannelFutureAggregator(ack.getDestination(),
+                                ack,
+                                packet.getType(),
+                                0,
+                                System.nanoTime() - start).operationComplete(null);
                         }
                     } else {
-                        byte[] errorBytes = NettyUtils.errorPacket(401, MessageFormatter.format("destination or clientId is null", ack.toString()).getMessage());
-                        NettyUtils.write(ctx.getChannel(), errorBytes, new ChannelFutureAggregator(ack.getDestination(),
-                                ack, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 401));
+                        byte[] errorBytes = NettyUtils.errorPacket(401,
+                            MessageFormatter.format("destination or clientId is null", ack.toString()).getMessage());
+                        NettyUtils.write(ctx.getChannel(),
+                            errorBytes,
+                            new ChannelFutureAggregator(ack.getDestination(),
+                                ack,
+                                packet.getType(),
+                                errorBytes.length,
+                                System.nanoTime() - start,
+                                (short) 401));
                     }
                     break;
                 case CLIENTROLLBACK:
@@ -241,25 +298,41 @@ public class SessionHandler extends SimpleChannelHandler {
                         } else {
                             embeddedServer.rollback(clientIdentity, rollback.getBatchId()); // 只回滚单个批次
                         }
-                        new ChannelFutureAggregator(rollback.getDestination(), rollback, packet.getType(), 0, System.nanoTime() - start).operationComplete(null);
+                        new ChannelFutureAggregator(rollback.getDestination(),
+                            rollback,
+                            packet.getType(),
+                            0,
+                            System.nanoTime() - start).operationComplete(null);
                     } else {
-                        byte[] errorBytes = NettyUtils.errorPacket(401, MessageFormatter.format("destination or clientId is null", rollback.toString()).getMessage());
-                        NettyUtils.write(ctx.getChannel(), errorBytes, new ChannelFutureAggregator(rollback.getDestination(),
-                                rollback, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 401));
+                        byte[] errorBytes = NettyUtils.errorPacket(401,
+                            MessageFormatter.format("destination or clientId is null", rollback.toString())
+                                .getMessage());
+                        NettyUtils.write(ctx.getChannel(),
+                            errorBytes,
+                            new ChannelFutureAggregator(rollback.getDestination(),
+                                rollback,
+                                packet.getType(),
+                                errorBytes.length,
+                                System.nanoTime() - start,
+                                (short) 401));
                     }
                     break;
                 default:
-                    byte[] errorBytes = NettyUtils.errorPacket(400, MessageFormatter.format("packet type={} is NOT supported!", packet.getType()).getMessage());
-                    NettyUtils.write(ctx.getChannel(), errorBytes, new ChannelFutureAggregator(ctx.getChannel().getRemoteAddress().toString(),
-                            null, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 400));
+                    byte[] errorBytes = NettyUtils.errorPacket(400,
+                        MessageFormatter.format("packet type={} is NOT supported!", packet.getType()).getMessage());
+                    NettyUtils.write(ctx.getChannel(), errorBytes, new ChannelFutureAggregator(ctx.getChannel()
+                        .getRemoteAddress()
+                        .toString(), null, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 400));
                     break;
             }
         } catch (Throwable exception) {
-            byte[] errorBytes = NettyUtils.errorPacket(400, MessageFormatter.format("something goes wrong with channel:{}, exception={}",
+            byte[] errorBytes = NettyUtils.errorPacket(400,
+                MessageFormatter.format("something goes wrong with channel:{}, exception={}",
                     ctx.getChannel(),
                     ExceptionUtils.getStackTrace(exception)).getMessage());
-            NettyUtils.write(ctx.getChannel(), errorBytes, new ChannelFutureAggregator(ctx.getChannel().getRemoteAddress().toString(),
-                    null, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 400));
+            NettyUtils.write(ctx.getChannel(), errorBytes, new ChannelFutureAggregator(ctx.getChannel()
+                .getRemoteAddress()
+                .toString(), null, packet.getType(), errorBytes.length, System.nanoTime() - start, (short) 400));
         } finally {
             MDC.remove("destination");
         }

+ 13 - 7
server/src/test/java/com/alibaba/otter/canal/server/CanalServerTest.java

@@ -34,6 +34,8 @@ import com.alibaba.otter.canal.protocol.CanalPacket.Sub;
 import com.alibaba.otter.canal.protocol.CanalPacket.Unsub;
 import com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;
 import com.alibaba.otter.canal.server.netty.CanalServerWithNetty;
+import com.alibaba.otter.canal.server.netty.NettyUtils;
+
 @Ignore
 public class CanalServerTest {
 
@@ -68,7 +70,6 @@ public class CanalServerTest {
     @Test
     public void testAuth() {
 
-
         try {
             SocketChannel channel = SocketChannel.open();
             channel.connect(new InetSocketAddress("127.0.0.1", 1088));
@@ -93,6 +94,7 @@ public class CanalServerTest {
             writeWithHeader(channel,
                 Packet.newBuilder()
                     .setType(PacketType.CLIENTAUTHENTICATION)
+                    .setVersion(NettyUtils.VERSION)
                     .setBody(ca.toByteString())
                     .build()
                     .toByteArray());
@@ -107,12 +109,12 @@ public class CanalServerTest {
                 throw new Exception("something goes wrong when doing authentication: " + ack.getErrorMessage());
             }
 
-            writeWithHeader(channel,
-                Packet.newBuilder()
-                    .setType(PacketType.SUBSCRIPTION)
-                    .setBody(Sub.newBuilder().setDestination(DESTINATION).setClientId("1").build().toByteString())
-                    .build()
-                    .toByteArray());
+            writeWithHeader(channel, Packet.newBuilder()
+                .setType(PacketType.SUBSCRIPTION)
+                .setVersion(NettyUtils.VERSION)
+                .setBody(Sub.newBuilder().setDestination(DESTINATION).setClientId("1").build().toByteString())
+                .build()
+                .toByteArray());
             //
             p = Packet.parseFrom(readNextPacket(channel));
             ack = Ack.parseFrom(p.getBody());
@@ -124,6 +126,7 @@ public class CanalServerTest {
                 writeWithHeader(channel,
                     Packet.newBuilder()
                         .setType(PacketType.GET)
+                        .setVersion(NettyUtils.VERSION)
                         .setBody(Get.newBuilder()
                             .setDestination(DESTINATION)
                             .setClientId("1")
@@ -158,6 +161,7 @@ public class CanalServerTest {
                 writeWithHeader(channel,
                     Packet.newBuilder()
                         .setType(PacketType.CLIENTACK)
+                        .setVersion(NettyUtils.VERSION)
                         .setBody(ClientAck.newBuilder()
                             .setDestination(DESTINATION)
                             .setClientId("1")
@@ -171,6 +175,7 @@ public class CanalServerTest {
             writeWithHeader(channel,
                 Packet.newBuilder()
                     .setType(PacketType.CLIENTROLLBACK)
+                    .setVersion(NettyUtils.VERSION)
                     .setBody(ClientRollback.newBuilder()
                         .setDestination(DESTINATION)
                         .setClientId("1")
@@ -182,6 +187,7 @@ public class CanalServerTest {
             writeWithHeader(channel,
                 Packet.newBuilder()
                     .setType(PacketType.UNSUBSCRIPTION)
+                    .setVersion(NettyUtils.VERSION)
                     .setBody(Unsub.newBuilder().setDestination(DESTINATION).setClientId("1").build().toByteString())
                     .build()
                     .toByteArray());

+ 22 - 0
server/src/test/java/com/alibaba/otter/canal/server/SecurityUtilTest.java

@@ -0,0 +1,22 @@
+package com.alibaba.otter.canal.server;
+
+import java.security.NoSuchAlgorithmException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.alibaba.otter.canal.protocol.SecurityUtil;
+
+public class SecurityUtilTest {
+
+    @Test
+    public void testSimple() throws NoSuchAlgorithmException {
+        byte[] seed = { 1, 2, 3, 4, 5, 6, 7, 8 };
+        // String str = "e3619321c1a937c46a0d8bd1dac39f93b27d4458"; // canal
+        // passwd
+        String str = SecurityUtil.scrambleGenPass("canal".getBytes());
+        byte[] client = SecurityUtil.scramble411("canal".getBytes(), seed);
+        boolean check = SecurityUtil.scrambleServerAuth(client, SecurityUtil.hexStr2Bytes(str), seed);
+        Assert.assertTrue(check);
+    }
+}

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.