Selaa lähdekoodia

Put ZLToolkit into 3rd party packages.

qiuyang 1 vuosi sitten
vanhempi
commit
32cf6766b0
52 muutettua tiedostoa jossa 7894 lisäystä ja 0 poistoa
  1. 449 0
      3rdparty/ZLToolKit/include/Network/Buffer.h
  2. 73 0
      3rdparty/ZLToolKit/include/Network/BufferSock.h
  3. 83 0
      3rdparty/ZLToolKit/include/Network/Server.h
  4. 85 0
      3rdparty/ZLToolKit/include/Network/Session.h
  5. 729 0
      3rdparty/ZLToolKit/include/Network/Socket.h
  6. 173 0
      3rdparty/ZLToolKit/include/Network/TcpClient.h
  7. 105 0
      3rdparty/ZLToolKit/include/Network/TcpServer.h
  8. 123 0
      3rdparty/ZLToolKit/include/Network/UdpServer.h
  9. 347 0
      3rdparty/ZLToolKit/include/Network/sockutil.h
  10. 290 0
      3rdparty/ZLToolKit/include/Poller/EventPoller.h
  11. 35 0
      3rdparty/ZLToolKit/include/Poller/Pipe.h
  12. 35 0
      3rdparty/ZLToolKit/include/Poller/PipeWrap.h
  13. 32 0
      3rdparty/ZLToolKit/include/Poller/SelectWrap.h
  14. 39 0
      3rdparty/ZLToolKit/include/Poller/Timer.h
  15. 253 0
      3rdparty/ZLToolKit/include/Thread/TaskExecutor.h
  16. 72 0
      3rdparty/ZLToolKit/include/Thread/TaskQueue.h
  17. 155 0
      3rdparty/ZLToolKit/include/Thread/ThreadPool.h
  18. 61 0
      3rdparty/ZLToolKit/include/Thread/WorkThreadPool.h
  19. 83 0
      3rdparty/ZLToolKit/include/Thread/semaphore.h
  20. 85 0
      3rdparty/ZLToolKit/include/Thread/threadgroup.h
  21. 384 0
      3rdparty/ZLToolKit/include/Util/CMD.h
  22. 145 0
      3rdparty/ZLToolKit/include/Util/File.h
  23. 218 0
      3rdparty/ZLToolKit/include/Util/List.h
  24. 97 0
      3rdparty/ZLToolKit/include/Util/MD5.h
  25. 174 0
      3rdparty/ZLToolKit/include/Util/NoticeCenter.h
  26. 205 0
      3rdparty/ZLToolKit/include/Util/ResourcePool.h
  27. 438 0
      3rdparty/ZLToolKit/include/Util/RingBuffer.h
  28. 47 0
      3rdparty/ZLToolKit/include/Util/SHA1.h
  29. 206 0
      3rdparty/ZLToolKit/include/Util/SSLBox.h
  30. 121 0
      3rdparty/ZLToolKit/include/Util/SSLUtil.h
  31. 65 0
      3rdparty/ZLToolKit/include/Util/SpeedStatistic.h
  32. 248 0
      3rdparty/ZLToolKit/include/Util/SqlConnection.h
  33. 307 0
      3rdparty/ZLToolKit/include/Util/SqlPool.h
  34. 147 0
      3rdparty/ZLToolKit/include/Util/TimeTicker.h
  35. 71 0
      3rdparty/ZLToolKit/include/Util/base64.h
  36. 55 0
      3rdparty/ZLToolKit/include/Util/function_traits.h
  37. 15 0
      3rdparty/ZLToolKit/include/Util/local_time.h
  38. 442 0
      3rdparty/ZLToolKit/include/Util/logger.h
  39. 186 0
      3rdparty/ZLToolKit/include/Util/mini.h
  40. 51 0
      3rdparty/ZLToolKit/include/Util/onceToken.h
  41. 10 0
      3rdparty/ZLToolKit/include/Util/strptime_win.h
  42. 384 0
      3rdparty/ZLToolKit/include/Util/util.h
  43. 524 0
      3rdparty/ZLToolKit/include/Util/uv_errno.h
  44. BIN
      3rdparty/ZLToolKit/lib/libZLToolKit.a
  45. BIN
      3rdparty/ZLToolKit/lib/libZLToolKit.so
  46. 9 0
      cmake/FindZLToolKit.cmake
  47. BIN
      lib/libgsd_core.so
  48. BIN
      lib/libgsd_modules.so
  49. BIN
      lib/libgsd_plugins.so
  50. 5 0
      modules/CMakeLists.txt
  51. 16 0
      plugins/CMakeLists.txt
  52. 17 0
      source/CMakeLists.txt

+ 449 - 0
3rdparty/ZLToolKit/include/Network/Buffer.h

@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLTOOLKIT_BUFFER_H
+#define ZLTOOLKIT_BUFFER_H
+
+#include <cassert>
+#include <memory>
+#include <string>
+#include <vector>
+#include <type_traits>
+#include <functional>
+#include "Util/util.h"
+#include "Util/ResourcePool.h"
+
+namespace toolkit {
+
+template <typename T> struct is_pointer : public std::false_type {};
+template <typename T> struct is_pointer<std::shared_ptr<T> > : public std::true_type {};
+template <typename T> struct is_pointer<std::shared_ptr<T const> > : public std::true_type {};
+template <typename T> struct is_pointer<T*> : public std::true_type {};
+template <typename T> struct is_pointer<const T*> : public std::true_type {};
+
+//缓存基类
+class Buffer : public noncopyable {
+public:
+    using Ptr = std::shared_ptr<Buffer>;
+
+    Buffer() = default;
+    virtual ~Buffer() = default;
+
+    //返回数据长度
+    virtual char *data() const = 0;
+    virtual size_t size() const = 0;
+
+    virtual std::string toString() const {
+        return std::string(data(), size());
+    }
+
+    virtual size_t getCapacity() const {
+        return size();
+    }
+
+private:
+    //对象个数统计
+    ObjectStatistic<Buffer> _statistic;
+};
+
+template <typename C>
+class BufferOffset : public  Buffer {
+public:
+    using Ptr = std::shared_ptr<BufferOffset>;
+
+    BufferOffset(C data, size_t offset = 0, size_t len = 0) : _data(std::move(data)) {
+        setup(offset, len);
+    }
+
+    ~BufferOffset() override = default;
+
+    char *data() const override {
+        return const_cast<char *>(getPointer<C>(_data)->data()) + _offset;
+    }
+
+    size_t size() const override {
+        return _size;
+    }
+
+    std::string toString() const override {
+        return std::string(data(), size());
+    }
+
+private:
+    void setup(size_t offset = 0, size_t size = 0) {
+        auto max_size = getPointer<C>(_data)->size();
+        assert(offset + size <= max_size);
+        if (!size) {
+            size = max_size - offset;
+        }
+        _size = size;
+        _offset = offset;
+    }
+
+    template<typename T>
+    static typename std::enable_if<::toolkit::is_pointer<T>::value, const T &>::type
+    getPointer(const T &data) {
+        return data;
+    }
+
+    template<typename T>
+    static typename std::enable_if<!::toolkit::is_pointer<T>::value, const T *>::type
+    getPointer(const T &data) {
+        return &data;
+    }
+
+private:
+    C _data;
+    size_t _size;
+    size_t _offset;
+};
+
+using BufferString = BufferOffset<std::string>;
+
+//指针式缓存对象,
+class BufferRaw : public Buffer {
+public:
+    using Ptr = std::shared_ptr<BufferRaw>;
+
+    static Ptr create();
+
+    ~BufferRaw() override {
+        if (_data) {
+            delete[] _data;
+        }
+    }
+
+    //在写入数据时请确保内存是否越界
+    char *data() const override {
+        return _data;
+    }
+
+    //有效数据大小
+    size_t size() const override {
+        return _size;
+    }
+
+    //分配内存大小
+    void setCapacity(size_t capacity) {
+        if (_data) {
+            do {
+                if (capacity > _capacity) {
+                    //请求的内存大于当前内存,那么重新分配
+                    break;
+                }
+
+                if (_capacity < 2 * 1024) {
+                    //2K以下,不重复开辟内存,直接复用
+                    return;
+                }
+
+                if (2 * capacity > _capacity) {
+                    //如果请求的内存大于当前内存的一半,那么也复用
+                    return;
+                }
+            } while (false);
+
+            delete[] _data;
+        }
+        _data = new char[capacity];
+        _capacity = capacity;
+    }
+
+    //设置有效数据大小
+    virtual void setSize(size_t size) {
+        if (size > _capacity) {
+            throw std::invalid_argument("Buffer::setSize out of range");
+        }
+        _size = size;
+    }
+
+    //赋值数据
+    void assign(const char *data, size_t size = 0) {
+        if (size <= 0) {
+            size = strlen(data);
+        }
+        setCapacity(size + 1);
+        memcpy(_data, data, size);
+        _data[size] = '\0';
+        setSize(size);
+    }
+
+    size_t getCapacity() const override {
+        return _capacity;
+    }
+
+protected:
+    friend class ResourcePool_l<BufferRaw>;
+
+    BufferRaw(size_t capacity = 0) {
+        if (capacity) {
+            setCapacity(capacity);
+        }
+    }
+
+    BufferRaw(const char *data, size_t size = 0) {
+        assign(data, size);
+    }
+
+private:
+    size_t _size = 0;
+    size_t _capacity = 0;
+    char *_data = nullptr;
+    //对象个数统计
+    ObjectStatistic<BufferRaw> _statistic;
+};
+
+class BufferLikeString : public Buffer {
+public:
+    ~BufferLikeString() override = default;
+
+    BufferLikeString() {
+        _erase_head = 0;
+        _erase_tail = 0;
+    }
+
+    BufferLikeString(std::string str) {
+        _str = std::move(str);
+        _erase_head = 0;
+        _erase_tail = 0;
+    }
+
+    BufferLikeString &operator=(std::string str) {
+        _str = std::move(str);
+        _erase_head = 0;
+        _erase_tail = 0;
+        return *this;
+    }
+
+    BufferLikeString(const char *str) {
+        _str = str;
+        _erase_head = 0;
+        _erase_tail = 0;
+    }
+
+    BufferLikeString &operator=(const char *str) {
+        _str = str;
+        _erase_head = 0;
+        _erase_tail = 0;
+        return *this;
+    }
+
+    BufferLikeString(BufferLikeString &&that) {
+        _str = std::move(that._str);
+        _erase_head = that._erase_head;
+        _erase_tail = that._erase_tail;
+        that._erase_head = 0;
+        that._erase_tail = 0;
+    }
+
+    BufferLikeString &operator=(BufferLikeString &&that) {
+        _str = std::move(that._str);
+        _erase_head = that._erase_head;
+        _erase_tail = that._erase_tail;
+        that._erase_head = 0;
+        that._erase_tail = 0;
+        return *this;
+    }
+
+    BufferLikeString(const BufferLikeString &that) {
+        _str = that._str;
+        _erase_head = that._erase_head;
+        _erase_tail = that._erase_tail;
+    }
+
+    BufferLikeString &operator=(const BufferLikeString &that) {
+        _str = that._str;
+        _erase_head = that._erase_head;
+        _erase_tail = that._erase_tail;
+        return *this;
+    }
+
+    char *data() const override {
+        return (char *) _str.data() + _erase_head;
+    }
+
+    size_t size() const override {
+        return _str.size() - _erase_tail - _erase_head;
+    }
+
+    BufferLikeString &erase(size_t pos = 0, size_t n = std::string::npos) {
+        if (pos == 0) {
+            //移除前面的数据
+            if (n != std::string::npos) {
+                //移除部分
+                if (n > size()) {
+                    //移除太多数据了
+                    throw std::out_of_range("BufferLikeString::erase out_of_range in head");
+                }
+                //设置起始便宜量
+                _erase_head += n;
+                data()[size()] = '\0';
+                return *this;
+            }
+            //移除全部数据
+            _erase_head = 0;
+            _erase_tail = _str.size();
+            data()[0] = '\0';
+            return *this;
+        }
+
+        if (n == std::string::npos || pos + n >= size()) {
+            //移除末尾所有数据
+            if (pos >= size()) {
+                //移除太多数据
+                throw std::out_of_range("BufferLikeString::erase out_of_range in tail");
+            }
+            _erase_tail += size() - pos;
+            data()[size()] = '\0';
+            return *this;
+        }
+
+        //移除中间的
+        if (pos + n > size()) {
+            //超过长度限制
+            throw std::out_of_range("BufferLikeString::erase out_of_range in middle");
+        }
+        _str.erase(_erase_head + pos, n);
+        return *this;
+    }
+
+    BufferLikeString &append(const BufferLikeString &str) {
+        return append(str.data(), str.size());
+    }
+
+    BufferLikeString &append(const std::string &str) {
+        return append(str.data(), str.size());
+    }
+
+    BufferLikeString &append(const char *data) {
+        return append(data, strlen(data));
+    }
+
+    BufferLikeString &append(const char *data, size_t len) {
+        if (len <= 0) {
+            return *this;
+        }
+        if (_erase_head > _str.capacity() / 2) {
+            moveData();
+        }
+        if (_erase_tail == 0) {
+            _str.append(data, len);
+            return *this;
+        }
+        _str.insert(_erase_head + size(), data, len);
+        return *this;
+    }
+
+    void push_back(char c) {
+        if (_erase_tail == 0) {
+            _str.push_back(c);
+            return;
+        }
+        data()[size()] = c;
+        --_erase_tail;
+        data()[size()] = '\0';
+    }
+
+    BufferLikeString &insert(size_t pos, const char *s, size_t n) {
+        _str.insert(_erase_head + pos, s, n);
+        return *this;
+    }
+
+    BufferLikeString &assign(const char *data) {
+        return assign(data, strlen(data));
+    }
+
+    BufferLikeString &assign(const char *data, size_t len) {
+        if (len <= 0) {
+            return *this;
+        }
+        if (data >= _str.data() && data < _str.data() + _str.size()) {
+            _erase_head = data - _str.data();
+            if (data + len > _str.data() + _str.size()) {
+                throw std::out_of_range("BufferLikeString::assign out_of_range");
+            }
+            _erase_tail = _str.data() + _str.size() - (data + len);
+            return *this;
+        }
+        _str.assign(data, len);
+        _erase_head = 0;
+        _erase_tail = 0;
+        return *this;
+    }
+
+    void clear() {
+        _erase_head = 0;
+        _erase_tail = 0;
+        _str.clear();
+    }
+
+    char &operator[](size_t pos) {
+        if (pos >= size()) {
+            throw std::out_of_range("BufferLikeString::operator[] out_of_range");
+        }
+        return data()[pos];
+    }
+
+    const char &operator[](size_t pos) const {
+        return (*const_cast<BufferLikeString *>(this))[pos];
+    }
+
+    size_t capacity() const {
+        return _str.capacity();
+    }
+
+    void reserve(size_t size) {
+        _str.reserve(size);
+    }
+
+    void resize(size_t size, char c = '\0') {
+        _str.resize(size, c);
+        _erase_head = 0;
+        _erase_tail = 0;
+    }
+
+    bool empty() const {
+        return size() <= 0;
+    }
+
+    std::string substr(size_t pos, size_t n = std::string::npos) const {
+        if (n == std::string::npos) {
+            //获取末尾所有的
+            if (pos >= size()) {
+                throw std::out_of_range("BufferLikeString::substr out_of_range");
+            }
+            return _str.substr(_erase_head + pos, size() - pos);
+        }
+
+        //获取部分
+        if (pos + n > size()) {
+            throw std::out_of_range("BufferLikeString::substr out_of_range");
+        }
+        return _str.substr(_erase_head + pos, n);
+    }
+
+private:
+    void moveData() {
+        if (_erase_head) {
+            _str.erase(0, _erase_head);
+            _erase_head = 0;
+        }
+    }
+
+private:
+    size_t _erase_head;
+    size_t _erase_tail;
+    std::string _str;
+    //对象个数统计
+    ObjectStatistic<BufferLikeString> _statistic;
+};
+
+}//namespace toolkit
+#endif //ZLTOOLKIT_BUFFER_H

+ 73 - 0
3rdparty/ZLToolKit/include/Network/BufferSock.h

@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLTOOLKIT_BUFFERSOCK_H
+#define ZLTOOLKIT_BUFFERSOCK_H
+
+#if !defined(_WIN32)
+#include <sys/uio.h>
+#include <limits.h>
+#endif
+#include <cassert>
+#include <memory>
+#include <string>
+#include <vector>
+#include <type_traits>
+#include <functional>
+#include "Util/util.h"
+#include "Util/List.h"
+#include "Util/ResourcePool.h"
+#include "sockutil.h"
+#include "Buffer.h"
+
+namespace toolkit {
+
+#if !defined(IOV_MAX)
+#define IOV_MAX 1024
+#endif
+
+class BufferSock : public Buffer {
+public:
+    using Ptr = std::shared_ptr<BufferSock>;
+    BufferSock(Buffer::Ptr ptr, struct sockaddr *addr = nullptr, int addr_len = 0);
+    ~BufferSock() override = default;
+
+    char *data() const override;
+    size_t size() const override;
+    const struct sockaddr *sockaddr() const;
+    socklen_t  socklen() const;
+
+private:
+    int _addr_len = 0;
+    struct sockaddr_storage _addr;
+    Buffer::Ptr _buffer;
+};
+
+class BufferList : public noncopyable {
+public:
+    using Ptr = std::shared_ptr<BufferList>;
+    using SendResult = std::function<void(const Buffer::Ptr &buffer, bool send_success)>;
+
+    BufferList() = default;
+    virtual ~BufferList() = default;
+
+    virtual bool empty() = 0;
+    virtual size_t count() = 0;
+    virtual ssize_t send(int fd, int flags) = 0;
+
+    static Ptr create(List<std::pair<Buffer::Ptr, bool> > list, SendResult cb, bool is_udp);
+
+private:
+    //对象个数统计
+    ObjectStatistic<BufferList> _statistic;
+};
+
+}
+#endif //ZLTOOLKIT_BUFFERSOCK_H

+ 83 - 0
3rdparty/ZLToolKit/include/Network/Server.h

@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2021 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLTOOLKIT_SERVER_H
+#define ZLTOOLKIT_SERVER_H
+
+#include <unordered_map>
+#include "Util/mini.h"
+#include "Session.h"
+
+namespace toolkit {
+
+// 全局的 Session 记录对象, 方便后面管理
+// 线程安全的
+class SessionMap : public std::enable_shared_from_this<SessionMap> {
+public:
+    friend class SessionHelper;
+    using Ptr = std::shared_ptr<SessionMap>;
+
+    //单例
+    static SessionMap &Instance();
+    ~SessionMap() = default;
+
+    //获取Session
+    Session::Ptr get(const std::string &tag);
+    void for_each_session(const std::function<void(const std::string &id, const Session::Ptr &session)> &cb);
+
+private:
+    SessionMap() = default;
+
+    //移除Session
+    bool del(const std::string &tag);
+    //添加Session
+    bool add(const std::string &tag, const Session::Ptr &session);
+
+private:
+    std::mutex _mtx_session;
+    std::unordered_map<std::string, std::weak_ptr<Session> > _map_session;
+};
+
+class Server;
+
+class SessionHelper {
+public:
+    using Ptr = std::shared_ptr<SessionHelper>;
+
+    SessionHelper(const std::weak_ptr<Server> &server, Session::Ptr session, std::string cls);
+    ~SessionHelper();
+
+    const Session::Ptr &session() const;
+    const std::string &className() const;
+
+private:
+    std::string _cls;
+    std::string _identifier;
+    Session::Ptr _session;
+    SessionMap::Ptr _session_map;
+    std::weak_ptr<Server> _server;
+};
+
+// server 基类, 暂时仅用于剥离 SessionHelper 对 TcpServer 的依赖
+// 后续将 TCP 与 UDP 服务通用部分加到这里.
+class Server : public std::enable_shared_from_this<Server>, public mINI {
+public:
+    using Ptr = std::shared_ptr<Server>;
+
+    explicit Server(EventPoller::Ptr poller = nullptr);
+    virtual ~Server() = default;
+
+protected:
+    EventPoller::Ptr _poller;
+};
+
+} // namespace toolkit
+
+#endif // ZLTOOLKIT_SERVER_H

+ 85 - 0
3rdparty/ZLToolKit/include/Network/Session.h

@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2021 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLTOOLKIT_SESSION_H
+#define ZLTOOLKIT_SESSION_H
+
+#include <memory>
+#include "Socket.h"
+#include "Util/util.h"
+#include "Util/SSLBox.h"
+
+namespace toolkit {
+
+// 会话, 用于存储一对客户端与服务端间的关系
+class Server;
+class TcpSession;
+class UdpSession;
+
+class Session : public SocketHelper {
+public:
+    using Ptr = std::shared_ptr<Session>;
+
+    Session(const Socket::Ptr &sock);
+    ~Session() override = default;
+
+    /**
+     * 在创建 Session 后, Server 会把自身的配置参数通过该函数传递给 Session
+     * @param server, 服务器对象
+     */
+    virtual void attachServer(const Server &server) {}
+
+    /**
+     * 作为该 Session 的唯一标识符
+     * @return 唯一标识符
+     */
+    std::string getIdentifier() const override;
+
+private:
+    mutable std::string _id;
+    std::unique_ptr<toolkit::ObjectStatistic<toolkit::TcpSession> > _statistic_tcp;
+    std::unique_ptr<toolkit::ObjectStatistic<toolkit::UdpSession> > _statistic_udp;
+};
+
+// 通过该模板可以让TCP服务器快速支持TLS
+template <typename SessionType>
+class SessionWithSSL : public SessionType {
+public:
+    template <typename... ArgsType>
+    SessionWithSSL(ArgsType &&...args)
+        : SessionType(std::forward<ArgsType>(args)...) {
+        _ssl_box.setOnEncData([&](const Buffer::Ptr &buf) { public_send(buf); });
+        _ssl_box.setOnDecData([&](const Buffer::Ptr &buf) { public_onRecv(buf); });
+    }
+
+    ~SessionWithSSL() override { _ssl_box.flush(); }
+
+    void onRecv(const Buffer::Ptr &buf) override { _ssl_box.onRecv(buf); }
+
+    // 添加public_onRecv和public_send函数是解决较低版本gcc一个lambad中不能访问protected或private方法的bug
+    inline void public_onRecv(const Buffer::Ptr &buf) { SessionType::onRecv(buf); }
+    inline void public_send(const Buffer::Ptr &buf) { SessionType::send(std::move(const_cast<Buffer::Ptr &>(buf))); }
+
+    bool overSsl() const override { return true; }
+
+protected:
+    ssize_t send(Buffer::Ptr buf) override {
+        auto size = buf->size();
+        _ssl_box.onSend(std::move(buf));
+        return size;
+    }
+
+private:
+    SSL_Box _ssl_box;
+};
+
+} // namespace toolkit
+
+#endif // ZLTOOLKIT_SESSION_H

+ 729 - 0
3rdparty/ZLToolKit/include/Network/Socket.h

@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef NETWORK_SOCKET_H
+#define NETWORK_SOCKET_H
+
+#include <memory>
+#include <string>
+#include <mutex>
+#include <atomic>
+#include <sstream>
+#include <functional>
+#include "Util/SpeedStatistic.h"
+#include "sockutil.h"
+#include "Poller/Timer.h"
+#include "Poller/EventPoller.h"
+#include "BufferSock.h"
+
+namespace toolkit {
+
+#if defined(MSG_NOSIGNAL)
+#define FLAG_NOSIGNAL MSG_NOSIGNAL
+#else
+#define FLAG_NOSIGNAL 0
+#endif //MSG_NOSIGNAL
+
+#if defined(MSG_MORE)
+#define FLAG_MORE MSG_MORE
+#else
+#define FLAG_MORE 0
+#endif //MSG_MORE
+
+#if defined(MSG_DONTWAIT)
+#define FLAG_DONTWAIT MSG_DONTWAIT
+#else
+#define FLAG_DONTWAIT 0
+#endif //MSG_DONTWAIT
+
+//默认的socket flags:不触发SIGPIPE,非阻塞发送
+#define SOCKET_DEFAULE_FLAGS (FLAG_NOSIGNAL | FLAG_DONTWAIT )
+    
+//发送超时时间,如果在规定时间内一直没有发送数据成功,那么将触发onErr事件
+#define SEND_TIME_OUT_SEC 10
+    
+//错误类型枚举
+typedef enum {
+    Err_success = 0, //成功
+    Err_eof, //eof
+    Err_timeout, //超时
+    Err_refused,//连接被拒绝
+    Err_dns,//dns解析失败
+    Err_shutdown,//主动关闭
+    Err_other = 0xFF,//其他错误
+} ErrCode;
+
+//错误信息类
+class SockException : public std::exception {
+public:
+    SockException(ErrCode code = Err_success, const std::string &msg = "", int custom_code = 0) {
+        _msg = msg;
+        _code = code;
+        _custom_code = custom_code;
+    }
+
+    //重置错误
+    void reset(ErrCode code, const std::string &msg, int custom_code = 0) {
+        _msg = msg;
+        _code = code;
+        _custom_code = custom_code;
+    }
+
+    //错误提示
+    const char *what() const noexcept override {
+        return _msg.c_str();
+    }
+
+    //错误代码
+    ErrCode getErrCode() const {
+        return _code;
+    }
+
+    //用户自定义错误代码
+    int getCustomCode() const {
+        return _custom_code;
+    }
+
+    //判断是否真的有错
+    operator bool() const {
+        return _code != Err_success;
+    }
+
+private:
+    ErrCode _code;
+    int _custom_code = 0;
+    std::string _msg;
+};
+
+//std::cout等输出流可以直接输出SockException对象
+std::ostream &operator<<(std::ostream &ost, const SockException &err);
+
+class SockNum {
+public:
+    using Ptr = std::shared_ptr<SockNum>;
+
+    typedef enum {
+        Sock_Invalid = -1,
+        Sock_TCP = 0,
+        Sock_UDP = 1,
+        Sock_TCP_Server = 2
+    } SockType;
+
+    SockNum(int fd, SockType type) {
+        _fd = fd;
+        _type = type;
+    }
+
+    ~SockNum() {
+#if defined (OS_IPHONE)
+        unsetSocketOfIOS(_fd);
+#endif //OS_IPHONE
+        // 停止socket收发能力
+        ::shutdown(_fd, SHUT_RDWR);
+        close(_fd);
+    }
+
+    int rawFd() const {
+        return _fd;
+    }
+
+    SockType type() {
+        return _type;
+    }
+
+    void setConnected() {
+#if defined (OS_IPHONE)
+        setSocketOfIOS(_fd);
+#endif //OS_IPHONE
+    }
+
+#if defined (OS_IPHONE)
+private:
+    void *readStream=nullptr;
+    void *writeStream=nullptr;
+    bool setSocketOfIOS(int socket);
+    void unsetSocketOfIOS(int socket);
+#endif //OS_IPHONE
+
+private:
+    int _fd;
+    SockType _type;
+};
+
+//socket 文件描述符的包装
+//在析构时自动溢出监听并close套接字
+//防止描述符溢出
+class SockFD : public noncopyable {
+public:
+    using Ptr = std::shared_ptr<SockFD>;
+
+    /**
+     * 创建一个fd对象
+     * @param num 文件描述符,int数字
+     * @param poller 事件监听器
+     */
+    SockFD(int num, SockNum::SockType type, const EventPoller::Ptr &poller) {
+        _num = std::make_shared<SockNum>(num, type);
+        _poller = poller;
+    }
+
+    /**
+     * 复制一个fd对象
+     * @param that 源对象
+     * @param poller 事件监听器
+     */
+    SockFD(const SockFD &that, const EventPoller::Ptr &poller) {
+        _num = that._num;
+        _poller = poller;
+        if (_poller == that._poller) {
+            throw std::invalid_argument("Copy a SockFD with same poller");
+        }
+    }
+
+     ~SockFD() { delEvent(); }
+
+    void delEvent() {
+        if (_poller) {
+            auto num = _num;
+            // 移除io事件成功后再close fd
+            _poller->delEvent(num->rawFd(), [num](bool) {});
+            _poller = nullptr;
+        }
+    }
+
+    void setConnected() {
+        _num->setConnected();
+    }
+
+    int rawFd() const {
+        return _num->rawFd();
+    }
+
+    SockNum::SockType type() {
+        return _num->type();
+    }
+
+private:
+    SockNum::Ptr _num;
+    EventPoller::Ptr _poller;
+};
+
+template<class Mtx = std::recursive_mutex>
+class MutexWrapper {
+public:
+    MutexWrapper(bool enable) {
+        _enable = enable;
+    }
+
+    ~MutexWrapper() = default;
+
+    inline void lock() {
+        if (_enable) {
+            _mtx.lock();
+        }
+    }
+
+    inline void unlock() {
+        if (_enable) {
+            _mtx.unlock();
+        }
+    }
+
+private:
+    bool _enable;
+    Mtx _mtx;
+};
+
+class SockInfo {
+public:
+    SockInfo() = default;
+    virtual ~SockInfo() = default;
+
+    //获取本机ip
+    virtual std::string get_local_ip() = 0;
+    //获取本机端口号
+    virtual uint16_t get_local_port() = 0;
+    //获取对方ip
+    virtual std::string get_peer_ip() = 0;
+    //获取对方端口号
+    virtual uint16_t get_peer_port() = 0;
+    //获取标识符
+    virtual std::string getIdentifier() const { return ""; }
+};
+
+#define TraceP(ptr) TraceL << ptr->getIdentifier() << "(" << ptr->get_peer_ip() << ":" << ptr->get_peer_port() << ") "
+#define DebugP(ptr) DebugL << ptr->getIdentifier() << "(" << ptr->get_peer_ip() << ":" << ptr->get_peer_port() << ") "
+#define InfoP(ptr) InfoL << ptr->getIdentifier() << "(" << ptr->get_peer_ip() << ":" << ptr->get_peer_port() << ") "
+#define WarnP(ptr) WarnL << ptr->getIdentifier() << "(" << ptr->get_peer_ip() << ":" << ptr->get_peer_port() << ") "
+#define ErrorP(ptr) ErrorL << ptr->getIdentifier() << "(" << ptr->get_peer_ip() << ":" << ptr->get_peer_port() << ") "
+
+//异步IO Socket对象,包括tcp客户端、服务器和udp套接字
+class Socket : public std::enable_shared_from_this<Socket>, public noncopyable, public SockInfo {
+public:
+    using Ptr = std::shared_ptr<Socket>;
+    //接收数据回调
+    using onReadCB = std::function<void(const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len)>;
+    //发生错误回调
+    using onErrCB = std::function<void(const SockException &err)>;
+    //tcp监听接收到连接请求
+    using onAcceptCB = std::function<void(Socket::Ptr &sock, std::shared_ptr<void> &complete)>;
+    //socket发送缓存清空事件,返回true代表下次继续监听该事件,否则停止
+    using onFlush = std::function<bool()>;
+    //在接收到连接请求前,拦截Socket默认生成方式
+    using onCreateSocket = std::function<Ptr(const EventPoller::Ptr &poller)>;
+    //发送buffer成功与否回调
+    using onSendResult = BufferList::SendResult;
+
+    /**
+     * 构造socket对象,尚未有实质操作
+     * @param poller 绑定的poller线程
+     * @param enable_mutex 是否启用互斥锁(接口是否线程安全)
+    */
+    static Ptr createSocket(const EventPoller::Ptr &poller = nullptr, bool enable_mutex = true);
+    Socket(const EventPoller::Ptr &poller = nullptr, bool enable_mutex = true);
+    ~Socket() override;
+
+    /**
+     * 创建tcp客户端并异步连接服务器
+     * @param url 目标服务器ip或域名
+     * @param port 目标服务器端口
+     * @param con_cb 结果回调
+     * @param timeout_sec 超时时间
+     * @param local_ip 绑定本地网卡ip
+     * @param local_port 绑定本地网卡端口号
+     */
+    void connect(const std::string &url, uint16_t port, const onErrCB &con_cb, float timeout_sec = 5, const std::string &local_ip = "::", uint16_t local_port = 0);
+
+    /**
+     * 创建tcp监听服务器
+     * @param port 监听端口,0则随机
+     * @param local_ip 监听的网卡ip
+     * @param backlog tcp最大积压数
+     * @return 是否成功
+     */
+    bool listen(uint16_t port, const std::string &local_ip = "::", int backlog = 1024);
+
+    /**
+     * 创建udp套接字,udp是无连接的,所以可以作为服务器和客户端
+     * @param port 绑定的端口为0则随机
+     * @param local_ip 绑定的网卡ip
+     * @return 是否成功
+     */
+    bool bindUdpSock(uint16_t port, const std::string &local_ip = "::", bool enable_reuse = true);
+
+    /**
+     * 包装外部fd,本对象负责close fd
+     * 内部会设置fd为NoBlocked,NoSigpipe,CloExec
+     * 其他设置需要自行使用SockUtil进行设置
+     */
+    bool fromSock(int fd, SockNum::SockType type);
+
+    /**
+     * 从另外一个Socket克隆
+     * 目的是一个socket可以被多个poller对象监听,提高性能或实现Socket归属线程的迁移
+     * @param other 原始的socket对象
+     * @return 是否成功
+     */
+    bool cloneSocket(const Socket &other);
+
+    ////////////设置事件回调////////////
+
+    /**
+     * 设置数据接收回调,tcp或udp客户端有效
+     * @param cb 回调对象
+     */
+    void setOnRead(onReadCB cb);
+
+    /**
+     * 设置异常事件(包括eof等)回调
+     * @param cb 回调对象
+     */
+    void setOnErr(onErrCB cb);
+
+    /**
+     * 设置tcp监听接收到连接回调
+     * @param cb 回调对象
+     */
+    void setOnAccept(onAcceptCB cb);
+
+    /**
+     * 设置socket写缓存清空事件回调
+     * 通过该回调可以实现发送流控
+     * @param cb 回调对象
+     */
+    void setOnFlush(onFlush cb);
+
+    /**
+     * 设置accept时,socket构造事件回调
+     * @param cb 回调
+     */
+    void setOnBeforeAccept(onCreateSocket cb);
+
+    /**
+     * 设置发送buffer结果回调
+     * @param cb 回调
+     */
+    void setOnSendResult(onSendResult cb);
+
+    ////////////发送数据相关接口////////////
+
+    /**
+     * 发送数据指针
+     * @param buf 数据指针
+     * @param size 数据长度
+     * @param addr 目标地址
+     * @param addr_len 目标地址长度
+     * @param try_flush 是否尝试写socket
+     * @return -1代表失败(socket无效),0代表数据长度为0,否则返回数据长度
+     */
+    ssize_t send(const char *buf, size_t size = 0, struct sockaddr *addr = nullptr, socklen_t addr_len = 0, bool try_flush = true);
+
+    /**
+     * 发送string
+     */
+    ssize_t send(std::string buf, struct sockaddr *addr = nullptr, socklen_t addr_len = 0, bool try_flush = true);
+
+    /**
+     * 发送Buffer对象,Socket对象发送数据的统一出口
+     * socket对象发送数据的统一出口
+     */
+    ssize_t send(Buffer::Ptr buf, struct sockaddr *addr = nullptr, socklen_t addr_len = 0, bool try_flush = true);
+
+    /**
+     * 尝试将所有数据写socket
+     * @return -1代表失败(socket无效或者发送超时),0代表成功?
+     */
+    int flushAll();
+
+    /**
+     * 关闭socket且触发onErr回调,onErr回调将在poller线程中进行
+     * @param err 错误原因
+     * @return 是否成功触发onErr回调
+     */
+    bool emitErr(const SockException &err) noexcept;
+
+    /**
+     * 关闭或开启数据接收
+     * @param enabled 是否开启
+     */
+    void enableRecv(bool enabled);
+
+    /**
+     * 获取裸文件描述符,请勿进行close操作(因为Socket对象会管理其生命周期)
+     * @return 文件描述符
+     */
+    int rawFD() const;
+
+    /**
+     * tcp客户端是否处于连接状态
+     * 支持Sock_TCP类型socket
+     */
+    bool alive() const;
+
+    /**
+     * 返回socket类型
+     */
+    SockNum::SockType sockType() const;
+
+    /**
+     * 设置发送超时主动断开时间;默认10秒
+     * @param second 发送超时数据,单位秒
+     */
+    void setSendTimeOutSecond(uint32_t second);
+
+    /**
+     * 套接字是否忙,如果套接字写缓存已满则返回true
+     * @return 套接字是否忙
+     */
+    bool isSocketBusy() const;
+
+    /**
+     * 获取poller线程对象
+     * @return poller线程对象
+     */
+    const EventPoller::Ptr &getPoller() const;
+
+    /**
+     * 绑定udp 目标地址,后续发送时就不用再单独指定了
+     * @param dst_addr 目标地址
+     * @param addr_len 目标地址长度
+     * @return 是否成功
+     */
+    bool bindPeerAddr(const struct sockaddr *dst_addr, socklen_t addr_len = 0);
+
+    /**
+     * 设置发送flags
+     * @param flags 发送的flag
+     */
+    void setSendFlags(int flags = SOCKET_DEFAULE_FLAGS);
+
+    /**
+     * 关闭套接字
+     * @param close_fd 是否关闭fd还是只移除io事件监听
+     */
+    void closeSock(bool close_fd = true);
+
+    /**
+     * 获取发送缓存包个数(不是字节数)
+     */
+    size_t getSendBufferCount();
+
+    /**
+     * 获取上次socket发送缓存清空至今的毫秒数,单位毫秒
+     */
+    uint64_t elapsedTimeAfterFlushed();
+
+    /**
+     * 获取接收速率,单位bytes/s
+     */
+    int getRecvSpeed();
+
+    /**
+     * 获取发送速率,单位bytes/s
+     */
+    int getSendSpeed();
+
+    ////////////SockInfo override////////////
+    std::string get_local_ip() override;
+    uint16_t get_local_port() override;
+    std::string get_peer_ip() override;
+    uint16_t get_peer_port() override;
+    std::string getIdentifier() const override;
+
+private:
+    SockFD::Ptr cloneSockFD(const Socket &other);
+    SockFD::Ptr makeSock(int sock, SockNum::SockType type);
+    void setPeerSock(int fd, SockNum::SockType type);
+    int onAccept(int sock, int event) noexcept;
+    ssize_t onRead(int sock, SockNum::SockType type, const BufferRaw::Ptr &buffer) noexcept;
+    void onWriteAble(int sock, SockNum::SockType type);
+    void onConnected(int sock, const onErrCB &cb);
+    void onFlushed();
+    void startWriteAbleEvent(int sock);
+    void stopWriteAbleEvent(int sock);
+    bool listen(const SockFD::Ptr &sock);
+    bool flushData(int sock, SockNum::SockType type, bool poller_thread);
+    bool attachEvent(int sock, SockNum::SockType type);
+    ssize_t send_l(Buffer::Ptr buf, bool is_buf_sock, bool try_flush = true);
+    void connect_l(const std::string &url, uint16_t port, const onErrCB &con_cb_in, float timeout_sec, const std::string &local_ip, uint16_t local_port);
+    bool fromSock_l(int fd, SockNum::SockType type);
+
+private:
+    //send socket时的flag
+    int _sock_flags = SOCKET_DEFAULE_FLAGS;
+    //最大发送缓存,单位毫秒,距上次发送缓存清空时间不能超过该参数
+    uint32_t _max_send_buffer_ms = SEND_TIME_OUT_SEC * 1000;
+    //控制是否接收监听socket可读事件,关闭后可用于流量控制
+    std::atomic<bool> _enable_recv {true};
+    //标记该socket是否可写,socket写缓存满了就不可写
+    std::atomic<bool> _sendable {true};
+    //是否已经触发err回调了
+    bool _err_emit = false;
+    //是否启用网速统计
+    bool _enable_speed = false;
+    //接收速率统计
+    BytesSpeed _recv_speed;
+    //发送速率统计
+    BytesSpeed _send_speed;
+
+    //tcp连接超时定时器
+    Timer::Ptr _con_timer;
+    //tcp连接结果回调对象
+    std::shared_ptr<std::function<void(int)> > _async_con_cb;
+
+    //记录上次发送缓存(包括socket写缓存、应用层缓存)清空的计时器
+    Ticker _send_flush_ticker;
+    //socket fd的抽象类
+    SockFD::Ptr _sock_fd;
+    //本socket绑定的poller线程,事件触发于此线程
+    EventPoller::Ptr _poller;
+    //跨线程访问_sock_fd时需要上锁
+    mutable MutexWrapper<std::recursive_mutex> _mtx_sock_fd;
+
+    //socket异常事件(比如说断开)
+    onErrCB _on_err;
+    //收到数据事件
+    onReadCB _on_read;
+    //socket缓存清空事件(可用于发送流速控制)
+    onFlush _on_flush;
+    //tcp监听收到accept请求事件
+    onAcceptCB _on_accept;
+    //tcp监听收到accept请求,自定义创建peer Socket事件(可以控制子Socket绑定到其他poller线程)
+    onCreateSocket _on_before_accept;
+    //设置上述回调函数的锁
+    MutexWrapper<std::recursive_mutex> _mtx_event;
+
+    //一级发送缓存, socket可写时,会把一级缓存批量送入到二级缓存
+    List<std::pair<Buffer::Ptr, bool> > _send_buf_waiting;
+    //一级发送缓存锁
+    MutexWrapper<std::recursive_mutex> _mtx_send_buf_waiting;
+    //二级发送缓存, socket可写时,会把二级缓存批量写入到socket
+    List<BufferList::Ptr> _send_buf_sending;
+    //二级发送缓存锁
+    MutexWrapper<std::recursive_mutex> _mtx_send_buf_sending;
+    //发送buffer结果回调
+    BufferList::SendResult _send_result;
+    //对象个数统计
+    ObjectStatistic<Socket> _statistic;
+};
+
+class SockSender {
+public:
+    SockSender() = default;
+    virtual ~SockSender() = default;
+    virtual ssize_t send(Buffer::Ptr buf) = 0;
+    virtual void shutdown(const SockException &ex = SockException(Err_shutdown, "self shutdown")) = 0;
+
+    //发送char *
+    SockSender &operator << (const char *buf);
+    //发送字符串
+    SockSender &operator << (std::string buf);
+    //发送Buffer对象
+    SockSender &operator << (Buffer::Ptr buf);
+
+    //发送其他类型是数据
+    template<typename T>
+    SockSender &operator << (T &&buf) {
+        std::ostringstream ss;
+        ss << std::forward<T>(buf);
+        send(ss.str());
+        return *this;
+    }
+
+    ssize_t send(std::string buf);
+    ssize_t send(const char *buf, size_t size = 0);
+};
+
+//Socket对象的包装类
+class SocketHelper : public SockSender, public SockInfo, public TaskExecutorInterface, public std::enable_shared_from_this<SocketHelper> {
+public:
+    using Ptr = std::shared_ptr<SocketHelper>;
+    SocketHelper(const Socket::Ptr &sock);
+    ~SocketHelper() override = default;
+
+    ///////////////////// Socket util std::functions /////////////////////
+    /**
+     * 获取poller线程
+     */
+    const EventPoller::Ptr& getPoller() const;
+
+    /**
+     * 设置批量发送标记,用于提升性能
+     * @param try_flush 批量发送标记
+     */
+    void setSendFlushFlag(bool try_flush);
+
+    /**
+     * 设置socket发送flags
+     * @param flags socket发送flags
+     */
+    void setSendFlags(int flags);
+
+    /**
+     * 套接字是否忙,如果套接字写缓存已满则返回true
+     */
+    bool isSocketBusy() const;
+
+    /**
+     * 设置Socket创建器,自定义Socket创建方式
+     * @param cb 创建器
+     */
+    void setOnCreateSocket(Socket::onCreateSocket cb);
+
+    /**
+     * 创建socket对象
+     */
+    Socket::Ptr createSocket();
+
+    /**
+     * 获取socket对象
+     */
+    const Socket::Ptr &getSock() const;
+
+    /**
+     * 尝试将所有数据写socket
+     * @return -1代表失败(socket无效或者发送超时),0代表成功?
+     */
+    int flushAll();
+
+    /**
+     * 是否ssl加密
+     */
+    virtual bool overSsl() const { return false; }
+
+    ///////////////////// SockInfo override /////////////////////
+    std::string get_local_ip() override;
+    uint16_t get_local_port() override;
+    std::string get_peer_ip() override;
+    uint16_t get_peer_port() override;
+
+    ///////////////////// TaskExecutorInterface override /////////////////////
+    /**
+     * 任务切换到所属poller线程执行
+     * @param task 任务
+     * @param may_sync 是否运行同步执行任务
+     */
+    Task::Ptr async(TaskIn task, bool may_sync = true) override;
+    Task::Ptr async_first(TaskIn task, bool may_sync = true) override;
+
+    ///////////////////// SockSender override /////////////////////
+    /**
+     * 统一发送数据的出口
+     */
+    ssize_t send(Buffer::Ptr buf) override;
+
+    /**
+     * 触发onErr事件
+     */
+    void shutdown(const SockException &ex = SockException(Err_shutdown, "self shutdown")) override;
+
+    /**
+     * 线程安全的脱离 Server 并触发 onError 事件
+     * @param ex 触发 onError 事件的原因
+     */
+    void safeShutdown(const SockException &ex = SockException(Err_shutdown, "self shutdown"));
+
+    ///////////////////// event functions /////////////////////
+    /**
+     * 接收数据入口
+     * @param buf 数据,可以重复使用内存区,不可被缓存使用
+     */
+    virtual void onRecv(const Buffer::Ptr &buf) = 0;
+
+    /**
+     * 收到 eof 或其他导致脱离 Server 事件的回调
+     * 收到该事件时, 该对象一般将立即被销毁
+     * @param err 原因
+     */
+    virtual void onError(const SockException &err) = 0;
+
+    /**
+     * 数据全部发送完毕后回调
+     */
+    virtual void onFlush() {}
+
+    /**
+     * 每隔一段时间触发, 用来做超时管理
+     */
+    virtual void onManager() = 0;
+
+protected:
+    void setPoller(const EventPoller::Ptr &poller);
+    void setSock(const Socket::Ptr &sock);
+
+private:
+    bool _try_flush = true;
+    Socket::Ptr _sock;
+    EventPoller::Ptr _poller;
+    Socket::onCreateSocket _on_create_socket;
+};
+
+}  // namespace toolkit
+#endif /* NETWORK_SOCKET_H */

+ 173 - 0
3rdparty/ZLToolKit/include/Network/TcpClient.h

@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef NETWORK_TCPCLIENT_H
+#define NETWORK_TCPCLIENT_H
+
+#include <memory>
+#include "Socket.h"
+#include "Util/SSLBox.h"
+
+namespace toolkit {
+
+//Tcp客户端,Socket对象默认开始互斥锁
+class TcpClient : public SocketHelper {
+public:
+    using Ptr = std::shared_ptr<TcpClient>;
+    TcpClient(const EventPoller::Ptr &poller = nullptr);
+    ~TcpClient() override;
+
+    /**
+     * 开始连接tcp服务器
+     * @param url 服务器ip或域名
+     * @param port 服务器端口
+     * @param timeout_sec 超时时间,单位秒
+     * @param local_port 本地端口
+     */
+    virtual void startConnect(const std::string &url, uint16_t port, float timeout_sec = 5, uint16_t local_port = 0);
+    
+    /**
+     * 通过代理开始连接tcp服务器
+     * @param url 服务器ip或域名
+     * @proxy_host 代理ip
+     * @proxy_port 代理端口
+     * @param timeout_sec 超时时间,单位秒
+     * @param local_port 本地端口
+     */
+    virtual void startConnectWithProxy(const std::string &url, const std::string &proxy_host, uint16_t proxy_port, float timeout_sec = 5, uint16_t local_port = 0){};
+    
+    /**
+     * 主动断开连接
+     * @param ex 触发onErr事件时的参数
+     */
+    void shutdown(const SockException &ex = SockException(Err_shutdown, "self shutdown")) override;
+
+    /**
+     * 连接中或已连接返回true,断开连接时返回false
+     */
+    virtual bool alive() const;
+
+    /**
+     * 设置网卡适配器,使用该网卡与服务器通信
+     * @param local_ip 本地网卡ip
+     */
+    virtual void setNetAdapter(const std::string &local_ip);
+
+    /**
+     * 唯一标识
+     */
+    std::string getIdentifier() const override;
+
+protected:
+    /**
+     * 连接服务器结果回调
+     * @param ex 成功与否
+     */
+    virtual void onConnect(const SockException &ex) = 0;
+
+    /**
+     * tcp连接成功后每2秒触发一次该事件
+     */
+    void onManager() override {}
+
+private:
+    void onSockConnect(const SockException &ex);
+
+private:
+    mutable std::string _id;
+    std::string _net_adapter = "::";
+    std::shared_ptr<Timer> _timer;
+    //对象个数统计
+    ObjectStatistic<TcpClient> _statistic;
+};
+
+//用于实现TLS客户端的模板对象
+template<typename TcpClientType>
+class TcpClientWithSSL : public TcpClientType {
+public:
+    using Ptr = std::shared_ptr<TcpClientWithSSL>;
+
+    template<typename ...ArgsType>
+    TcpClientWithSSL(ArgsType &&...args):TcpClientType(std::forward<ArgsType>(args)...) {}
+
+    ~TcpClientWithSSL() override {
+        if (_ssl_box) {
+            _ssl_box->flush();
+        }
+    }
+
+    void onRecv(const Buffer::Ptr &buf) override {
+        if (_ssl_box) {
+            _ssl_box->onRecv(buf);
+        } else {
+            TcpClientType::onRecv(buf);
+        }
+    }
+
+    ssize_t send(Buffer::Ptr buf) override {
+        if (_ssl_box) {
+            auto size = buf->size();
+            _ssl_box->onSend(std::move(buf));
+            return size;
+        }
+        return TcpClientType::send(std::move(buf));
+    }
+
+    //添加public_onRecv和public_send函数是解决较低版本gcc一个lambad中不能访问protected或private方法的bug
+    inline void public_onRecv(const Buffer::Ptr &buf) {
+        TcpClientType::onRecv(buf);
+    }
+
+    inline void public_send(const Buffer::Ptr &buf) {
+        TcpClientType::send(std::move(const_cast<Buffer::Ptr &>(buf)));
+    }
+
+    void startConnect(const std::string &url, uint16_t port, float timeout_sec = 5, uint16_t local_port = 0) override {
+        _host = url;
+        TcpClientType::startConnect(url, port, timeout_sec, local_port);
+    }
+    void startConnectWithProxy(const std::string &url, const std::string &proxy_host, uint16_t proxy_port, float timeout_sec = 5, uint16_t local_port = 0) override {
+        _host = url;
+        TcpClientType::startConnect(proxy_host, proxy_port, timeout_sec, local_port);
+    }
+
+    bool overSsl() const override { return (bool)_ssl_box; }
+
+protected:
+    void onConnect(const SockException &ex) override {
+        if (!ex) {
+            _ssl_box = std::make_shared<SSL_Box>(false);
+            _ssl_box->setOnDecData([this](const Buffer::Ptr &buf) {
+                public_onRecv(buf);
+            });
+            _ssl_box->setOnEncData([this](const Buffer::Ptr &buf) {
+                public_send(buf);
+            });
+
+            if (!isIP(_host.data())) {
+                //设置ssl域名
+                _ssl_box->setHost(_host.data());
+            }
+        }
+        TcpClientType::onConnect(ex);
+    }
+    /**
+     * 重置ssl, 主要为了解决一些302跳转时http与https的转换
+     */
+    void setDoNotUseSSL() {
+        _ssl_box.reset();
+    }
+private:
+    std::string _host;
+    std::shared_ptr<SSL_Box> _ssl_box;
+};
+
+} /* namespace toolkit */
+#endif /* NETWORK_TCPCLIENT_H */

+ 105 - 0
3rdparty/ZLToolKit/include/Network/TcpServer.h

@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef TCPSERVER_TCPSERVER_H
+#define TCPSERVER_TCPSERVER_H
+
+#include <memory>
+#include <functional>
+#include <unordered_map>
+#include "Server.h"
+#include "Session.h"
+#include "Poller/Timer.h"
+#include "Util/util.h"
+
+namespace toolkit {
+
+//TCP服务器,可配置的;配置通过Session::attachServer方法传递给会话对象
+class TcpServer : public Server {
+public:
+    using Ptr = std::shared_ptr<TcpServer>;
+
+    /**
+     * 创建tcp服务器,listen fd的accept事件会加入到所有的poller线程中监听
+     * 在调用TcpServer::start函数时,内部会创建多个子TcpServer对象,
+     * 这些子TcpServer对象通过Socket对象克隆的方式在多个poller线程中监听同一个listen fd
+     * 这样这个TCP服务器将会通过抢占式accept的方式把客户端均匀的分布到不同的poller线程
+     * 通过该方式能实现客户端负载均衡以及提高连接接收速度
+     */
+    explicit TcpServer(const EventPoller::Ptr &poller = nullptr);
+    ~TcpServer() override;
+
+    /**
+    * @brief 开始tcp server
+    * @param port 本机端口,0则随机
+    * @param host 监听网卡ip
+    * @param backlog tcp listen backlog
+    */
+    template<typename SessionType>
+    void start(uint16_t port, const std::string &host = "::", uint32_t backlog = 1024) {
+        static std::string cls_name = toolkit::demangle(typeid(SessionType).name());
+        //Session创建器,通过它创建不同类型的服务器
+        _session_alloc = [](const TcpServer::Ptr &server, const Socket::Ptr &sock) {
+            auto session = std::shared_ptr<SessionType>(new SessionType(sock), [](SessionType * ptr) {
+                TraceP(static_cast<Session *>(ptr)) << "~" << cls_name;
+                delete ptr;
+            });
+            TraceP(static_cast<Session *>(session.get())) << cls_name;
+            session->setOnCreateSocket(server->_on_create_socket);
+            return std::make_shared<SessionHelper>(server, std::move(session), cls_name);
+        };
+        start_l(port, host, backlog);
+    }
+
+    /**
+     * @brief 获取服务器监听端口号, 服务器可以选择监听随机端口
+     */
+    uint16_t getPort();
+
+    /**
+     * @brief 自定义socket构建行为
+     */
+    void setOnCreateSocket(Socket::onCreateSocket cb);
+
+    /**
+     * 根据socket对象创建Session对象
+     * 需要确保在socket归属poller线程执行本函数
+     */
+    Session::Ptr createSession(const Socket::Ptr &socket);
+
+protected:
+    virtual void cloneFrom(const TcpServer &that);
+    virtual TcpServer::Ptr onCreatServer(const EventPoller::Ptr &poller);
+
+    virtual Session::Ptr onAcceptConnection(const Socket::Ptr &sock);
+    virtual Socket::Ptr onBeforeAcceptConnection(const EventPoller::Ptr &poller);
+
+private:
+    void onManagerSession();
+    Socket::Ptr createSocket(const EventPoller::Ptr &poller);
+    void start_l(uint16_t port, const std::string &host, uint32_t backlog);
+    Ptr getServer(const EventPoller *) const;
+    void setupEvent();
+
+private:
+    bool _is_on_manager = false;
+    const TcpServer *_parent = nullptr;
+    Socket::Ptr _socket;
+    std::shared_ptr<Timer> _timer;
+    Socket::onCreateSocket _on_create_socket;
+    std::unordered_map<SessionHelper *, SessionHelper::Ptr> _session_map;
+    std::function<SessionHelper::Ptr(const TcpServer::Ptr &server, const Socket::Ptr &)> _session_alloc;
+    std::unordered_map<const EventPoller *, Ptr> _cloned_server;
+    //对象个数统计
+    ObjectStatistic<TcpServer> _statistic;
+};
+
+} /* namespace toolkit */
+#endif /* TCPSERVER_TCPSERVER_H */

+ 123 - 0
3rdparty/ZLToolKit/include/Network/UdpServer.h

@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2021 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef TOOLKIT_NETWORK_UDPSERVER_H
+#define TOOLKIT_NETWORK_UDPSERVER_H
+
+#include "Server.h"
+#include "Session.h"
+
+namespace toolkit {
+
+class UdpServer : public Server {
+public:
+    using Ptr = std::shared_ptr<UdpServer>;
+    using PeerIdType = std::string;
+    using onCreateSocket = std::function<Socket::Ptr(const EventPoller::Ptr &, const Buffer::Ptr &, struct sockaddr *, int)>;
+
+    explicit UdpServer(const EventPoller::Ptr &poller = nullptr);
+    ~UdpServer() override;
+
+    /**
+     * @brief 开始监听服务器
+     */
+    template<typename SessionType>
+    void start(uint16_t port, const std::string &host = "::") {
+        static std::string cls_name = toolkit::demangle(typeid(SessionType).name());
+        // Session 创建器, 通过它创建不同类型的服务器
+        _session_alloc = [](const UdpServer::Ptr &server, const Socket::Ptr &sock) {
+            auto session = std::shared_ptr<SessionType>(new SessionType(sock), [](SessionType * ptr) {
+                TraceP(static_cast<Session *>(ptr)) << "~" << cls_name;
+                delete ptr;
+            });
+            TraceP(static_cast<Session *>(session.get())) << cls_name;
+            auto sock_creator = server->_on_create_socket;
+            session->setOnCreateSocket([sock_creator](const EventPoller::Ptr &poller) {
+                return sock_creator(poller, nullptr, nullptr, 0);
+            });
+            return std::make_shared<SessionHelper>(server, std::move(session), cls_name);
+        };
+        start_l(port, host);
+    }
+
+    /**
+     * @brief 获取服务器监听端口号, 服务器可以选择监听随机端口
+     */
+    uint16_t getPort();
+
+    /**
+     * @brief 自定义socket构建行为
+     */
+    void setOnCreateSocket(onCreateSocket cb);
+
+protected:
+    virtual Ptr onCreatServer(const EventPoller::Ptr &poller);
+    virtual void cloneFrom(const UdpServer &that);
+
+private:
+    /**
+     * @brief 开始udp server
+     * @param port 本机端口,0则随机
+     * @param host 监听网卡ip
+     */
+    void start_l(uint16_t port, const std::string &host = "::");
+
+    /**
+     * @brief 定时管理 Session, UDP 会话需要根据需要处理超时
+     */
+    void onManagerSession();
+
+    void onRead(const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len);
+
+    /**
+     * @brief 接收到数据,可能来自server fd,也可能来自peer fd
+     * @param is_server_fd 时候为server fd
+     * @param id 客户端id
+     * @param buf 数据
+     * @param addr 客户端地址
+     * @param addr_len 客户端地址长度
+     */
+    void onRead_l(bool is_server_fd, const PeerIdType &id, const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len);
+
+    /**
+     * @brief 根据对端信息获取或创建一个会话
+     */
+    Session::Ptr getOrCreateSession(const PeerIdType &id, const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len, bool &is_new);
+
+    /**
+     * @brief 创建一个会话, 同时进行必要的设置
+     */
+    Session::Ptr createSession(const PeerIdType &id, const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len);
+
+    /**
+     * @brief 创建socket
+     */
+    Socket::Ptr createSocket(const EventPoller::Ptr &poller, const Buffer::Ptr &buf = nullptr, struct sockaddr *addr = nullptr, int addr_len = 0);
+
+    void setupEvent();
+
+private:
+    bool _cloned = false;
+    Socket::Ptr _socket;
+    std::shared_ptr<Timer> _timer;
+    onCreateSocket _on_create_socket;
+    //cloned server共享主server的session map,防止数据在不同server间漂移
+    std::shared_ptr<std::recursive_mutex> _session_mutex;
+    std::shared_ptr<std::unordered_map<PeerIdType, SessionHelper::Ptr> > _session_map;
+    //主server持有cloned server的引用
+    std::unordered_map<EventPoller *, Ptr> _cloned_server;
+    std::function<SessionHelper::Ptr(const UdpServer::Ptr &, const Socket::Ptr &)> _session_alloc;
+    // 对象个数统计
+    ObjectStatistic<UdpServer> _statistic;
+};
+
+} // namespace toolkit
+
+#endif // TOOLKIT_NETWORK_UDPSERVER_H

+ 347 - 0
3rdparty/ZLToolKit/include/Network/sockutil.h

@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef NETWORK_SOCKUTIL_H
+#define NETWORK_SOCKUTIL_H
+
+#if defined(_WIN32)
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <iphlpapi.h>
+#pragma comment (lib, "Ws2_32.lib")
+#pragma comment(lib,"Iphlpapi.lib")
+#else
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#endif // defined(_WIN32)
+
+#include <cstring>
+#include <cstdint>
+#include <map>
+#include <vector>
+#include <string>
+
+namespace toolkit {
+
+#if defined(_WIN32)
+#ifndef socklen_t
+#define socklen_t int
+#endif //!socklen_t
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 2
+#endif //!SHUT_RDWR
+int ioctl(int fd, long cmd, u_long *ptr);
+int close(int fd);
+#endif // defined(_WIN32)
+
+#define SOCKET_DEFAULT_BUF_SIZE (256 * 1024)
+#define TCP_KEEPALIVE_INTERVAL 30
+#define TCP_KEEPALIVE_PROBE_TIMES 9
+#define TCP_KEEPALIVE_TIME 120
+
+//套接字工具类,封装了socket、网络的一些基本操作
+class SockUtil {
+public:
+    /**
+     * 创建tcp客户端套接字并连接服务器
+     * @param host 服务器ip或域名
+     * @param port 服务器端口号
+     * @param async 是否异步连接
+     * @param local_ip 绑定的本地网卡ip
+     * @param local_port 绑定的本地端口号
+     * @return -1代表失败,其他为socket fd号
+     */
+    static int connect(const char *host, uint16_t port, bool async = true, const char *local_ip = "::", uint16_t local_port = 0);
+
+    /**
+     * 创建tcp监听套接字
+     * @param port 监听的本地端口
+     * @param local_ip 绑定的本地网卡ip
+     * @param back_log accept列队长度
+     * @return -1代表失败,其他为socket fd号
+     */
+    static int listen(const uint16_t port, const char *local_ip = "::", int back_log = 1024);
+
+    /**
+     * 创建udp套接字
+     * @param port 监听的本地端口
+     * @param local_ip 绑定的本地网卡ip
+     * @param enable_reuse 是否允许重复bind端口
+     * @return -1代表失败,其他为socket fd号
+     */
+    static int bindUdpSock(const uint16_t port, const char *local_ip = "::", bool enable_reuse = true);
+
+    /**
+     * @brief 解除与 sock 相关的绑定关系
+     * @param sock, socket fd 号
+     * @return 0 成功, -1 失败
+     */
+    static int dissolveUdpSock(int sock);
+
+    /**
+     * 开启TCP_NODELAY,降低TCP交互延时
+     * @param fd socket fd号
+     * @param on 是否开启
+     * @return 0代表成功,-1为失败
+     */
+    static int setNoDelay(int fd, bool on = true);
+
+    /**
+     * 写socket不触发SIG_PIPE信号(貌似只有mac有效)
+     * @param fd socket fd号
+     * @return 0代表成功,-1为失败
+     */
+    static int setNoSigpipe(int fd);
+
+    /**
+     * 设置读写socket是否阻塞
+     * @param fd socket fd号
+     * @param noblock 是否阻塞
+     * @return 0代表成功,-1为失败
+     */
+    static int setNoBlocked(int fd, bool noblock = true);
+
+    /**
+     * 设置socket接收缓存,默认貌似8K左右,一般有设置上限
+     * 可以通过配置内核配置文件调整
+     * @param fd socket fd号
+     * @param size 接收缓存大小
+     * @return 0代表成功,-1为失败
+     */
+    static int setRecvBuf(int fd, int size = SOCKET_DEFAULT_BUF_SIZE);
+
+    /**
+     * 设置socket接收缓存,默认貌似8K左右,一般有设置上限
+     * 可以通过配置内核配置文件调整
+     * @param fd socket fd号
+     * @param size 接收缓存大小
+     * @return 0代表成功,-1为失败
+     */
+    static int setSendBuf(int fd, int size = SOCKET_DEFAULT_BUF_SIZE);
+
+    /**
+     * 设置后续可绑定复用端口(处于TIME_WAITE状态)
+     * @param fd socket fd号
+     * @param on 是否开启该特性
+     * @return 0代表成功,-1为失败
+     */
+    static int setReuseable(int fd, bool on = true, bool reuse_port = true);
+
+    /**
+     * 运行发送或接收udp广播信息
+     * @param fd socket fd号
+     * @param on 是否开启该特性
+     * @return 0代表成功,-1为失败
+     */
+    static int setBroadcast(int fd, bool on = true);
+
+    /**
+     * 是否开启TCP KeepAlive特性
+     * @param fd socket fd号
+     * @param on 是否开启该特性
+     * @param idle keepalive空闲时间
+     * @param interval keepalive探测时间间隔
+     * @param times keepalive探测次数
+     * @return 0代表成功,-1为失败
+     */
+    static int setKeepAlive(int fd, bool on = true, int interval = TCP_KEEPALIVE_INTERVAL, int idle = TCP_KEEPALIVE_TIME, int times = TCP_KEEPALIVE_PROBE_TIMES);
+
+    /**
+     * 是否开启FD_CLOEXEC特性(多进程相关)
+     * @param fd fd号,不一定是socket
+     * @param on 是否开启该特性
+     * @return 0代表成功,-1为失败
+     */
+    static int setCloExec(int fd, bool on = true);
+
+    /**
+     * 开启SO_LINGER特性
+     * @param sock socket fd号
+     * @param second 内核等待关闭socket超时时间,单位秒
+     * @return 0代表成功,-1为失败
+     */
+    static int setCloseWait(int sock, int second = 0);
+
+    /**
+     * dns解析
+     * @param host 域名或ip
+     * @param port 端口号
+     * @param addr sockaddr结构体
+     * @return 是否成功
+     */
+    static bool getDomainIP(const char *host, uint16_t port, struct sockaddr_storage &addr, int ai_family = AF_INET,
+                            int ai_socktype = SOCK_STREAM, int ai_protocol = IPPROTO_TCP, int expire_sec = 60);
+
+    /**
+     * 设置组播ttl
+     * @param sock socket fd号
+     * @param ttl ttl值
+     * @return 0代表成功,-1为失败
+     */
+    static int setMultiTTL(int sock, uint8_t ttl = 64);
+
+    /**
+     * 设置组播发送网卡
+     * @param sock socket fd号
+     * @param local_ip 本机网卡ip
+     * @return 0代表成功,-1为失败
+     */
+    static int setMultiIF(int sock, const char *local_ip);
+
+    /**
+     * 设置是否接收本机发出的组播包
+     * @param fd socket fd号
+     * @param acc 是否接收
+     * @return 0代表成功,-1为失败
+     */
+    static int setMultiLOOP(int fd, bool acc = false);
+
+    /**
+     * 加入组播
+     * @param fd socket fd号
+     * @param addr 组播地址
+     * @param local_ip 本机网卡ip
+     * @return 0代表成功,-1为失败
+     */
+    static int joinMultiAddr(int fd, const char *addr, const char *local_ip = "0.0.0.0");
+
+    /**
+     * 退出组播
+     * @param fd socket fd号
+     * @param addr 组播地址
+     * @param local_ip 本机网卡ip
+     * @return 0代表成功,-1为失败
+     */
+    static int leaveMultiAddr(int fd, const char *addr, const char *local_ip = "0.0.0.0");
+
+    /**
+     * 加入组播并只接受该源端的组播数据
+     * @param sock socket fd号
+     * @param addr 组播地址
+     * @param src_ip 数据源端地址
+     * @param local_ip  本机网卡ip
+     * @return 0代表成功,-1为失败
+     */
+    static int joinMultiAddrFilter(int sock, const char *addr, const char *src_ip, const char *local_ip = "0.0.0.0");
+
+    /**
+     * 退出组播
+     * @param fd socket fd号
+     * @param addr 组播地址
+     * @param src_ip 数据源端地址
+     * @param local_ip  本机网卡ip
+     * @return 0代表成功,-1为失败
+     */
+    static int leaveMultiAddrFilter(int fd, const char *addr, const char *src_ip, const char *local_ip = "0.0.0.0");
+
+    /**
+     * 获取该socket当前发生的错误
+     * @param fd socket fd号
+     * @return 错误代码
+     */
+    static int getSockError(int fd);
+
+    /**
+     * 获取网卡列表
+     * @return vector<map<ip:name> >
+     */
+    static std::vector<std::map<std::string, std::string>> getInterfaceList();
+
+    /**
+     * 获取本机默认网卡ip
+     */
+    static std::string get_local_ip();
+
+    /**
+     * 获取该socket绑定的本地ip
+     * @param sock socket fd号
+     */
+    static std::string get_local_ip(int sock);
+
+    /**
+     * 获取该socket绑定的本地端口
+     * @param sock socket fd号
+     */
+    static uint16_t get_local_port(int sock);
+
+    /**
+     * 获取该socket绑定的远端ip
+     * @param sock socket fd号
+     */
+    static std::string get_peer_ip(int sock);
+
+    /**
+     * 获取该socket绑定的远端端口
+     * @param sock socket fd号
+     */
+    static uint16_t get_peer_port(int sock);
+
+    static bool support_ipv6();
+    /**
+     * 线程安全的in_addr转ip字符串
+     */
+    static std::string inet_ntoa(const struct in_addr &addr);
+    static std::string inet_ntoa(const struct in6_addr &addr);
+    static std::string inet_ntoa(const struct sockaddr *addr);
+    static uint16_t inet_port(const struct sockaddr *addr);
+    static struct sockaddr_storage make_sockaddr(const char *ip, uint16_t port);
+    static socklen_t get_sock_len(const struct sockaddr *addr);
+    static bool get_sock_local_addr(int fd, struct sockaddr_storage &addr);
+    static bool get_sock_peer_addr(int fd, struct sockaddr_storage &addr);
+
+    /**
+     * 获取网卡ip
+     * @param if_name 网卡名
+     */
+    static std::string get_ifr_ip(const char *if_name);
+
+    /**
+     * 获取网卡名
+     * @param local_op 网卡ip
+     */
+    static std::string get_ifr_name(const char *local_op);
+
+    /**
+     * 根据网卡名获取子网掩码
+     * @param if_name 网卡名
+     */
+    static std::string get_ifr_mask(const char *if_name);
+
+    /**
+     * 根据网卡名获取广播地址
+     * @param if_name 网卡名
+     */
+    static std::string get_ifr_brdaddr(const char *if_name);
+
+    /**
+     * 判断两个ip是否为同一网段
+     * @param src_ip 我的ip
+     * @param dts_ip 对方ip
+     */
+    static bool in_same_lan(const char *src_ip, const char *dts_ip);
+
+    /**
+     * 判断是否为ipv4地址
+     */
+    static bool is_ipv4(const char *str);
+
+    /**
+     * 判断是否为ipv6地址
+     */
+    static bool is_ipv6(const char *str);
+};
+
+}  // namespace toolkit
+#endif // !NETWORK_SOCKUTIL_H

+ 290 - 0
3rdparty/ZLToolKit/include/Poller/EventPoller.h

@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef EventPoller_h
+#define EventPoller_h
+
+#include <mutex>
+#include <thread>
+#include <string>
+#include <functional>
+#include <memory>
+#include <unordered_map>
+#include "PipeWrap.h"
+#include "Util/logger.h"
+#include "Util/List.h"
+#include "Thread/TaskExecutor.h"
+#include "Thread/ThreadPool.h"
+#include "Network/Buffer.h"
+
+#if defined(__linux__) || defined(__linux)
+#define HAS_EPOLL
+#endif //__linux__
+
+namespace toolkit {
+
+class EventPoller : public TaskExecutor, public AnyStorage, public std::enable_shared_from_this<EventPoller> {
+public:
+    friend class TaskExecutorGetterImp;
+
+    using Ptr = std::shared_ptr<EventPoller>;
+    using PollEventCB = std::function<void(int event)>;
+    using PollDelCB = std::function<void(bool success)>;
+    using DelayTask = TaskCancelableImp<uint64_t(void)>;
+
+    typedef enum {
+        Event_Read = 1 << 0, //读事件
+        Event_Write = 1 << 1, //写事件
+        Event_Error = 1 << 2, //错误事件
+        Event_LT = 1 << 3,//水平触发
+    } Poll_Event;
+
+    ~EventPoller();
+
+    /**
+     * 获取EventPollerPool单例中的第一个EventPoller实例,
+     * 保留该接口是为了兼容老代码
+     * @return 单例
+     */
+    static EventPoller &Instance();
+
+    /**
+     * 添加事件监听
+     * @param fd 监听的文件描述符
+     * @param event 事件类型,例如 Event_Read | Event_Write
+     * @param cb 事件回调functional
+     * @return -1:失败,0:成功
+     */
+    int addEvent(int fd, int event, PollEventCB cb);
+
+    /**
+     * 删除事件监听
+     * @param fd 监听的文件描述符
+     * @param cb 删除成功回调functional
+     * @return -1:失败,0:成功
+     */
+    int delEvent(int fd, PollDelCB cb = nullptr);
+
+    /**
+     * 修改监听事件类型
+     * @param fd 监听的文件描述符
+     * @param event 事件类型,例如 Event_Read | Event_Write
+     * @return -1:失败,0:成功
+     */
+    int modifyEvent(int fd, int event);
+
+    /**
+     * 异步执行任务
+     * @param task 任务
+     * @param may_sync 如果调用该函数的线程就是本对象的轮询线程,那么may_sync为true时就是同步执行任务
+     * @return 是否成功,一定会返回true
+     */
+    Task::Ptr async(TaskIn task, bool may_sync = true) override;
+
+    /**
+     * 同async方法,不过是把任务打入任务列队头,这样任务优先级最高
+     * @param task 任务
+     * @param may_sync 如果调用该函数的线程就是本对象的轮询线程,那么may_sync为true时就是同步执行任务
+     * @return 是否成功,一定会返回true
+     */
+    Task::Ptr async_first(TaskIn task, bool may_sync = true) override;
+
+    /**
+     * 判断执行该接口的线程是否为本对象的轮询线程
+     * @return 是否为本对象的轮询线程
+     */
+    bool isCurrentThread();
+
+    /**
+     * 延时执行某个任务
+     * @param delay_ms 延时毫秒数
+     * @param task 任务,返回值为0时代表不再重复任务,否则为下次执行延时,如果任务中抛异常,那么默认不重复任务
+     * @return 可取消的任务标签
+     */
+    DelayTask::Ptr doDelayTask(uint64_t delay_ms, std::function<uint64_t()> task);
+
+    /**
+     * 获取当前线程关联的Poller实例
+     */
+    static EventPoller::Ptr getCurrentPoller();
+
+    /**
+     * 获取当前线程下所有socket共享的读缓存
+     */
+    BufferRaw::Ptr getSharedBuffer();
+
+    /**
+     * 获取poller线程id
+     */
+    const std::thread::id& getThreadId() const;
+
+    /**
+     * 获取线程名
+     */
+    const std::string& getThreadName() const;
+
+private:
+    /**
+     * 本对象只允许在EventPollerPool中构造
+     */
+    EventPoller(std::string name, ThreadPool::Priority priority = ThreadPool::PRIORITY_HIGHEST);
+
+    /**
+     * 执行事件轮询
+     * @param blocked 是否用执行该接口的线程执行轮询
+     * @param ref_self 是记录本对象到thread local变量
+     */
+    void runLoop(bool blocked, bool ref_self);
+
+    /**
+     * 内部管道事件,用于唤醒轮询线程用
+     */
+    void onPipeEvent();
+
+    /**
+     * 切换线程并执行任务
+     * @param task
+     * @param may_sync
+     * @param first
+     * @return 可取消的任务本体,如果已经同步执行,则返回nullptr
+     */
+    Task::Ptr async_l(TaskIn task, bool may_sync = true, bool first = false);
+
+    /**
+     * 阻塞当前线程,等待轮询线程退出;
+     * 在执行shutdown接口时本函数会退出
+     */
+    void wait();
+
+    /**
+     * 结束事件轮询
+     * 需要指出的是,一旦结束就不能再次恢复轮询线程
+     */
+    void shutdown();
+
+    /**
+     * 刷新延时任务
+     */
+    uint64_t flushDelayTask(uint64_t now);
+
+    /**
+     * 获取select或epoll休眠时间
+     */
+    uint64_t getMinDelay();
+
+    /**
+     * 添加管道监听事件
+     */
+    void addEventPipe();
+
+private:
+    class ExitException : public std::exception {};
+
+private:
+    //标记loop线程是否退出
+    bool _exit_flag;
+    //线程名
+    std::string _name;
+    //当前线程下,所有socket共享的读缓存
+    std::weak_ptr<BufferRaw> _shared_buffer;
+    //线程优先级
+    ThreadPool::Priority _priority;
+    //正在运行事件循环时该锁处于被锁定状态
+    std::mutex _mtx_running;
+    //执行事件循环的线程
+    std::thread *_loop_thread = nullptr;
+    //事件循环的线程id
+    std::thread::id _loop_thread_id;
+    //通知事件循环的线程已启动
+    semaphore _sem_run_started;
+
+    //内部事件管道
+    PipeWrap _pipe;
+    //从其他线程切换过来的任务
+    std::mutex _mtx_task;
+    List<Task::Ptr> _list_task;
+
+    //保持日志可用
+    Logger::Ptr _logger;
+
+#if defined(HAS_EPOLL)
+    //epoll相关
+    int _epoll_fd = -1;
+    unordered_map<int, std::shared_ptr<PollEventCB> > _event_map;
+#else
+    //select相关
+    struct Poll_Record {
+        using Ptr = std::shared_ptr<Poll_Record>;
+        int event;
+        int attach;
+        PollEventCB call_back;
+    };
+    unordered_map<int, Poll_Record::Ptr> _event_map;
+#endif //HAS_EPOLL
+
+    //定时器相关
+    std::multimap<uint64_t, DelayTask::Ptr> _delay_task_map;
+};
+
+class EventPollerPool : public std::enable_shared_from_this<EventPollerPool>, public TaskExecutorGetterImp {
+public:
+    using Ptr = std::shared_ptr<EventPollerPool>;
+    static const std::string kOnStarted;
+    ~EventPollerPool() = default;
+
+    /**
+     * 获取单例
+     * @return
+     */
+    static EventPollerPool &Instance();
+
+    /**
+     * 设置EventPoller个数,在EventPollerPool单例创建前有效
+     * 在不调用此方法的情况下,默认创建thread::hardware_concurrency()个EventPoller实例
+     * @param size  EventPoller个数,如果为0则为thread::hardware_concurrency()
+     */
+    static void setPoolSize(size_t size = 0);
+
+    /**
+     * 内部创建线程是否设置cpu亲和性,默认设置cpu亲和性
+     */
+    static void enableCpuAffinity(bool enable);
+
+    /**
+     * 获取第一个实例
+     * @return
+     */
+    EventPoller::Ptr getFirstPoller();
+
+    /**
+     * 根据负载情况获取轻负载的实例
+     * 如果优先返回当前线程,那么会返回当前线程
+     * 返回当前线程的目的是为了提高线程安全性
+     * @param prefer_current_thread 是否优先获取当前线程
+     */
+    EventPoller::Ptr getPoller(bool prefer_current_thread = true);
+
+    /**
+     * 设置 getPoller() 是否优先返回当前线程
+     * 在批量创建Socket对象时,如果优先返回当前线程,
+     * 那么将导致负载不够均衡,所以可以暂时关闭然后再开启
+     * @param flag 是否优先返回当前线程
+     */
+    void preferCurrentThread(bool flag = true);
+
+private:
+    EventPollerPool();
+
+private:
+    bool _prefer_current_thread = true;
+};
+
+}  // namespace toolkit
+#endif /* EventPoller_h */

+ 35 - 0
3rdparty/ZLToolKit/include/Poller/Pipe.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef Pipe_h
+#define Pipe_h
+
+#include <functional>
+#include "PipeWrap.h"
+#include "EventPoller.h"
+
+namespace toolkit {
+
+class Pipe {
+public:
+    using onRead = std::function<void(int size, const char *buf)>;
+
+    Pipe(const onRead &cb = nullptr, const EventPoller::Ptr &poller = nullptr);
+    ~Pipe();
+
+    void send(const char *send, int size = 0);
+
+private:
+    std::shared_ptr<PipeWrap> _pipe;
+    EventPoller::Ptr _poller;
+};
+
+}  // namespace toolkit
+#endif /* Pipe_h */

+ 35 - 0
3rdparty/ZLToolKit/include/Poller/PipeWrap.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef PipeWarp_h
+#define PipeWarp_h
+
+namespace toolkit {
+
+class PipeWrap {
+public:
+    PipeWrap();
+    ~PipeWrap();
+    int write(const void *buf, int n);
+    int read(void *buf, int n);
+    int readFD() const { return _pipe_fd[0]; }
+    int writeFD() const { return _pipe_fd[1]; }
+    void reOpen();
+
+private:
+    void clearFD();
+
+private:
+    int _pipe_fd[2] = { -1, -1 };
+};
+
+} /* namespace toolkit */
+#endif // !PipeWarp_h
+

+ 32 - 0
3rdparty/ZLToolKit/include/Poller/SelectWrap.h

@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef SRC_POLLER_SELECTWRAP_H_
+#define SRC_POLLER_SELECTWRAP_H_
+
+#include "Util/util.h"
+
+namespace toolkit {
+
+class FdSet {
+public:
+    FdSet();
+    ~FdSet();
+    void fdZero();
+    void fdSet(int fd);
+    void fdClr(int fd);
+    bool isSet(int fd);
+    void *_ptr;
+};
+
+int zl_select(int cnt, FdSet *read, FdSet *write, FdSet *err, struct timeval *tv);
+
+} /* namespace toolkit */
+#endif /* SRC_POLLER_SELECTWRAP_H_ */

+ 39 - 0
3rdparty/ZLToolKit/include/Poller/Timer.h

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef Timer_h
+#define Timer_h
+
+#include <functional>
+#include "EventPoller.h"
+
+namespace toolkit {
+
+class Timer {
+public:
+    using Ptr = std::shared_ptr<Timer>;
+
+    /**
+     * 构造定时器
+     * @param second 定时器重复秒数
+     * @param cb 定时器任务,返回true表示重复下次任务,否则不重复,如果任务中抛异常,则默认重复下次任务
+     * @param poller EventPoller对象,可以为nullptr
+     */
+    Timer(float second, const std::function<bool()> &cb, const EventPoller::Ptr &poller);
+    ~Timer();
+
+private:
+    std::weak_ptr<EventPoller::DelayTask> _tag;
+    //定时器保持EventPoller的强引用
+    EventPoller::Ptr _poller;
+};
+
+}  // namespace toolkit
+#endif /* Timer_h */

+ 253 - 0
3rdparty/ZLToolKit/include/Thread/TaskExecutor.h

@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLTOOLKIT_TASKEXECUTOR_H
+#define ZLTOOLKIT_TASKEXECUTOR_H
+
+#include <mutex>
+#include <memory>
+#include <functional>
+#include "Util/List.h"
+#include "Util/util.h"
+
+namespace toolkit {
+
+/**
+* cpu负载计算器
+*/
+class ThreadLoadCounter {
+public:
+    /**
+     * 构造函数
+     * @param max_size 统计样本数量
+     * @param max_usec 统计时间窗口,亦即最近{max_usec}的cpu负载率
+     */
+    ThreadLoadCounter(uint64_t max_size, uint64_t max_usec);
+    ~ThreadLoadCounter() = default;
+
+    /**
+     * 线程进入休眠
+     */
+    void startSleep();
+
+    /**
+     * 休眠唤醒,结束休眠
+     */
+    void sleepWakeUp();
+
+    /**
+     * 返回当前线程cpu使用率,范围为 0 ~ 100
+     * @return 当前线程cpu使用率
+     */
+    int load();
+
+private:
+    struct TimeRecord {
+        TimeRecord(uint64_t tm, bool slp) {
+            _time = tm;
+            _sleep = slp;
+        }
+
+        bool _sleep;
+        uint64_t _time;
+    };
+
+private:
+    bool _sleeping = true;
+    uint64_t _last_sleep_time;
+    uint64_t _last_wake_time;
+    uint64_t _max_size;
+    uint64_t _max_usec;
+    std::mutex _mtx;
+    List<TimeRecord> _time_list;
+};
+
+class TaskCancelable : public noncopyable {
+public:
+    TaskCancelable() = default;
+    virtual ~TaskCancelable() = default;
+    virtual void cancel() = 0;
+};
+
+template<class R, class... ArgTypes>
+class TaskCancelableImp;
+
+template<class R, class... ArgTypes>
+class TaskCancelableImp<R(ArgTypes...)> : public TaskCancelable {
+public:
+    using Ptr = std::shared_ptr<TaskCancelableImp>;
+    using func_type = std::function<R(ArgTypes...)>;
+
+    ~TaskCancelableImp() = default;
+
+    template<typename FUNC>
+    TaskCancelableImp(FUNC &&task) {
+        _strongTask = std::make_shared<func_type>(std::forward<FUNC>(task));
+        _weakTask = _strongTask;
+    }
+
+    void cancel() override {
+        _strongTask = nullptr;
+    }
+
+    operator bool() {
+        return _strongTask && *_strongTask;
+    }
+
+    void operator=(std::nullptr_t) {
+        _strongTask = nullptr;
+    }
+
+    R operator()(ArgTypes ...args) const {
+        auto strongTask = _weakTask.lock();
+        if (strongTask && *strongTask) {
+            return (*strongTask)(std::forward<ArgTypes>(args)...);
+        }
+        return defaultValue<R>();
+    }
+
+    template<typename T>
+    static typename std::enable_if<std::is_void<T>::value, void>::type
+    defaultValue() {}
+
+    template<typename T>
+    static typename std::enable_if<std::is_pointer<T>::value, T>::type
+    defaultValue() {
+        return nullptr;
+    }
+
+    template<typename T>
+    static typename std::enable_if<std::is_integral<T>::value, T>::type
+    defaultValue() {
+        return 0;
+    }
+
+protected:
+    std::weak_ptr<func_type> _weakTask;
+    std::shared_ptr<func_type> _strongTask;
+};
+
+using TaskIn = std::function<void()>;
+using Task = TaskCancelableImp<void()>;
+
+class TaskExecutorInterface {
+public:
+    TaskExecutorInterface() = default;
+    virtual ~TaskExecutorInterface() = default;
+
+    /**
+     * 异步执行任务
+     * @param task 任务
+     * @param may_sync 是否允许同步执行该任务
+     * @return 任务是否添加成功
+     */
+    virtual Task::Ptr async(TaskIn task, bool may_sync = true) = 0;
+
+    /**
+     * 最高优先级方式异步执行任务
+     * @param task 任务
+     * @param may_sync 是否允许同步执行该任务
+     * @return 任务是否添加成功
+     */
+    virtual Task::Ptr async_first(TaskIn task, bool may_sync = true);
+
+    /**
+     * 同步执行任务
+     * @param task
+     * @return
+     */
+    void sync(const TaskIn &task);
+
+    /**
+     * 最高优先级方式同步执行任务
+     * @param task
+     * @return
+     */
+    void sync_first(const TaskIn &task);
+};
+
+/**
+* 任务执行器
+*/
+class TaskExecutor : public ThreadLoadCounter, public TaskExecutorInterface {
+public:
+    using Ptr = std::shared_ptr<TaskExecutor>;
+
+    /**
+     * 构造函数
+     * @param max_size cpu负载统计样本数
+     * @param max_usec cpu负载统计时间窗口大小
+     */
+    TaskExecutor(uint64_t max_size = 32, uint64_t max_usec = 2 * 1000 * 1000);
+    ~TaskExecutor() = default;
+};
+
+class TaskExecutorGetter {
+public:
+    using Ptr = std::shared_ptr<TaskExecutorGetter>;
+
+    virtual ~TaskExecutorGetter() = default;
+
+    /**
+     * 获取任务执行器
+     * @return 任务执行器
+     */
+    virtual TaskExecutor::Ptr getExecutor() = 0;
+
+    /**
+     * 获取执行器个数
+     */
+    virtual size_t getExecutorSize() const = 0;
+};
+
+class TaskExecutorGetterImp : public TaskExecutorGetter {
+public:
+    TaskExecutorGetterImp() = default;
+    ~TaskExecutorGetterImp() = default;
+
+    /**
+     * 根据线程负载情况,获取最空闲的任务执行器
+     * @return 任务执行器
+     */
+    TaskExecutor::Ptr getExecutor() override;
+
+    /**
+     * 获取所有线程的负载率
+     * @return 所有线程的负载率
+     */
+    std::vector<int> getExecutorLoad();
+
+    /**
+     * 获取所有线程任务执行延时,单位毫秒
+     * 通过此函数也可以大概知道线程负载情况
+     * @return
+     */
+    void getExecutorDelay(const std::function<void(const std::vector<int> &)> &callback);
+
+    /**
+     * 遍历所有线程
+     */
+    void for_each(const std::function<void(const TaskExecutor::Ptr &)> &cb);
+
+    /**
+     * 获取线程数
+     */
+    size_t getExecutorSize() const override;
+
+protected:
+    size_t addPoller(const std::string &name, size_t size, int priority, bool register_thread, bool enable_cpu_affinity = true);
+
+protected:
+    size_t _thread_pos = 0;
+    std::vector<TaskExecutor::Ptr> _threads;
+};
+
+}//toolkit
+#endif //ZLTOOLKIT_TASKEXECUTOR_H

+ 72 - 0
3rdparty/ZLToolKit/include/Thread/TaskQueue.h

@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef TASKQUEUE_H_
+#define TASKQUEUE_H_
+
+#include <mutex>
+#include "Util/List.h"
+#include "semaphore.h"
+
+namespace toolkit {
+
+//实现了一个基于函数对象的任务列队,该列队是线程安全的,任务列队任务数由信号量控制
+template<typename T>
+class TaskQueue {
+public:
+    //打入任务至列队
+    template<typename C>
+    void push_task(C &&task_func) {
+        {
+            std::lock_guard<decltype(_mutex)> lock(_mutex);
+            _queue.emplace_back(std::forward<C>(task_func));
+        }
+        _sem.post();
+    }
+
+    template<typename C>
+    void push_task_first(C &&task_func) {
+        {
+            std::lock_guard<decltype(_mutex)> lock(_mutex);
+            _queue.emplace_front(std::forward<C>(task_func));
+        }
+        _sem.post();
+    }
+
+    //清空任务列队
+    void push_exit(size_t n) {
+        _sem.post(n);
+    }
+
+    //从列队获取一个任务,由执行线程执行
+    bool get_task(T &tsk) {
+        _sem.wait();
+        std::lock_guard<decltype(_mutex)> lock(_mutex);
+        if (_queue.empty()) {
+            return false;
+        }
+        tsk = std::move(_queue.front());
+        _queue.pop_front();
+        return true;
+    }
+
+    size_t size() const {
+        std::lock_guard<decltype(_mutex)> lock(_mutex);
+        return _queue.size();
+    }
+
+private:
+    List <T> _queue;
+    mutable std::mutex _mutex;
+    semaphore _sem;
+};
+
+} /* namespace toolkit */
+#endif /* TASKQUEUE_H_ */

+ 155 - 0
3rdparty/ZLToolKit/include/Thread/ThreadPool.h

@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef THREADPOOL_H_
+#define THREADPOOL_H_
+
+#include "threadgroup.h"
+#include "TaskQueue.h"
+#include "TaskExecutor.h"
+#include "Util/util.h"
+#include "Util/logger.h"
+
+namespace toolkit {
+
+class ThreadPool : public TaskExecutor {
+public:
+    enum Priority {
+        PRIORITY_LOWEST = 0,
+        PRIORITY_LOW,
+        PRIORITY_NORMAL,
+        PRIORITY_HIGH,
+        PRIORITY_HIGHEST
+    };
+
+    ThreadPool(int num = 1, Priority priority = PRIORITY_HIGHEST, bool auto_run = true, bool set_affinity = true,
+               const std::string &pool_name = "thread pool") {
+        _thread_num = num;
+        _on_setup = [pool_name, priority, set_affinity](int index) {
+            std::string name = pool_name + ' ' + std::to_string(index);
+            setPriority(priority);
+            setThreadName(name.data());
+            if (set_affinity) {
+                setThreadAffinity(index % std::thread::hardware_concurrency());
+            }
+        };
+        _logger = Logger::Instance().shared_from_this();
+        if (auto_run) {
+            start();
+        }
+    }
+
+    ~ThreadPool() {
+        shutdown();
+        wait();
+    }
+
+    //把任务打入线程池并异步执行
+    Task::Ptr async(TaskIn task, bool may_sync = true) override {
+        if (may_sync && _thread_group.is_this_thread_in()) {
+            task();
+            return nullptr;
+        }
+        auto ret = std::make_shared<Task>(std::move(task));
+        _queue.push_task(ret);
+        return ret;
+    }
+
+    Task::Ptr async_first(TaskIn task, bool may_sync = true) override {
+        if (may_sync && _thread_group.is_this_thread_in()) {
+            task();
+            return nullptr;
+        }
+
+        auto ret = std::make_shared<Task>(std::move(task));
+        _queue.push_task_first(ret);
+        return ret;
+    }
+
+    size_t size() {
+        return _queue.size();
+    }
+
+    static bool setPriority(Priority priority = PRIORITY_NORMAL, std::thread::native_handle_type threadId = 0) {
+        // set priority
+#if defined(_WIN32)
+        static int Priorities[] = { THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST };
+        if (priority != PRIORITY_NORMAL && SetThreadPriority(GetCurrentThread(), Priorities[priority]) == 0) {
+            return false;
+        }
+        return true;
+#else
+        static int Min = sched_get_priority_min(SCHED_OTHER);
+        if (Min == -1) {
+            return false;
+        }
+        static int Max = sched_get_priority_max(SCHED_OTHER);
+        if (Max == -1) {
+            return false;
+        }
+        static int Priorities[] = {Min, Min + (Max - Min) / 4, Min + (Max - Min) / 2, Min + (Max - Min) * 3 / 4, Max};
+
+        if (threadId == 0) {
+            threadId = pthread_self();
+        }
+        struct sched_param params;
+        params.sched_priority = Priorities[priority];
+        return pthread_setschedparam(threadId, SCHED_OTHER, &params) == 0;
+#endif
+    }
+
+    void start() {
+        if (_thread_num <= 0) {
+            return;
+        }
+        size_t total = _thread_num - _thread_group.size();
+        for (size_t i = 0; i < total; ++i) {
+            _thread_group.create_thread([this, i]() {run(i);});
+        }
+    }
+
+private:
+    void run(size_t index) {
+        _on_setup(index);
+        Task::Ptr task;
+        while (true) {
+            startSleep();
+            if (!_queue.get_task(task)) {
+                //空任务,退出线程
+                break;
+            }
+            sleepWakeUp();
+            try {
+                (*task)();
+                task = nullptr;
+            } catch (std::exception &ex) {
+                ErrorL << "ThreadPool catch a exception: " << ex.what();
+            }
+        }
+    }
+
+    void wait() {
+        _thread_group.join_all();
+    }
+
+    void shutdown() {
+        _queue.push_exit(_thread_num);
+    }
+
+private:
+    size_t _thread_num;
+    Logger::Ptr _logger;
+    thread_group _thread_group;
+    TaskQueue<Task::Ptr> _queue;
+    std::function<void(int)> _on_setup;
+};
+
+} /* namespace toolkit */
+#endif /* THREADPOOL_H_ */

+ 61 - 0
3rdparty/ZLToolKit/include/Thread/WorkThreadPool.h

@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef UTIL_WORKTHREADPOOL_H_
+#define UTIL_WORKTHREADPOOL_H_
+
+#include <memory>
+#include "Poller/EventPoller.h"
+
+namespace toolkit {
+
+class WorkThreadPool : public std::enable_shared_from_this<WorkThreadPool>, public TaskExecutorGetterImp {
+public:
+    using Ptr = std::shared_ptr<WorkThreadPool>;
+
+    ~WorkThreadPool() override = default;
+
+    /**
+     * 获取单例
+     */
+    static WorkThreadPool &Instance();
+
+    /**
+     * 设置EventPoller个数,在WorkThreadPool单例创建前有效
+     * 在不调用此方法的情况下,默认创建thread::hardware_concurrency()个EventPoller实例
+     * @param size EventPoller个数,如果为0则为thread::hardware_concurrency()
+     */
+    static void setPoolSize(size_t size = 0);
+
+    /**
+     * 内部创建线程是否设置cpu亲和性,默认设置cpu亲和性
+     */
+    static void enableCpuAffinity(bool enable);
+
+    /**
+     * 获取第一个实例
+     * @return
+     */
+    EventPoller::Ptr getFirstPoller();
+
+    /**
+     * 根据负载情况获取轻负载的实例
+     * 如果优先返回当前线程,那么会返回当前线程
+     * 返回当前线程的目的是为了提高线程安全性
+     * @return
+     */
+    EventPoller::Ptr getPoller();
+
+protected:
+    WorkThreadPool();
+};
+
+} /* namespace toolkit */
+#endif /* UTIL_WORKTHREADPOOL_H_ */

+ 83 - 0
3rdparty/ZLToolKit/include/Thread/semaphore.h

@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef SEMAPHORE_H_
+#define SEMAPHORE_H_
+
+/*
+ * 目前发现信号量在32位的系统上有问题,
+ * 休眠的线程无法被正常唤醒,先禁用之
+#if defined(__linux__)
+#include <semaphore.h>
+#define HAVE_SEM
+#endif //HAVE_SEM
+*/
+
+#include <mutex>
+#include <condition_variable>
+
+namespace toolkit {
+
+class semaphore {
+public:
+    explicit semaphore(size_t initial = 0) {
+#if defined(HAVE_SEM)
+        sem_init(&_sem, 0, initial);
+#else
+        _count = 0;
+#endif
+    }
+
+    ~semaphore() {
+#if defined(HAVE_SEM)
+        sem_destroy(&_sem);
+#endif
+    }
+
+    void post(size_t n = 1) {
+#if defined(HAVE_SEM)
+        while (n--) {
+            sem_post(&_sem);
+        }
+#else
+        std::unique_lock<std::recursive_mutex> lock(_mutex);
+        _count += n;
+        if (n == 1) {
+            _condition.notify_one();
+        } else {
+            _condition.notify_all();
+        }
+#endif
+    }
+
+    void wait() {
+#if defined(HAVE_SEM)
+        sem_wait(&_sem);
+#else
+        std::unique_lock<std::recursive_mutex> lock(_mutex);
+        while (_count == 0) {
+            _condition.wait(lock);
+        }
+        --_count;
+#endif
+    }
+
+private:
+#if defined(HAVE_SEM)
+    sem_t _sem;
+#else
+    size_t _count;
+    std::recursive_mutex _mutex;
+    std::condition_variable_any _condition;
+#endif
+};
+
+} /* namespace toolkit */
+#endif /* SEMAPHORE_H_ */

+ 85 - 0
3rdparty/ZLToolKit/include/Thread/threadgroup.h

@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef THREADGROUP_H_
+#define THREADGROUP_H_
+
+#include <stdexcept>
+#include <thread>
+#include <unordered_map>
+
+namespace toolkit {
+
+class thread_group {
+private:
+    thread_group(thread_group const &);
+    thread_group &operator=(thread_group const &);
+
+public:
+    thread_group() {}
+
+    ~thread_group() {
+        _threads.clear();
+    }
+
+    bool is_this_thread_in() {
+        auto thread_id = std::this_thread::get_id();
+        if (_thread_id == thread_id) {
+            return true;
+        }
+        return _threads.find(thread_id) != _threads.end();
+    }
+
+    bool is_thread_in(std::thread *thrd) {
+        if (!thrd) {
+            return false;
+        }
+        auto it = _threads.find(thrd->get_id());
+        return it != _threads.end();
+    }
+
+    template<typename F>
+    std::thread *create_thread(F &&threadfunc) {
+        auto thread_new = std::make_shared<std::thread>(threadfunc);
+        _thread_id = thread_new->get_id();
+        _threads[_thread_id] = thread_new;
+        return thread_new.get();
+    }
+
+    void remove_thread(std::thread *thrd) {
+        auto it = _threads.find(thrd->get_id());
+        if (it != _threads.end()) {
+            _threads.erase(it);
+        }
+    }
+
+    void join_all() {
+        if (is_this_thread_in()) {
+            throw std::runtime_error("Trying joining itself in thread_group");
+        }
+        for (auto &it : _threads) {
+            if (it.second->joinable()) {
+                it.second->join(); //等待线程主动退出
+            }
+        }
+        _threads.clear();
+    }
+
+    size_t size() {
+        return _threads.size();
+    }
+
+private:
+    std::thread::id _thread_id;
+    std::unordered_map<std::thread::id, std::shared_ptr<std::thread>> _threads;
+};
+
+} /* namespace toolkit */
+#endif /* THREADGROUP_H_ */

+ 384 - 0
3rdparty/ZLToolKit/include/Util/CMD.h

@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef SRC_UTIL_CMD_H_
+#define SRC_UTIL_CMD_H_
+
+#include <map>
+#include <mutex>
+#include <string>
+#include <memory>
+#include <vector>
+#include <iostream>
+#include <functional>
+#include "mini.h"
+
+namespace toolkit{
+
+class Option {
+public:
+    using OptionHandler = std::function<bool(const std::shared_ptr<std::ostream> &stream, const std::string &arg)>;
+
+    enum ArgType {
+        ArgNone = 0,//no_argument,
+        ArgRequired = 1,//required_argument,
+        ArgOptional = 2,//optional_argument
+    };
+
+    Option() = default;
+
+    Option(char short_opt, const char *long_opt, enum ArgType type, const char *default_value, bool must_exist,
+           const char *des, const OptionHandler &cb) {
+        _short_opt = short_opt;
+        _long_opt = long_opt;
+        _type = type;
+        if (type != ArgNone) {
+            if (default_value) {
+                _default_value = std::make_shared<std::string>(default_value);
+            }
+            if (!_default_value && must_exist) {
+                _must_exist = true;
+            }
+        }
+        _des = des;
+        _cb = cb;
+    }
+
+    bool operator()(const std::shared_ptr<std::ostream> &stream, const std::string &arg) {
+        return _cb ? _cb(stream, arg) : true;
+    }
+
+private:
+    friend class OptionParser;
+    bool _must_exist = false;
+    char _short_opt;
+    enum ArgType _type;
+    std::string _des;
+    std::string _long_opt;
+    OptionHandler _cb;
+    std::shared_ptr<std::string> _default_value;
+};
+
+class OptionParser {
+public:
+    using OptionCompleted = std::function<void(const std::shared_ptr<std::ostream> &, mINI &)>;
+
+    OptionParser(const OptionCompleted &cb = nullptr, bool enable_empty_args = true) {
+        _on_completed = cb;
+        _enable_empty_args = enable_empty_args;
+        _helper = Option('h', "help", Option::ArgNone, nullptr, false, "打印此信息",
+                         [this](const std::shared_ptr<std::ostream> &stream,const std::string &arg)->bool {
+             static const char *argsType[] = {"无参", "有参", "选参"};
+             static const char *mustExist[] = {"选填", "必填"};
+             static std::string defaultPrefix = "默认:";
+             static std::string defaultNull = "null";
+
+             std::stringstream printer;
+             size_t maxLen_longOpt = 0;
+             auto maxLen_default = defaultNull.size();
+
+             for (auto &pr : _map_options) {
+                 auto &opt = pr.second;
+                 if (opt._long_opt.size() > maxLen_longOpt) {
+                     maxLen_longOpt = opt._long_opt.size();
+                 }
+                 if (opt._default_value) {
+                     if (opt._default_value->size() > maxLen_default) {
+                         maxLen_default = opt._default_value->size();
+                     }
+                 }
+             }
+             for (auto &pr : _map_options) {
+                 auto &opt = pr.second;
+                 //打印短参和长参名
+                 if (opt._short_opt) {
+                     printer << "  -" << opt._short_opt << "  --" << opt._long_opt;
+                 } else {
+                     printer << "   " << " " << "  --" << opt._long_opt;
+                 }
+                 for (size_t i = 0; i < maxLen_longOpt - opt._long_opt.size(); ++i) {
+                     printer << " ";
+                 }
+                 //打印是否有参
+                 printer << "  " << argsType[opt._type];
+                 //打印默认参数
+                 std::string defaultValue = defaultNull;
+                 if (opt._default_value) {
+                     defaultValue = *opt._default_value;
+                 }
+                 printer << "  " << defaultPrefix << defaultValue;
+                 for (size_t i = 0; i < maxLen_default - defaultValue.size(); ++i) {
+                     printer << " ";
+                 }
+                 //打印是否必填参数
+                 printer << "  " << mustExist[opt._must_exist];
+                 //打印描述
+                 printer << "  " << opt._des << std::endl;
+             }
+             throw std::invalid_argument(printer.str());
+         });
+        (*this) << _helper;
+    }
+
+    OptionParser &operator<<(Option &&option) {
+        int index = 0xFF + (int) _map_options.size();
+        if (option._short_opt) {
+            _map_char_index.emplace(option._short_opt, index);
+        }
+        _map_options.emplace(index, std::forward<Option>(option));
+        return *this;
+    }
+
+    OptionParser &operator<<(const Option &option) {
+        int index = 0xFF + (int) _map_options.size();
+        if (option._short_opt) {
+            _map_char_index.emplace(option._short_opt, index);
+        }
+        _map_options.emplace(index, option);
+        return *this;
+    }
+
+    void delOption(const char *key) {
+        for (auto &pr : _map_options) {
+            if (pr.second._long_opt == key) {
+                if (pr.second._short_opt) {
+                    _map_char_index.erase(pr.second._short_opt);
+                }
+                _map_options.erase(pr.first);
+                break;
+            }
+        }
+    }
+
+    void operator ()(mINI &all_args, int argc, char *argv[], const std::shared_ptr<std::ostream> &stream);
+
+private:
+    bool _enable_empty_args;
+    Option _helper;
+    std::map<char, int> _map_char_index;
+    std::map<int, Option> _map_options;
+    OptionCompleted _on_completed;
+};
+
+class CMD : public mINI {
+public:
+    virtual ~CMD() = default;
+
+    virtual const char *description() const {
+        return "description";
+    }
+
+    void operator()(int argc, char *argv[], const std::shared_ptr<std::ostream> &stream = nullptr) {
+        this->clear();
+        std::shared_ptr<std::ostream> coutPtr(&std::cout, [](std::ostream *) {});
+        (*_parser)(*this, argc, argv, stream ? stream : coutPtr);
+    }
+
+    bool hasKey(const char *key) {
+        return this->find(key) != this->end();
+    }
+
+    std::vector<variant> splitedVal(const char *key, const char *delim = ":") {
+        std::vector<variant> ret;
+        auto &val = (*this)[key];
+        split(val, delim, ret);
+        return ret;
+    }
+
+    void delOption(const char *key) {
+        if (_parser) {
+            _parser->delOption(key);
+        }
+    }
+
+protected:
+    std::shared_ptr<OptionParser> _parser;
+
+private:
+    void split(const std::string &s, const char *delim, std::vector<variant> &ret) {
+        size_t last = 0;
+        auto index = s.find(delim, last);
+        while (index != std::string::npos) {
+            if (index - last > 0) {
+                ret.push_back(s.substr(last, index - last));
+            }
+            last = index + strlen(delim);
+            index = s.find(delim, last);
+        }
+        if (s.size() - last > 0) {
+            ret.push_back(s.substr(last));
+        }
+    }
+};
+
+class CMDRegister {
+public:
+    static CMDRegister &Instance();
+
+    void clear() {
+        std::lock_guard<std::recursive_mutex> lck(_mtx);
+        _cmd_map.clear();
+    }
+
+    void registCMD(const char *name, const std::shared_ptr<CMD> &cmd) {
+        std::lock_guard<std::recursive_mutex> lck(_mtx);
+        _cmd_map.emplace(name, cmd);
+    }
+
+    void unregistCMD(const char *name) {
+        std::lock_guard<std::recursive_mutex> lck(_mtx);
+        _cmd_map.erase(name);
+    }
+
+    std::shared_ptr<CMD> operator[](const char *name) {
+        std::lock_guard<std::recursive_mutex> lck(_mtx);
+        auto it = _cmd_map.find(name);
+        if (it == _cmd_map.end()) {
+            throw std::invalid_argument(std::string("CMD not existed: ") + name);
+        }
+        return it->second;
+    }
+
+    void operator()(const char *name, int argc, char *argv[], const std::shared_ptr<std::ostream> &stream = nullptr) {
+        auto cmd = (*this)[name];
+        if (!cmd) {
+            throw std::invalid_argument(std::string("CMD not existed: ") + name);
+        }
+        (*cmd)(argc, argv, stream);
+    }
+
+    void printHelp(const std::shared_ptr<std::ostream> &streamTmp = nullptr) {
+        auto stream = streamTmp;
+        if (!stream) {
+            stream.reset(&std::cout, [](std::ostream *) {});
+        }
+
+        std::lock_guard<std::recursive_mutex> lck(_mtx);
+        size_t maxLen = 0;
+        for (auto &pr : _cmd_map) {
+            if (pr.first.size() > maxLen) {
+                maxLen = pr.first.size();
+            }
+        }
+        for (auto &pr : _cmd_map) {
+            (*stream) << "  " << pr.first;
+            for (size_t i = 0; i < maxLen - pr.first.size(); ++i) {
+                (*stream) << " ";
+            }
+            (*stream) << "  " << pr.second->description() << std::endl;
+        }
+    }
+
+    void operator()(const std::string &line, const std::shared_ptr<std::ostream> &stream = nullptr) {
+        if (line.empty()) {
+            return;
+        }
+        std::vector<char *> argv;
+        size_t argc = getArgs((char *) line.data(), argv);
+        if (argc == 0) {
+            return;
+        }
+        std::string cmd = argv[0];
+        std::lock_guard<std::recursive_mutex> lck(_mtx);
+        auto it = _cmd_map.find(cmd);
+        if (it == _cmd_map.end()) {
+            std::stringstream ss;
+            ss << "  未识别的命令\"" << cmd << "\",输入 \"help\" 获取帮助.";
+            throw std::invalid_argument(ss.str());
+        }
+        (*it->second)((int) argc, &argv[0], stream);
+    }
+
+private:
+    size_t getArgs(char *buf, std::vector<char *> &argv) {
+        size_t argc = 0;
+        bool start = false;
+        auto len = strlen(buf);
+        for (size_t i = 0; i < len; ++i) {
+            if (buf[i] != ' ' && buf[i] != '\t' && buf[i] != '\r' && buf[i] != '\n') {
+                if (!start) {
+                    start = true;
+                    if (argv.size() < argc + 1) {
+                        argv.resize(argc + 1);
+                    }
+                    argv[argc++] = buf + i;
+                }
+            } else {
+                buf[i] = '\0';
+                start = false;
+            }
+        }
+        return argc;
+    }
+
+private:
+    std::recursive_mutex _mtx;
+    std::map<std::string, std::shared_ptr<CMD> > _cmd_map;
+};
+
+//帮助命令(help),该命令默认已注册
+class CMD_help : public CMD {
+public:
+    CMD_help() {
+        _parser = std::make_shared<OptionParser>([](const std::shared_ptr<std::ostream> &stream, mINI &) {
+            CMDRegister::Instance().printHelp(stream);
+        });
+    }
+
+    const char *description() const override {
+        return "打印帮助信息";
+    }
+};
+
+class ExitException : public std::exception {};
+
+//退出程序命令(exit),该命令默认已注册
+class CMD_exit : public CMD {
+public:
+    CMD_exit() {
+        _parser = std::make_shared<OptionParser>([](const std::shared_ptr<std::ostream> &, mINI &) {
+            throw ExitException();
+        });
+    }
+
+    const char *description() const override {
+        return "退出shell";
+    }
+};
+
+//退出程序命令(quit),该命令默认已注册
+#define CMD_quit CMD_exit
+
+//清空屏幕信息命令(clear),该命令默认已注册
+class CMD_clear : public CMD {
+public:
+    CMD_clear() {
+        _parser = std::make_shared<OptionParser>([this](const std::shared_ptr<std::ostream> &stream, mINI &args) {
+            clear(stream);
+        });
+    }
+
+    const char *description() const {
+        return "清空屏幕输出";
+    }
+
+private:
+    void clear(const std::shared_ptr<std::ostream> &stream) {
+        (*stream) << "\x1b[2J\x1b[H";
+        stream->flush();
+    }
+};
+
+#define GET_CMD(name) (*(CMDRegister::Instance()[name]))
+#define CMD_DO(name,...) (*(CMDRegister::Instance()[name]))(__VA_ARGS__)
+#define REGIST_CMD(name) CMDRegister::Instance().registCMD(#name,std::make_shared<CMD_##name>());
+
+}//namespace toolkit
+#endif /* SRC_UTIL_CMD_H_ */

+ 145 - 0
3rdparty/ZLToolKit/include/Util/File.h

@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef SRC_UTIL_FILE_H_
+#define SRC_UTIL_FILE_H_
+
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include "util.h"
+#include <functional>
+
+#if defined(__linux__)
+#include <limits.h>
+#endif
+
+#if defined(_WIN32)
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif // !PATH_MAX
+
+struct dirent{
+    long d_ino;              /* inode number*/
+    off_t d_off;             /* offset to this dirent*/
+    unsigned short d_reclen; /* length of this d_name*/
+    unsigned char d_type;    /* the type of d_name*/
+    char d_name[1];          /* file name (null-terminated)*/
+};
+typedef struct _dirdesc {
+    int     dd_fd;      /** file descriptor associated with directory */
+    long    dd_loc;     /** offset in current buffer */
+    long    dd_size;    /** amount of data returned by getdirentries */
+    char    *dd_buf;    /** data buffer */
+    int     dd_len;     /** size of data buffer */
+    long    dd_seek;    /** magic cookie returned by getdirentries */
+    HANDLE handle;
+    struct dirent *index;
+} DIR;
+# define __dirfd(dp)    ((dp)->dd_fd)
+
+int mkdir(const char *path, int mode);
+DIR *opendir(const char *);
+int closedir(DIR *);
+struct dirent *readdir(DIR *);
+
+#endif // defined(_WIN32)
+
+#if defined(_WIN32) || defined(_WIN64)
+#define fseek64 _fseeki64
+#define ftell64 _ftelli64
+#else
+#define fseek64 fseek
+#define ftell64 ftell
+#endif
+
+namespace toolkit {
+
+class File {
+public:
+    //创建路径
+    static bool create_path(const char *file, unsigned int mod);
+
+    //新建文件,目录文件夹自动生成
+    static FILE *create_file(const char *file, const char *mode);
+
+    //判断是否为目录
+    static bool is_dir(const char *path);
+
+    //判断是否是特殊目录(. or ..)
+    static bool is_special_dir(const char *path);
+
+    //删除目录或文件
+    static int delete_file(const char *path);
+
+    //判断文件是否存在
+    static bool fileExist(const char *path);
+
+    /**
+     * 加载文件内容至string
+     * @param path 加载的文件路径
+     * @return 文件内容
+     */
+    static std::string loadFile(const char *path);
+
+    /**
+     * 保存内容至文件
+     * @param data 文件内容
+     * @param path 保存的文件路径
+     * @return 是否保存成功
+     */
+    static bool saveFile(const std::string &data, const char *path);
+
+    /**
+     * 获取父文件夹
+     * @param path 路径
+     * @return 文件夹
+     */
+    static std::string parentDir(const std::string &path);
+
+    /**
+     * 替换"../",获取绝对路径
+     * @param path 相对路径,里面可能包含 "../"
+     * @param current_path 当前目录
+     * @param can_access_parent 能否访问父目录之外的目录
+     * @return 替换"../"之后的路径
+     */
+    static std::string absolutePath(const std::string &path, const std::string &current_path, bool can_access_parent = false);
+
+    /**
+     * 遍历文件夹下的所有文件
+     * @param path 文件夹路径
+     * @param cb 回调对象 ,path为绝对路径,isDir为该路径是否为文件夹,返回true代表继续扫描,否则中断
+     * @param enter_subdirectory 是否进入子目录扫描
+     */
+    static void scanDir(const std::string &path, const std::function<bool(const std::string &path, bool isDir)> &cb, bool enter_subdirectory = false);
+
+    /**
+     * 获取文件大小
+     * @param fp 文件句柄
+     * @param remain_size true:获取文件剩余未读数据大小,false:获取文件总大小
+     */
+    static uint64_t fileSize(FILE *fp, bool remain_size = false);
+
+    /**
+     * 获取文件大小
+     * @param path 文件路径
+     * @return 文件大小
+     * @warning 调用者应确保文件存在
+     */
+    static uint64_t fileSize(const char *path);
+
+private:
+    File();
+    ~File();
+};
+
+} /* namespace toolkit */
+#endif /* SRC_UTIL_FILE_H_ */

+ 218 - 0
3rdparty/ZLToolKit/include/Util/List.h

@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLTOOLKIT_LIST_H
+#define ZLTOOLKIT_LIST_H
+
+#include <list>
+#include <type_traits>
+
+namespace toolkit {
+
+#if 0
+template<typename T>
+class List;
+
+template<typename T>
+class ListNode
+{
+public:
+    friend class List<T>;
+    ~ListNode(){}
+
+    template <class... Args>
+    ListNode(Args&&... args):_data(std::forward<Args>(args)...){}
+
+private:
+    T _data;
+    ListNode *next = nullptr;
+};
+
+
+template<typename T>
+class List {
+public:
+    using NodeType = ListNode<T>;
+    List(){}
+    List(List &&that){
+        swap(that);
+    }
+    ~List(){
+        clear();
+    }
+    void clear(){
+        auto ptr = _front;
+        auto last = ptr;
+        while(ptr){
+            last = ptr;
+            ptr = ptr->next;
+            delete last;
+        }
+        _size = 0;
+        _front = nullptr;
+        _back = nullptr;
+    }
+
+    template<typename FUN>
+    void for_each(FUN &&fun) const {
+        auto ptr = _front;
+        while (ptr) {
+            fun(ptr->_data);
+            ptr = ptr->next;
+        }
+    }
+
+    size_t size() const{
+        return _size;
+    }
+
+    bool empty() const{
+        return _size == 0;
+    }
+    template <class... Args>
+    void emplace_front(Args&&... args){
+        NodeType *node = new NodeType(std::forward<Args>(args)...);
+        if(!_front){
+            _front = node;
+            _back = node;
+            _size = 1;
+        }else{
+            node->next = _front;
+            _front = node;
+            ++_size;
+        }
+    }
+
+    template <class...Args>
+    void emplace_back(Args&&... args){
+        NodeType *node = new NodeType(std::forward<Args>(args)...);
+        if(!_back){
+            _back = node;
+            _front = node;
+            _size = 1;
+        }else{
+            _back->next = node;
+            _back = node;
+            ++_size;
+        }
+    }
+
+    T &front() const{
+        return _front->_data;
+    }
+
+    T &back() const{
+        return _back->_data;
+    }
+
+    T &operator[](size_t pos){
+        NodeType *front = _front ;
+        while(pos--){
+            front = front->next;
+        }
+        return front->_data;
+    }
+
+    void pop_front(){
+        if(!_front){
+            return;
+        }
+        auto ptr = _front;
+        _front = _front->next;
+        delete ptr;
+        if(!_front){
+            _back = nullptr;
+        }
+        --_size;
+    }
+
+    void swap(List &other){
+        NodeType *tmp_node;
+
+        tmp_node = _front;
+        _front = other._front;
+        other._front = tmp_node;
+
+        tmp_node = _back;
+        _back = other._back;
+        other._back = tmp_node;
+
+        size_t tmp_size = _size;
+        _size = other._size;
+        other._size = tmp_size;
+    }
+
+    void append(List<T> &other){
+        if(other.empty()){
+            return;
+        }
+        if(_back){
+            _back->next = other._front;
+            _back = other._back;
+        }else{
+            _front = other._front;
+            _back = other._back;
+        }
+        _size += other._size;
+
+        other._front = other._back = nullptr;
+        other._size = 0;
+    }
+
+    List &operator=(const List &that) {
+        that.for_each([&](const T &t) {
+            emplace_back(t);
+        });
+        return *this;
+    }
+
+private:
+    NodeType *_front = nullptr;
+    NodeType *_back = nullptr;
+    size_t _size = 0;
+};
+
+#else
+
+template<typename T>
+class List : public std::list<T> {
+public:
+    template<typename ... ARGS>
+    List(ARGS &&...args) : std::list<T>(std::forward<ARGS>(args)...) {};
+
+    ~List() = default;
+
+    void append(List<T> &other) {
+        if (other.empty()) {
+            return;
+        }
+        this->insert(this->end(), other.begin(), other.end());
+        other.clear();
+    }
+
+    template<typename FUNC>
+    void for_each(FUNC &&func) {
+        for (auto &t : *this) {
+            func(t);
+        }
+    }
+
+    template<typename FUNC>
+    void for_each(FUNC &&func) const {
+        for (auto &t : *this) {
+            func(t);
+        }
+    }
+};
+
+#endif
+
+} /* namespace toolkit */
+#endif //ZLTOOLKIT_LIST_H

+ 97 - 0
3rdparty/ZLToolKit/include/Util/MD5.h

@@ -0,0 +1,97 @@
+//MD5.cpp
+/* MD5
+converted to C++ class by Frank Thilo (thilo@unix-ag.org)
+for bzflag (http://www.bzflag.org)
+
+based on:
+
+md5.h and md5.c
+reference implemantion of RFC 1321
+
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+*/
+
+#ifndef SRC_UTIL_MD5_H_
+#define SRC_UTIL_MD5_H_
+
+#include <string>
+#include <iostream>
+#include <cstdint>
+
+namespace toolkit {
+
+// a small class for calculating MD5 hashes of strings or byte arrays
+// it is not meant to be fast or secure
+//
+// usage: 1) feed it blocks of uchars with update()
+//      2) finalize()
+//      3) get hexdigest() string
+//      or
+//      MD5(std::string).hexdigest()
+//
+// assumes that char is 8 bit and int is 32 bit
+class MD5
+{
+public:
+    typedef unsigned int size_type; // must be 32bit
+
+    MD5();
+    MD5(const std::string& text);
+    void update(const unsigned char *buf, size_type length);
+    void update(const char *buf, size_type length);
+    MD5& finalize();
+    std::string hexdigest() const;
+    std::string rawdigest() const;
+    friend std::ostream& operator<<(std::ostream&, MD5 md5);
+private:
+    void init();
+    typedef uint8_t uint1; //  8bit
+    typedef uint32_t uint4;  // 32bit
+    enum {blocksize = 64}; // VC6 won't eat a const static int here
+
+    void transform(const uint1 block[blocksize]);
+    static void decode(uint4 output[], const uint1 input[], size_type len);
+    static void encode(uint1 output[], const uint4 input[], size_type len);
+
+    bool finalized;
+    uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk
+    uint4 count[2];   // 64bit counter for number of bits (lo, hi)
+    uint4 state[4];   // digest so far
+    uint1 digest[16]; // the result
+
+    // low level logic operations
+    static inline uint4 F(uint4 x, uint4 y, uint4 z);
+    static inline uint4 G(uint4 x, uint4 y, uint4 z);
+    static inline uint4 H(uint4 x, uint4 y, uint4 z);
+    static inline uint4 I(uint4 x, uint4 y, uint4 z);
+    static inline uint4 rotate_left(uint4 x, int n);
+    static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+    static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+    static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+    static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+};
+
+
+} /* namespace toolkit */
+
+#endif /* SRC_UTIL_MD5_H_ */

+ 174 - 0
3rdparty/ZLToolKit/include/Util/NoticeCenter.h

@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef SRC_UTIL_NOTICECENTER_H_
+#define SRC_UTIL_NOTICECENTER_H_
+
+#include <mutex>
+#include <memory>
+#include <string>
+#include <exception>
+#include <functional>
+#include <unordered_map>
+#include <stdexcept>
+#include "function_traits.h"
+
+namespace toolkit {
+
+class EventDispatcher {
+public:
+    friend class NoticeCenter;
+    using Ptr = std::shared_ptr<EventDispatcher>;
+
+    ~EventDispatcher() = default;
+
+private:
+    using MapType = std::unordered_multimap<void *, std::shared_ptr<void> >;
+
+    EventDispatcher() = default;
+
+    class InterruptException : public std::runtime_error {
+    public:
+        InterruptException() : std::runtime_error("InterruptException") {}
+
+        ~InterruptException() {}
+    };
+
+    template<typename ...ArgsType>
+    int emitEvent(ArgsType &&...args) {
+        using funType = std::function<void(decltype(std::forward<ArgsType>(args))...)>;
+        decltype(_mapListener) copy;
+        {
+            //先拷贝(开销比较小),目的是防止在触发回调时还是上锁状态从而导致交叉互锁
+            std::lock_guard<std::recursive_mutex> lck(_mtxListener);
+            copy = _mapListener;
+        }
+
+        int ret = 0;
+        for (auto &pr : copy) {
+            funType *obj = (funType *) (pr.second.get());
+            try {
+                (*obj)(std::forward<ArgsType>(args)...);
+                ++ret;
+            } catch (InterruptException &) {
+                ++ret;
+                break;
+            }
+        }
+        return ret;
+    }
+
+    template<typename FUNC>
+    void addListener(void *tag, FUNC &&func) {
+        using funType = typename function_traits<typename std::remove_reference<FUNC>::type>::stl_function_type;
+        std::shared_ptr<void> pListener(new funType(std::forward<FUNC>(func)), [](void *ptr) {
+            funType *obj = (funType *) ptr;
+            delete obj;
+        });
+        std::lock_guard<std::recursive_mutex> lck(_mtxListener);
+        _mapListener.emplace(tag, pListener);
+    }
+
+    void delListener(void *tag, bool &empty) {
+        std::lock_guard<std::recursive_mutex> lck(_mtxListener);
+        _mapListener.erase(tag);
+        empty = _mapListener.empty();
+    }
+
+private:
+    std::recursive_mutex _mtxListener;
+    MapType _mapListener;
+};
+
+class NoticeCenter : public std::enable_shared_from_this<NoticeCenter> {
+public:
+    using Ptr = std::shared_ptr<NoticeCenter>;
+
+    static NoticeCenter &Instance();
+
+    template<typename ...ArgsType>
+    int emitEvent(const std::string &strEvent, ArgsType &&...args) {
+        auto dispatcher = getDispatcher(strEvent);
+        if (!dispatcher) {
+            //该事件无人监听
+            return 0;
+        }
+        return dispatcher->emitEvent(std::forward<ArgsType>(args)...);
+    }
+
+    template<typename FUNC>
+    void addListener(void *tag, const std::string &event, FUNC &&func) {
+        getDispatcher(event, true)->addListener(tag, std::forward<FUNC>(func));
+    }
+
+    void delListener(void *tag, const std::string &event) {
+        auto dispatcher = getDispatcher(event);
+        if (!dispatcher) {
+            //不存在该事件
+            return;
+        }
+        bool empty;
+        dispatcher->delListener(tag, empty);
+        if (empty) {
+            delDispatcher(event, dispatcher);
+        }
+    }
+
+    //这个方法性能比较差
+    void delListener(void *tag) {
+        std::lock_guard<std::recursive_mutex> lck(_mtxListener);
+        bool empty;
+        for (auto it = _mapListener.begin(); it != _mapListener.end();) {
+            it->second->delListener(tag, empty);
+            if (empty) {
+                it = _mapListener.erase(it);
+                continue;
+            }
+            ++it;
+        }
+    }
+
+    void clearAll() {
+        std::lock_guard<std::recursive_mutex> lck(_mtxListener);
+        _mapListener.clear();
+    }
+
+private:
+    EventDispatcher::Ptr getDispatcher(const std::string &event, bool create = false) {
+        std::lock_guard<std::recursive_mutex> lck(_mtxListener);
+        auto it = _mapListener.find(event);
+        if (it != _mapListener.end()) {
+            return it->second;
+        }
+        if (create) {
+            //如果为空则创建一个
+            EventDispatcher::Ptr dispatcher(new EventDispatcher());
+            _mapListener.emplace(event, dispatcher);
+            return dispatcher;
+        }
+        return nullptr;
+    }
+
+    void delDispatcher(const std::string &event, const EventDispatcher::Ptr &dispatcher) {
+        std::lock_guard<std::recursive_mutex> lck(_mtxListener);
+        auto it = _mapListener.find(event);
+        if (it != _mapListener.end() && dispatcher == it->second) {
+            //两者相同则删除
+            _mapListener.erase(it);
+        }
+    }
+
+private:
+    std::recursive_mutex _mtxListener;
+    std::unordered_map<std::string, EventDispatcher::Ptr> _mapListener;
+};
+
+} /* namespace toolkit */
+#endif /* SRC_UTIL_NOTICECENTER_H_ */

+ 205 - 0
3rdparty/ZLToolKit/include/Util/ResourcePool.h

@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef UTIL_RECYCLEPOOL_H_
+#define UTIL_RECYCLEPOOL_H_
+
+#include "List.h"
+#include <atomic>
+#include <deque>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <unordered_set>
+
+namespace toolkit {
+
+#if (defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 9))) || defined(__clang__)             \
+    || !defined(__GNUC__)
+#define SUPPORT_DYNAMIC_TEMPLATE
+#endif
+
+template <typename C>
+class ResourcePool_l;
+template <typename C>
+class ResourcePool;
+
+template <typename C>
+class shared_ptr_imp : public std::shared_ptr<C> {
+public:
+    shared_ptr_imp() {}
+
+    /**
+     * 构造智能指针
+     * @param ptr 裸指针
+     * @param weakPool 管理本指针的循环池
+     * @param quit 对接是否放弃循环使用
+     */
+    shared_ptr_imp(
+        C *ptr, const std::weak_ptr<ResourcePool_l<C>> &weakPool, std::shared_ptr<std::atomic_bool> quit,
+        const std::function<void(C *)> &on_recycle);
+
+    /**
+     * 放弃或恢复回到循环池继续使用
+     * @param flag
+     */
+    void quit(bool flag = true) {
+        if (_quit) {
+            *_quit = flag;
+        }
+    }
+
+private:
+    std::shared_ptr<std::atomic_bool> _quit;
+};
+
+template <typename C>
+class ResourcePool_l : public std::enable_shared_from_this<ResourcePool_l<C>> {
+public:
+    using ValuePtr = shared_ptr_imp<C>;
+    friend class shared_ptr_imp<C>;
+    friend class ResourcePool<C>;
+
+    ResourcePool_l() {
+        _alloc = []() -> C * { return new C(); };
+    }
+
+#if defined(SUPPORT_DYNAMIC_TEMPLATE)
+    template <typename... ArgTypes>
+    ResourcePool_l(ArgTypes &&...args) {
+        _alloc = [args...]() -> C * { return new C(args...); };
+    }
+#endif // defined(SUPPORT_DYNAMIC_TEMPLATE)
+
+    ~ResourcePool_l() {
+        for (auto ptr : _objs) {
+            delete ptr;
+        }
+    }
+
+    void setSize(size_t size) {
+        _pool_size = size;
+        _objs.reserve(size);
+    }
+
+    ValuePtr obtain(const std::function<void(C *)> &on_recycle = nullptr) {
+        return ValuePtr(getPtr(), _weak_self, std::make_shared<std::atomic_bool>(false), on_recycle);
+    }
+
+    std::shared_ptr<C> obtain2() {
+        auto weak_self = _weak_self;
+        return std::shared_ptr<C>(getPtr(), [weak_self](C *ptr) {
+            auto strongPool = weak_self.lock();
+            if (strongPool) {
+                //放入循环池
+                strongPool->recycle(ptr);
+            } else {
+                delete ptr;
+            }
+        });
+    }
+
+private:
+    void recycle(C *obj) {
+        auto is_busy = _busy.test_and_set();
+        if (!is_busy) {
+            //获取到锁
+            if (_objs.size() >= _pool_size) {
+                delete obj;
+            } else {
+                _objs.emplace_back(obj);
+            }
+            _busy.clear();
+        } else {
+            //未获取到锁
+            delete obj;
+        }
+    }
+
+    C *getPtr() {
+        C *ptr;
+        auto is_busy = _busy.test_and_set();
+        if (!is_busy) {
+            //获取到锁
+            if (_objs.size() == 0) {
+                ptr = _alloc();
+            } else {
+                ptr = _objs.back();
+                _objs.pop_back();
+            }
+            _busy.clear();
+        } else {
+            //未获取到锁
+            ptr = _alloc();
+        }
+        return ptr;
+    }
+
+    void setup() { _weak_self = this->shared_from_this(); }
+
+private:
+    size_t _pool_size = 8;
+    std::vector<C *> _objs;
+    std::function<C *(void)> _alloc;
+    std::atomic_flag _busy { false };
+    std::weak_ptr<ResourcePool_l> _weak_self;
+};
+
+/**
+ * 循环池,注意,循环池里面的对象不能继承enable_shared_from_this!
+ * @tparam C
+ */
+template <typename C>
+class ResourcePool {
+public:
+    using ValuePtr = shared_ptr_imp<C>;
+    ResourcePool() {
+        pool.reset(new ResourcePool_l<C>());
+        pool->setup();
+    }
+#if defined(SUPPORT_DYNAMIC_TEMPLATE)
+    template <typename... ArgTypes>
+    ResourcePool(ArgTypes &&...args) {
+        pool = std::make_shared<ResourcePool_l<C>>(std::forward<ArgTypes>(args)...);
+        pool->setup();
+    }
+#endif // defined(SUPPORT_DYNAMIC_TEMPLATE)
+    void setSize(size_t size) { pool->setSize(size); }
+
+    //获取一个对象,性能差些,但是功能丰富些
+    ValuePtr obtain(const std::function<void(C *)> &on_recycle = nullptr) { return pool->obtain(on_recycle); }
+
+    //获取一个对象,性能好些
+    std::shared_ptr<C> obtain2() { return pool->obtain2(); }
+
+private:
+    std::shared_ptr<ResourcePool_l<C>> pool;
+};
+
+template<typename C>
+shared_ptr_imp<C>::shared_ptr_imp(C *ptr,
+                                  const std::weak_ptr<ResourcePool_l<C> > &weakPool,
+                                  std::shared_ptr<std::atomic_bool> quit,
+                                  const std::function<void(C *)> &on_recycle) :
+    std::shared_ptr<C>(ptr, [weakPool, quit, on_recycle](C *ptr) {
+            if (on_recycle) {
+                on_recycle(ptr);
+            }
+            auto strongPool = weakPool.lock();
+            if (strongPool && !(*quit)) {
+                //循环池还在并且不放弃放入循环池
+                strongPool->recycle(ptr);
+            } else {
+                delete ptr;
+            }
+        }), _quit(std::move(quit)) {}
+
+} /* namespace toolkit */
+#endif /* UTIL_RECYCLEPOOL_H_ */

+ 438 - 0
3rdparty/ZLToolKit/include/Util/RingBuffer.h

@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef UTIL_RINGBUFFER_H_
+#define UTIL_RINGBUFFER_H_
+
+#include <assert.h>
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <condition_variable>
+#include <functional>
+#include "List.h"
+#include "Poller/EventPoller.h"
+
+// GOP缓存最大长度下限值
+#define RING_MIN_SIZE 32
+#define LOCK_GUARD(mtx) std::lock_guard<decltype(mtx)> lck(mtx)
+
+namespace toolkit {
+
+using ReaderInfo = std::shared_ptr<void>;
+
+template <typename T>
+class RingDelegate {
+public:
+    using Ptr = std::shared_ptr<RingDelegate>;
+    RingDelegate() = default;
+    virtual ~RingDelegate() = default;
+    virtual void onWrite(T in, bool is_key = true) = 0;
+};
+
+template <typename T>
+class _RingStorage;
+
+template <typename T>
+class _RingReaderDispatcher;
+
+/**
+ * 环形缓存读取器
+ * 该对象的事件触发都会在绑定的poller线程中执行
+ * 所以把锁去掉了
+ * 对该对象的一切操作都应该在poller线程中执行
+ */
+template <typename T>
+class _RingReader {
+public:
+    using Ptr = std::shared_ptr<_RingReader>;
+    friend class _RingReaderDispatcher<T>;
+
+    _RingReader(std::shared_ptr<_RingStorage<T>> storage) { _storage = std::move(storage); }
+
+    ~_RingReader() = default;
+
+    void setReadCB(std::function<void(const T &)> cb) {
+        if (!cb) {
+            _read_cb = [](const T &) {};
+        } else {
+            _read_cb = std::move(cb);
+            flushGop();
+        }
+    }
+
+    void setDetachCB(std::function<void()> cb) {
+        _detach_cb = cb ? std::move(cb) : []() {};
+    }
+
+    void setGetInfoCB(std::function<ReaderInfo()> cb) {
+        _get_info = cb ? std::move(cb) : []() { return ReaderInfo(); };
+    }
+
+private:
+    void onRead(const T &data, bool /*is_key*/) { _read_cb(data); }
+
+    void onDetach() const { _detach_cb(); }
+
+    void flushGop() {
+        if (!_storage) {
+            return;
+        }
+        _storage->getCache().for_each([this](const List<std::pair<bool, T>> &lst) {
+            lst.for_each([this](const std::pair<bool, T> &pr) { onRead(pr.second, pr.first); });
+        });
+    }
+
+    ReaderInfo getInfo() { return _get_info(); }
+
+private:
+    std::shared_ptr<_RingStorage<T>> _storage;
+    std::function<void(void)> _detach_cb = []() {};
+    std::function<void(const T &)> _read_cb = [](const T &) {};
+    std::function<ReaderInfo()> _get_info = []() { return ReaderInfo(); };
+};
+
+template <typename T>
+class _RingStorage {
+public:
+    using Ptr = std::shared_ptr<_RingStorage>;
+    using GopType = List<List<std::pair<bool, T>>>;
+    _RingStorage(size_t max_size, size_t max_gop_size) {
+        // gop缓存个数不能小于32
+        if (max_size < RING_MIN_SIZE) {
+            max_size = RING_MIN_SIZE;
+        }
+        _max_size = max_size;
+        _max_gop_size = max_gop_size;
+        clearCache();
+    }
+
+    ~_RingStorage() = default;
+
+    /**
+     * 写入环形缓存数据
+     * @param in 数据
+     * @param is_key 是否为关键帧
+     * @return 是否触发重置环形缓存大小
+     */
+    void write(T in, bool is_key = true) {
+        if (is_key) {
+            _have_idr = true;
+            _started = true;
+            if (!_data_cache.back().empty()) {
+                //当前gop列队还没收到任意缓存
+                _data_cache.emplace_back();
+            }
+            if (_data_cache.size() > _max_gop_size) {
+                // GOP个数超过限制,那么移除最早的GOP
+                popFrontGop();
+            }
+        }
+
+        if (!_have_idr && _started) {
+            //缓存中没有关键帧,那么gop缓存无效
+            return;
+        }
+        _data_cache.back().emplace_back(std::make_pair(is_key, std::move(in)));
+        if (++_size > _max_size) {
+            // GOP缓存溢出
+            while (_data_cache.size() > 1) {
+                //先尝试清除老的GOP缓存
+                popFrontGop();
+            }
+            if (_size > _max_size) {
+                //还是大于最大缓冲限制,那么清空所有GOP
+                clearCache();
+            }
+        }
+    }
+
+    Ptr clone() const {
+        Ptr ret(new _RingStorage());
+        ret->_size = _size;
+        ret->_have_idr = _have_idr;
+        ret->_started = _started;
+        ret->_max_size = _max_size;
+        ret->_max_gop_size = _max_gop_size;
+        ret->_data_cache = _data_cache;
+        return ret;
+    }
+
+    const GopType &getCache() const { return _data_cache; }
+
+    void clearCache() {
+        _size = 0;
+        _have_idr = false;
+        _data_cache.clear();
+        _data_cache.emplace_back();
+    }
+
+private:
+    _RingStorage() = default;
+
+    void popFrontGop() {
+        if (!_data_cache.empty()) {
+            _size -= _data_cache.front().size();
+            _data_cache.pop_front();
+            if (_data_cache.empty()) {
+                _data_cache.emplace_back();
+            }
+        }
+    }
+
+private:
+    bool _started = false;
+    bool _have_idr;
+    size_t _size;
+    size_t _max_size;
+    size_t _max_gop_size;
+    GopType _data_cache;
+};
+
+template <typename T>
+class RingBuffer;
+
+/**
+ * 环形缓存事件派发器,只能一个poller线程操作它
+ * @tparam T
+ */
+template <typename T>
+class _RingReaderDispatcher : public std::enable_shared_from_this<_RingReaderDispatcher<T>> {
+public:
+    using Ptr = std::shared_ptr<_RingReaderDispatcher>;
+    using RingReader = _RingReader<T>;
+    using RingStorage = _RingStorage<T>;
+    using onChangeInfoCB = std::function<ReaderInfo(ReaderInfo &&info)>;
+
+    friend class RingBuffer<T>;
+
+    ~_RingReaderDispatcher() {
+        decltype(_reader_map) reader_map;
+        reader_map.swap(_reader_map);
+        for (auto &pr : reader_map) {
+            auto reader = pr.second.lock();
+            if (reader) {
+                reader->onDetach();
+            }
+        }
+    }
+
+private:
+    _RingReaderDispatcher(
+        const typename RingStorage::Ptr &storage, std::function<void(int, bool)> onSizeChanged) {
+        _reader_size = 0;
+        _storage = storage;
+        _on_size_changed = std::move(onSizeChanged);
+        assert(_on_size_changed);
+    }
+
+    void write(T in, bool is_key = true) {
+        for (auto it = _reader_map.begin(); it != _reader_map.end();) {
+            auto reader = it->second.lock();
+            if (!reader) {
+                it = _reader_map.erase(it);
+                --_reader_size;
+                onSizeChanged(false);
+                continue;
+            }
+            reader->onRead(in, is_key);
+            ++it;
+        }
+        _storage->write(std::move(in), is_key);
+    }
+
+    std::shared_ptr<RingReader> attach(const EventPoller::Ptr &poller, bool use_cache) {
+        if (!poller->isCurrentThread()) {
+            throw std::runtime_error("You can attach RingBuffer only in it's poller thread");
+        }
+
+        std::weak_ptr<_RingReaderDispatcher> weak_self = this->shared_from_this();
+        auto on_dealloc = [weak_self, poller](RingReader *ptr) {
+            poller->async([weak_self, ptr]() {
+                auto strong_self = weak_self.lock();
+                if (strong_self && strong_self->_reader_map.erase(ptr)) {
+                    --strong_self->_reader_size;
+                    strong_self->onSizeChanged(false);
+                }
+                delete ptr;
+            });
+        };
+
+        std::shared_ptr<RingReader> reader(new RingReader(use_cache ? _storage : nullptr), on_dealloc);
+        _reader_map[reader.get()] = reader;
+        ++_reader_size;
+        onSizeChanged(true);
+        return reader;
+    }
+
+    void onSizeChanged(bool add_flag) { _on_size_changed(_reader_size, add_flag); }
+
+    void clearCache() {
+        if (_reader_size == 0) {
+            _storage->clearCache();
+        }
+    }
+
+    std::list<ReaderInfo> getInfoList(const onChangeInfoCB &on_change) {
+        std::list<ReaderInfo> ret;
+        for (auto &pr : _reader_map) {
+            auto reader = pr.second.lock();
+            if (!reader) {
+                continue;
+            }
+            auto info = reader->getInfo();
+            if (!info) {
+                continue;
+            }
+            ret.emplace_back(on_change(std::move(info)));
+        }
+        return ret;
+    }
+
+private:
+    std::atomic_int _reader_size;
+    std::function<void(int, bool)> _on_size_changed;
+    typename RingStorage::Ptr _storage;
+    std::unordered_map<void *, std::weak_ptr<RingReader>> _reader_map;
+};
+
+template <typename T>
+class RingBuffer : public std::enable_shared_from_this<RingBuffer<T>> {
+public:
+    using Ptr = std::shared_ptr<RingBuffer>;
+    using RingReader = _RingReader<T>;
+    using RingStorage = _RingStorage<T>;
+    using RingReaderDispatcher = _RingReaderDispatcher<T>;
+    using onReaderChanged = std::function<void(int size)>;
+    using onGetInfoCB = std::function<void(std::list<ReaderInfo> &info_list)>;
+
+    RingBuffer(size_t max_size = 1024, onReaderChanged cb = nullptr, size_t max_gop_size = 1) {
+        _storage = std::make_shared<RingStorage>(max_size, max_gop_size);
+        _on_reader_changed = cb ? std::move(cb) : [](int size) {};
+        //先触发无人观看
+        _on_reader_changed(0);
+    }
+
+    ~RingBuffer() = default;
+
+    void write(T in, bool is_key = true) {
+        if (_delegate) {
+            _delegate->onWrite(std::move(in), is_key);
+            return;
+        }
+
+        LOCK_GUARD(_mtx_map);
+        for (auto &pr : _dispatcher_map) {
+            auto &second = pr.second;
+            //切换线程后触发onRead事件
+            pr.first->async([second, in, is_key]() { second->write(std::move(const_cast<T &>(in)), is_key); }, false);
+        }
+        _storage->write(std::move(in), is_key);
+    }
+
+    void setDelegate(const typename RingDelegate<T>::Ptr &delegate) { _delegate = delegate; }
+
+    std::shared_ptr<RingReader> attach(const EventPoller::Ptr &poller, bool use_cache = true) {
+        typename RingReaderDispatcher::Ptr dispatcher;
+        {
+            LOCK_GUARD(_mtx_map);
+            auto &ref = _dispatcher_map[poller];
+            if (!ref) {
+                std::weak_ptr<RingBuffer> weak_self = this->shared_from_this();
+                auto onSizeChanged = [weak_self, poller](int size, bool add_flag) {
+                    if (auto strong_self = weak_self.lock()) {
+                        strong_self->onSizeChanged(poller, size, add_flag);
+                    }
+                };
+                auto onDealloc = [poller](RingReaderDispatcher *ptr) { poller->async([ptr]() { delete ptr; }); };
+                ref.reset(new RingReaderDispatcher(_storage->clone(), std::move(onSizeChanged)), std::move(onDealloc));
+            }
+            dispatcher = ref;
+        }
+
+        return dispatcher->attach(poller, use_cache);
+    }
+
+    int readerCount() { return _total_count; }
+
+    void clearCache() {
+        LOCK_GUARD(_mtx_map);
+        _storage->clearCache();
+        for (auto &pr : _dispatcher_map) {
+            auto &second = pr.second;
+            //切换线程后清空缓存
+            pr.first->async([second]() { second->clearCache(); }, false);
+        }
+    }
+
+    void getInfoList(const onGetInfoCB &cb, const typename RingReaderDispatcher::onChangeInfoCB &on_change = nullptr) {
+        if (!cb) {
+            return;
+        }
+        if (!on_change) {
+            const_cast<typename RingReaderDispatcher::onChangeInfoCB &>(on_change) = [](ReaderInfo &&info) { return std::move(info); };
+        }
+
+        LOCK_GUARD(_mtx_map);
+
+        auto info_vec = std::make_shared<std::vector<std::list<ReaderInfo>>>();
+        // 1、最少确保一个元素
+        info_vec->resize(_dispatcher_map.empty() ? 1 : _dispatcher_map.size());
+        std::shared_ptr<void> on_finished(nullptr, [cb, info_vec](void *) mutable {
+            // 2、防止这里为空
+            auto &lst = *info_vec->begin();
+            for (auto &item : *info_vec) {
+                if (&lst != &item) {
+                    lst.insert(lst.end(), item.begin(), item.end());
+                }
+            }
+            cb(lst);
+        });
+
+        auto i = 0U;
+        for (auto &pr : _dispatcher_map) {
+            auto &second = pr.second;
+            pr.first->async([second, info_vec, on_finished, i, on_change]() { (*info_vec)[i] = second->getInfoList(on_change); });
+            ++i;
+        }
+    }
+
+private:
+    void onSizeChanged(const EventPoller::Ptr &poller, int size, bool add_flag) {
+        if (size == 0) {
+            LOCK_GUARD(_mtx_map);
+            _dispatcher_map.erase(poller);
+        }
+
+        if (add_flag) {
+            ++_total_count;
+        } else {
+            --_total_count;
+        }
+        _on_reader_changed(_total_count);
+    }
+
+private:
+    struct HashOfPtr {
+        std::size_t operator()(const EventPoller::Ptr &key) const { return (std::size_t)key.get(); }
+    };
+
+private:
+    std::mutex _mtx_map;
+    std::atomic_int _total_count { 0 };
+    typename RingStorage::Ptr _storage;
+    typename RingDelegate<T>::Ptr _delegate;
+    onReaderChanged _on_reader_changed;
+    std::unordered_map<EventPoller::Ptr, typename RingReaderDispatcher::Ptr, HashOfPtr> _dispatcher_map;
+};
+
+} /* namespace toolkit */
+#endif /* UTIL_RINGBUFFER_H_ */

+ 47 - 0
3rdparty/ZLToolKit/include/Util/SHA1.h

@@ -0,0 +1,47 @@
+//	100% Public Domain.
+//
+//	Original C Code
+//	 -- Steve Reid <steve@edmweb.com>
+//	Small changes to fit into bglibs
+//	  -- Bruce Guenter <bruce@untroubled.org>
+//	Translation to simpler C++ Code
+//	  -- Volker Grabsch <vog@notjusthosting.com>
+//	Safety fixes
+//	  -- Eugene Hopkinson <slowriot at voxelstorm dot com>
+//  Adapt for project
+//      Dmitriy Khaustov <khaustov.dm@gmail.com>
+//
+// File created on: 2017.02.25
+
+// SHA1.h
+
+#pragma once
+
+#include <cstdint>
+#include <iostream>
+#include <string>
+
+namespace toolkit {
+
+class SHA1 final
+{
+public:
+    SHA1();
+
+    void update(const std::string &s);
+    void update(std::istream &is);
+    std::string final();
+    std::string final_bin();
+
+    static std::string from_file(const std::string &filename);
+
+    static std::string encode(const std::string &s);
+    static std::string encode_bin(const std::string &s);
+
+private:
+    uint32_t digest[5];
+    std::string buffer;
+    uint64_t transforms;
+};
+
+}//namespace toolkit

+ 206 - 0
3rdparty/ZLToolKit/include/Util/SSLBox.h

@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef CRYPTO_SSLBOX_H_
+#define CRYPTO_SSLBOX_H_
+
+#include <mutex>
+#include <string>
+#include <functional>
+#include "logger.h"
+#include "List.h"
+#include "util.h"
+#include "Network/Buffer.h"
+#include "ResourcePool.h"
+
+typedef struct x509_st X509;
+typedef struct evp_pkey_st EVP_PKEY;
+typedef struct ssl_ctx_st SSL_CTX;
+typedef struct ssl_st SSL;
+typedef struct bio_st BIO;
+
+namespace toolkit {
+
+class SSL_Initor {
+public:
+    friend class SSL_Box;
+
+    static SSL_Initor &Instance();
+
+    /**
+     * 从文件或字符串中加载公钥和私钥
+     * 该证书文件必须同时包含公钥和私钥(cer格式的证书只包括公钥,请使用后面的方法加载)
+     * 客户端默认可以不加载证书(除非服务器要求客户端提供证书)
+     * @param pem_or_p12 pem或p12文件路径或者文件内容字符串
+     * @param server_mode 是否为服务器模式
+     * @param password 私钥加密密码
+     * @param is_file 参数pem_or_p12是否为文件路径
+     * @param is_default 是否为默认证书
+     */
+    bool loadCertificate(const std::string &pem_or_p12, bool server_mode = true, const std::string &password = "",
+                         bool is_file = true, bool is_default = true);
+
+    /**
+     * 是否忽略无效的证书
+     * 默认忽略,强烈建议不要忽略!
+     * @param ignore 标记
+     */
+    void ignoreInvalidCertificate(bool ignore = true);
+
+    /**
+     * 信任某证书,一般用于客户端信任自签名的证书或自签名CA签署的证书使用
+     * 比如说我的客户端要信任我自己签发的证书,那么我们可以只信任这个证书
+     * @param pem_p12_cer pem文件或p12文件或cer文件路径或内容
+     * @param server_mode 是否为服务器模式
+     * @param password pem或p12证书的密码
+     * @param is_file 是否为文件路径
+     * @return 是否加载成功
+     */
+    bool trustCertificate(const std::string &pem_p12_cer, bool server_mode = false, const std::string &password = "",
+                          bool is_file = true);
+
+    /**
+     * 信任某证书
+     * @param cer 证书公钥
+     * @param server_mode 是否为服务模式
+     * @return 是否加载成功
+     */
+    bool trustCertificate(X509 *cer, bool server_mode = false);
+
+private:
+    SSL_Initor();
+    ~SSL_Initor();
+
+    /**
+     * 创建SSL对象
+     */
+    std::shared_ptr<SSL> makeSSL(bool server_mode);
+
+    /**
+     * 设置ssl context
+     * @param vhost 虚拟主机名
+     * @param ctx ssl context
+     * @param server_mode ssl context
+     * @param is_default 是否为默认证书
+     */
+    bool setContext(const std::string &vhost, const std::shared_ptr<SSL_CTX> &ctx, bool server_mode, bool is_default = true);
+
+    /**
+     * 设置SSL_CTX的默认配置
+     * @param ctx 对象指针
+     */
+    void setupCtx(SSL_CTX *ctx);
+
+    /**
+     * 根据虚拟主机获取SSL_CTX对象
+     * @param vhost 虚拟主机名
+     * @param server_mode 是否为服务器模式
+     * @return SSL_CTX对象
+     */
+    std::shared_ptr<SSL_CTX> getSSLCtx(const std::string &vhost, bool server_mode);
+
+    std::shared_ptr<SSL_CTX> getSSLCtx_l(const std::string &vhost, bool server_mode);
+
+    std::shared_ptr<SSL_CTX> getSSLCtxWildcards(const std::string &vhost, bool server_mode);
+
+    /**
+     * 获取默认的虚拟主机
+     */
+    std::string defaultVhost(bool server_mode);
+
+    /**
+     * 完成vhost name 匹配的回调函数
+     */
+    static int findCertificate(SSL *ssl, int *ad, void *arg);
+
+private:
+    struct less_nocase {
+        bool operator()(const std::string &x, const std::string &y) const {
+            return strcasecmp(x.data(), y.data()) < 0;
+        }
+    };
+
+private:
+    std::string _default_vhost[2];
+    std::shared_ptr<SSL_CTX> _ctx_empty[2];
+    std::map<std::string, std::shared_ptr<SSL_CTX>, less_nocase> _ctxs[2];
+    std::map<std::string, std::shared_ptr<SSL_CTX>, less_nocase> _ctxs_wildcards[2];
+};
+
+////////////////////////////////////////////////////////////////////////////////////
+
+class SSL_Box {
+public:
+    SSL_Box(bool server_mode = true, bool enable = true, int buff_size = 32 * 1024);
+
+    ~SSL_Box();
+
+    /**
+     * 收到密文后,调用此函数解密
+     * @param buffer 收到的密文数据
+     */
+    void onRecv(const Buffer::Ptr &buffer);
+
+    /**
+     * 需要加密明文调用此函数
+     * @param buffer 需要加密的明文数据
+     */
+    void onSend(Buffer::Ptr buffer);
+
+    /**
+     * 设置解密后获取明文的回调
+     * @param cb 回调对象
+     */
+    void setOnDecData(const std::function<void(const Buffer::Ptr &)> &cb);
+
+    /**
+     * 设置加密后获取密文的回调
+     * @param cb 回调对象
+     */
+    void setOnEncData(const std::function<void(const Buffer::Ptr &)> &cb);
+
+    /**
+     * 终结ssl
+     */
+    void shutdown();
+
+    /**
+     * 清空数据
+     */
+    void flush();
+
+    /**
+     * 设置虚拟主机名
+     * @param host 虚拟主机名
+     * @return 是否成功
+     */
+    bool setHost(const char *host);
+
+private:
+    void flushWriteBio();
+
+    void flushReadBio();
+
+private:
+    bool _server_mode;
+    bool _send_handshake;
+    bool _is_flush = false;
+    int _buff_size;
+    BIO *_read_bio;
+    BIO *_write_bio;
+    std::shared_ptr<SSL> _ssl;
+    List <Buffer::Ptr> _buffer_send;
+    ResourcePool <BufferRaw> _buffer_pool;
+    std::function<void(const Buffer::Ptr &)> _on_dec;
+    std::function<void(const Buffer::Ptr &)> _on_enc;
+};
+
+} /* namespace toolkit */
+#endif /* CRYPTO_SSLBOX_H_ */

+ 121 - 0
3rdparty/ZLToolKit/include/Util/SSLUtil.h

@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ZLTOOLKIT_SSLUTIL_H
+#define ZLTOOLKIT_SSLUTIL_H
+
+#include <memory>
+#include <string>
+#include <vector>
+
+typedef struct x509_st X509;
+typedef struct evp_pkey_st EVP_PKEY;
+typedef struct ssl_ctx_st SSL_CTX;
+typedef struct ssl_st SSL;
+typedef struct bio_st BIO;
+
+namespace toolkit {
+/**
+ * ssl证书后缀一般分为以下几种
+ * pem:这个是base64的字符编码串,可能存在公钥、私钥或者两者都存在
+ * cer:只且只能是公钥,可以与pem的私钥配合使用
+ * p12:必须包括私钥和公钥
+ */
+class SSLUtil {
+public:
+    static std::string getLastError();
+
+    /**
+     * 加载公钥证书,支持pem,p12,cer后缀
+     * 由于openssl加载p12证书时会校验公钥和私钥是否匹对,所以加载p12的公钥时可能需要传入证书密码
+     * @param file_path_or_data 文件路径或文件内容
+     * @param isFile 是否为文件
+     * @return 公钥证书列表
+     */
+    static std::vector<std::shared_ptr<X509> > loadPublicKey(const std::string &file_path_or_data, const std::string &passwd = "", bool isFile = true);
+
+    /**
+     * 加载私钥证书,支持pem,p12后缀
+     * @param file_path_or_data 文件路径或文件内容
+     * @param passwd 密码
+     * @param isFile 是否为文件
+     * @return 私钥证书
+     */
+    static std::shared_ptr<EVP_PKEY> loadPrivateKey(const std::string &file_path_or_data, const std::string &passwd = "", bool isFile = true);
+
+    /**
+     * 创建SSL_CTX对象
+     * @param cer 公钥数组
+     * @param key 私钥
+     * @param serverMode 是否为服务器模式或客户端模式
+     * @return SSL_CTX对象
+     */
+    static std::shared_ptr<SSL_CTX> makeSSLContext(const std::vector<std::shared_ptr<X509> > &cers, const std::shared_ptr<EVP_PKEY> &key, bool serverMode = true, bool checkKey = false);
+
+    /**
+     * 创建ssl对象
+     * @param ctx SSL_CTX对象
+     */
+    static std::shared_ptr<SSL> makeSSL(SSL_CTX *ctx);
+
+    /**
+     * specifies that the default locations from which CA certificates are loaded should be used.
+     * There is one default directory and one default file.
+     * The default CA certificates directory is called "certs" in the default OpenSSL directory.
+     * Alternatively the SSL_CERT_DIR environment variable can be defined to override this location.
+     * The default CA certificates file is called "cert.pem" in the default OpenSSL directory.
+     *  Alternatively the SSL_CERT_FILE environment variable can be defined to override this location.
+     * 信任/usr/local/ssl/certs/目录下的所有证书/usr/local/ssl/cert.pem的证书
+     * 环境变量SSL_CERT_FILE将替换/usr/local/ssl/cert.pem的路径
+     */
+    static bool loadDefaultCAs(SSL_CTX *ctx);
+
+    /**
+     * 信任某公钥
+     */
+    static bool trustCertificate(SSL_CTX *ctx, X509 *cer);
+
+
+    /**
+     * 验证证书合法性
+     * @param cer 待验证的证书
+     * @param ... 信任的CA根证书,X509类型,以nullptr结尾
+     * @return 是否合法
+     */
+    static bool verifyX509(X509 *cer, ...);
+
+    /**
+     * 使用公钥加解密数据
+     * @param cer 公钥,必须为ras的公钥
+     * @param in_str 加密或解密的原始数据,实测加密最大支持245个字节,加密后数据长度固定为256个字节
+     * @param enc_or_dec true:加密,false:解密
+     * @return 加密或解密后的数据
+     */
+    static std::string cryptWithRsaPublicKey(X509 *cer, const std::string &in_str, bool enc_or_dec);
+
+    /**
+     * 使用私钥加解密数据
+     * @param private_key 私钥,必须为ras的私钥
+     * @param in_str 加密或解密的原始数据,实测加密最大支持245个字节,加密后数据长度固定为256个字节
+     * @param enc_or_dec true:加密,false:解密
+     * @return 加密或解密后的数据
+     */
+    static std::string cryptWithRsaPrivateKey(EVP_PKEY *private_key, const std::string &in_str, bool enc_or_dec);
+
+    /**
+     * 获取证书域名
+     * @param cer 证书公钥
+     * @return 证书域名
+     */
+    static std::string getServerName(X509 *cer);
+};
+
+}//namespace toolkit
+#endif //ZLTOOLKIT_SSLUTIL_H

+ 65 - 0
3rdparty/ZLToolKit/include/Util/SpeedStatistic.h

@@ -0,0 +1,65 @@
+/*
+* Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+*
+* This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+*
+* Use of this source code is governed by MIT license that can be found in the
+* LICENSE file in the root of the source tree. All contributing project authors
+* may be found in the AUTHORS file in the root of the source tree.
+*/
+
+#ifndef SPEED_STATISTIC_H_
+#define SPEED_STATISTIC_H_
+
+#include "TimeTicker.h"
+
+namespace toolkit {
+
+class BytesSpeed {
+public:
+    BytesSpeed() = default;
+    ~BytesSpeed() = default;
+
+    /**
+     * 添加统计字节
+     */
+    BytesSpeed &operator+=(size_t bytes) {
+        _bytes += bytes;
+        if (_bytes > 1024 * 1024) {
+            //数据大于1MB就计算一次网速
+            computeSpeed();
+        }
+        return *this;
+    }
+
+    /**
+     * 获取速度,单位bytes/s
+     */
+    int getSpeed() {
+        if (_ticker.elapsedTime() < 1000) {
+            //获取频率小于1秒,那么返回上次计算结果
+            return _speed;
+        }
+        return computeSpeed();
+    }
+
+private:
+    int computeSpeed() {
+        auto elapsed = _ticker.elapsedTime();
+        if (!elapsed) {
+            return _speed;
+        }
+        _speed = (int)(_bytes * 1000 / elapsed);
+        _ticker.resetTime();
+        _bytes = 0;
+        return _speed;
+    }
+
+private:
+    int _speed = 0;
+    size_t _bytes = 0;
+    Ticker _ticker;
+};
+
+} /* namespace toolkit */
+#endif /* SPEED_STATISTIC_H_ */

+ 248 - 0
3rdparty/ZLToolKit/include/Util/SqlConnection.h

@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef SQL_SQLCONNECTION_H_
+#define SQL_SQLCONNECTION_H_
+
+#include <cstdio>
+#include <cstdarg>
+#include <cstring>
+#include <string>
+#include <vector>
+#include <list>
+#include <deque>
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+#include "logger.h"
+#include "util.h"
+#include <mysql.h>
+
+#if defined(_WIN32)
+#pragma  comment (lib,"libmysql") 
+#endif
+
+namespace toolkit {
+
+/**
+ * 数据库异常类
+ */
+class SqlException : public std::exception {
+public:
+    SqlException(const std::string &sql, const std::string &err) {
+        _sql = sql;
+        _err = err;
+    }
+
+    virtual const char *what() const noexcept {
+        return _err.data();
+    }
+
+    const std::string &getSql() const {
+        return _sql;
+    }
+
+private:
+    std::string _sql;
+    std::string _err;
+};
+
+/**
+ * mysql连接
+ */
+class SqlConnection {
+public:
+    /**
+     * 构造函数
+     * @param url 数据库地址
+     * @param port 数据库端口号
+     * @param dbname 数据库名
+     * @param username 用户名
+     * @param password 用户密码
+     * @param character 字符集
+     */
+    SqlConnection(const std::string &url, unsigned short port,
+                  const std::string &dbname, const std::string &username,
+                  const std::string &password, const std::string &character = "utf8mb4") {
+        mysql_init(&_sql);
+        unsigned int timeout = 3;
+        mysql_options(&_sql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
+        if (!mysql_real_connect(&_sql, url.data(), username.data(),
+                                password.data(), dbname.data(), port, nullptr, 0)) {
+            mysql_close(&_sql);
+            throw SqlException("mysql_real_connect", mysql_error(&_sql));
+        }
+        //兼容bool与my_bool
+        uint32_t reconnect = 0x01010101;
+        mysql_options(&_sql, MYSQL_OPT_RECONNECT, &reconnect);
+        mysql_set_character_set(&_sql, character.data());
+    }
+
+    ~SqlConnection() {
+        mysql_close(&_sql);
+    }
+
+    /**
+     * 以printf样式执行sql,无数据返回
+     * @param rowId insert时的插入rowid
+     * @param fmt printf类型fmt
+     * @param arg 可变参数列表
+     * @return 影响行数
+     */
+    template<typename Fmt, typename ...Args>
+    int64_t query(int64_t &rowId, Fmt &&fmt, Args &&...arg) {
+        check();
+        auto tmp = queryString(std::forward<Fmt>(fmt), std::forward<Args>(arg)...);
+        if (doQuery(tmp)) {
+            throw SqlException(tmp, mysql_error(&_sql));
+        }
+        rowId = mysql_insert_id(&_sql);
+        return mysql_affected_rows(&_sql);
+    }
+
+    /**
+     * 以printf样式执行sql,并且返回list类型的结果(不包含数据列名)
+     * @param rowId insert时的插入rowid
+     * @param ret 返回数据列表
+     * @param fmt printf类型fmt
+     * @param arg 可变参数列表
+     * @return 影响行数
+     */
+    template<typename Fmt, typename ...Args>
+    int64_t query(int64_t &rowId, std::vector<std::vector<std::string> > &ret, Fmt &&fmt, Args &&...arg) {
+        return queryList(rowId, ret, std::forward<Fmt>(fmt), std::forward<Args>(arg)...);
+    }
+
+    template<typename Fmt, typename... Args>
+    int64_t query(int64_t &rowId, std::vector<std::list<std::string>> &ret, Fmt &&fmt, Args &&...arg) {
+        return queryList(rowId, ret, std::forward<Fmt>(fmt), std::forward<Args>(arg)...);
+    }
+
+    template<typename Fmt, typename ...Args>
+    int64_t query(int64_t &rowId, std::vector<std::deque<std::string> > &ret, Fmt &&fmt, Args &&...arg) {
+        return queryList(rowId, ret, std::forward<Fmt>(fmt), std::forward<Args>(arg)...);
+    }
+
+    /**
+     * 以printf样式执行sql,并且返回Map类型的结果(包含数据列名)
+     * @param rowId insert时的插入rowid
+     * @param ret 返回数据列表
+     * @param fmt printf类型fmt
+     * @param arg 可变参数列表
+     * @return 影响行数
+     */
+    template<typename Map, typename Fmt, typename ...Args>
+    int64_t query(int64_t &rowId, std::vector<Map> &ret, Fmt &&fmt, Args &&...arg) {
+        check();
+        auto tmp = queryString(std::forward<Fmt>(fmt), std::forward<Args>(arg)...);
+        if (doQuery(tmp)) {
+            throw SqlException(tmp, mysql_error(&_sql));
+        }
+        ret.clear();
+        MYSQL_RES *res = mysql_store_result(&_sql);
+        if (!res) {
+            rowId = mysql_insert_id(&_sql);
+            return mysql_affected_rows(&_sql);
+        }
+        MYSQL_ROW row;
+        unsigned int column = mysql_num_fields(res);
+        MYSQL_FIELD *fields = mysql_fetch_fields(res);
+        while ((row = mysql_fetch_row(res)) != nullptr) {
+            ret.emplace_back();
+            auto &back = ret.back();
+            for (unsigned int i = 0; i < column; i++) {
+                back[std::string(fields[i].name, fields[i].name_length)] = (row[i] ? row[i] : "");
+            }
+        }
+        mysql_free_result(res);
+        rowId = mysql_insert_id(&_sql);
+        return mysql_affected_rows(&_sql);
+    }
+
+    std::string escape(const std::string &str) {
+        char *out = new char[str.length() * 2 + 1];
+        mysql_real_escape_string(&_sql, out, str.c_str(), str.size());
+        std::string ret(out);
+        delete[] out;
+        return ret;
+    }
+
+    template<typename ...Args>
+    static std::string queryString(const char *fmt, Args &&...arg) {
+        char *ptr_out = nullptr;
+        if (asprintf(&ptr_out, fmt, arg...) > 0 && ptr_out) {
+            std::string ret(ptr_out);
+            free(ptr_out);
+            return ret;
+        }
+        return "";
+    }
+
+    template<typename ...Args>
+    static std::string queryString(const std::string &fmt, Args &&...args) {
+        return queryString(fmt.data(), std::forward<Args>(args)...);
+    }
+
+    static const char *queryString(const char *fmt) {
+        return fmt;
+    }
+
+    static const std::string &queryString(const std::string &fmt) {
+        return fmt;
+    }
+
+private:
+    template<typename List, typename Fmt, typename... Args>
+    int64_t queryList(int64_t &rowId, std::vector<List> &ret, Fmt &&fmt, Args &&...arg) {
+        check();
+        auto tmp = queryString(std::forward<Fmt>(fmt), std::forward<Args>(arg)...);
+        if (doQuery(tmp)) {
+            throw SqlException(tmp, mysql_error(&_sql));
+        }
+        ret.clear();
+        MYSQL_RES *res = mysql_store_result(&_sql);
+        if (!res) {
+            rowId = mysql_insert_id(&_sql);
+            return mysql_affected_rows(&_sql);
+        }
+        MYSQL_ROW row;
+        unsigned int column = mysql_num_fields(res);
+        while ((row = mysql_fetch_row(res)) != nullptr) {
+            ret.emplace_back();
+            auto &back = ret.back();
+            for (unsigned int i = 0; i < column; i++) {
+                back.emplace_back(row[i] ? row[i] : "");
+            }
+        }
+        mysql_free_result(res);
+        rowId = mysql_insert_id(&_sql);
+        return mysql_affected_rows(&_sql);
+    }
+
+    inline void check() {
+        if (mysql_ping(&_sql) != 0) {
+            throw SqlException("mysql_ping", "Mysql connection ping failed");
+        }
+    }
+
+    int doQuery(const std::string &sql) {
+        return mysql_query(&_sql, sql.data());
+    }
+
+    int doQuery(const char *sql) {
+        return mysql_query(&_sql, sql);
+    }
+
+private:
+    MYSQL _sql;
+};
+
+} /* namespace toolkit */
+#endif /* SQL_SQLCONNECTION_H_ */

+ 307 - 0
3rdparty/ZLToolKit/include/Util/SqlPool.h

@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef SQL_SQLPOOL_H_
+#define SQL_SQLPOOL_H_
+
+#include <deque>
+#include <mutex>
+#include <memory>
+#include <sstream>
+#include <functional>
+#include "logger.h"
+#include "Poller/Timer.h"
+#include "SqlConnection.h"
+#include "Thread/WorkThreadPool.h"
+#include "ResourcePool.h"
+
+namespace toolkit {
+
+class SqlPool : public std::enable_shared_from_this<SqlPool> {
+public:
+    using Ptr = std::shared_ptr<SqlPool>;
+    using PoolType = ResourcePool<SqlConnection>;
+    using SqlRetType = std::vector<std::vector<std::string> >;
+
+    static SqlPool &Instance();
+
+    ~SqlPool() {
+        _timer.reset();
+        flushError();
+        _threadPool.reset();
+        _pool.reset();
+        InfoL;
+    }
+
+    /**
+     * 设置循环池对象个数
+     * @param size
+     */
+    void setSize(int size) {
+        checkInited();
+        _pool->setSize(size);
+    }
+
+    /**
+     * 初始化循环池,设置数据库连接参数
+     * @tparam Args
+     * @param arg
+     */
+    template<typename ...Args>
+    void Init(Args &&...arg) {
+        _pool.reset(new PoolType(std::forward<Args>(arg)...));
+        _pool->obtain();
+    }
+
+
+    /**
+     * 异步执行sql
+     * @param str sql语句
+     * @param tryCnt 重试次数
+     */
+    template<typename ...Args>
+    void asyncQuery(Args &&...args) {
+        asyncQuery_l(SqlConnection::queryString(std::forward<Args>(args)...));
+    }
+
+
+    /**
+     * 同步执行sql
+     * @tparam Args 可变参数类型列表
+     * @param arg 可变参数列表
+     * @return 影响行数
+     */
+
+    template<typename ...Args>
+    int64_t syncQuery(Args &&...arg) {
+        checkInited();
+        typename PoolType::ValuePtr mysql;
+        try {
+            //捕获执行异常
+            mysql = _pool->obtain();
+            return mysql->query(std::forward<Args>(arg)...);
+        } catch (std::exception &e) {
+            mysql.quit();
+            throw;
+        }
+    }
+
+
+    /**
+     * sql转义
+     * @param str
+     * @return
+     */
+    std::string escape(const std::string &str) {
+        checkInited();
+        return _pool->obtain()->escape(const_cast<std::string &>(str));
+    }
+
+private:
+    SqlPool() {
+        _threadPool = WorkThreadPool::Instance().getExecutor();
+        _timer = std::make_shared<Timer>(30, [this]() {
+            flushError();
+            return true;
+        }, nullptr);
+    }
+
+    /**
+     * 异步执行sql
+     * @param sql sql语句
+     * @param tryCnt 重试次数
+     */
+    void asyncQuery_l(const std::string &sql, int tryCnt = 3) {
+        auto lam = [this, sql, tryCnt]() {
+            int64_t rowID;
+            auto cnt = tryCnt - 1;
+            try {
+                syncQuery(rowID, sql);
+            } catch (std::exception &ex) {
+                if (cnt > 0) {
+                    //失败重试
+                    std::lock_guard<std::mutex> lk(_error_query_mutex);
+                    sqlQuery query(sql, cnt);
+                    _error_query.push_back(query);
+                } else {
+                    WarnL << "SqlPool::syncQuery failed: " << ex.what();
+                }
+            }
+        };
+        _threadPool->async(lam);
+    }
+
+    /**
+     * 定时重试失败的sql
+     */
+    void flushError() {
+        decltype(_error_query) query_copy;
+        {
+            std::lock_guard<std::mutex> lck(_error_query_mutex);
+            query_copy.swap(_error_query);
+        }
+        for (auto &query : query_copy) {
+            asyncQuery(query.sql_str, query.tryCnt);
+        }
+    }
+
+    /**
+     * 检查数据库连接池是否初始化
+     */
+    void checkInited() {
+        if (!_pool) {
+            throw SqlException("SqlPool::checkInited", "Mysql connection pool not initialized");
+        }
+    }
+
+private:
+    struct sqlQuery {
+        sqlQuery(const std::string &sql, int cnt) : sql_str(sql), tryCnt(cnt) {}
+
+        std::string sql_str;
+        int tryCnt = 0;
+    };
+
+private:
+    std::deque<sqlQuery> _error_query;
+    TaskExecutor::Ptr _threadPool;
+    std::mutex _error_query_mutex;
+    std::shared_ptr<PoolType> _pool;
+    Timer::Ptr _timer;
+};
+
+/**
+ * Sql语句生成器,通过占位符'?'的方式生成sql语句
+ */
+class SqlStream {
+public:
+    SqlStream(const char *sql) : _sql(sql) {}
+
+    ~SqlStream() {}
+
+    template<typename T>
+    SqlStream &operator<<(T &&data) {
+        auto pos = _sql.find('?', _startPos);
+        if (pos == std::string::npos) {
+            return *this;
+        }
+        _str_tmp.str("");
+        _str_tmp << std::forward<T>(data);
+        std::string str = SqlPool::Instance().escape(_str_tmp.str());
+        _startPos = pos + str.size();
+        _sql.replace(pos, 1, str);
+        return *this;
+    }
+
+    const std::string &operator<<(std::ostream &(*f)(std::ostream &)) const {
+        return _sql;
+    }
+
+    operator std::string() {
+        return _sql;
+    }
+
+private:
+    std::stringstream _str_tmp;
+    std::string _sql;
+    std::string::size_type _startPos = 0;
+};
+
+
+/**
+ * sql查询器
+ */
+class SqlWriter {
+public:
+    /**
+     * 构造函数
+     * @param sql 带'?'占位符的sql模板
+     * @param throwAble 是否抛异常
+     */
+    SqlWriter(const char *sql, bool throwAble = true) : _sqlstream(sql), _throwAble(throwAble) {}
+
+    ~SqlWriter() {}
+
+    /**
+     * 输入参数替换占位符'?'以便生成sql语句;可能抛异常
+     * @tparam T 参数类型
+     * @param data 参数
+     * @return 本身引用
+     */
+    template<typename T>
+    SqlWriter &operator<<(T &&data) {
+        try {
+            _sqlstream << std::forward<T>(data);
+        } catch (std::exception &ex) {
+            //在转义sql时可能抛异常
+            if (!_throwAble) {
+                WarnL << "Commit sql failed: " << ex.what();
+            } else {
+                throw;
+            }
+        }
+        return *this;
+    }
+
+    /**
+     * 异步执行sql,不会抛异常
+     * @param f std::endl
+     */
+    void operator<<(std::ostream &(*f)(std::ostream &)) {
+        //异步执行sql不会抛异常
+        SqlPool::Instance().asyncQuery((std::string) _sqlstream);
+    }
+
+    /**
+     * 同步执行sql,可能抛异常
+     * @tparam Row 数据行类型,可以是vector<string>/list<string>等支持 obj.emplace_back("value")操作的数据类型
+     * 			   也可以是map<string,string>/Json::Value 等支持 obj["key"] = "value"操作的数据类型
+     * @param ret 数据存放对象
+     * @return 影响行数
+     */
+    template<typename Row>
+    int64_t operator<<(std::vector<Row> &ret) {
+        try {
+            _affectedRows = SqlPool::Instance().syncQuery(_rowId, ret, (std::string) _sqlstream);
+        } catch (std::exception &ex) {
+            if (!_throwAble) {
+                WarnL << "SqlPool::syncQuery failed: " << ex.what();
+            } else {
+                throw;
+            }
+        }
+        return _affectedRows;
+    }
+
+    /**
+     * 在insert数据库时返回插入的rowid
+     * @return
+     */
+    int64_t getRowID() const {
+        return _rowId;
+    }
+
+    /**
+     * 返回影响数据库数据行数
+     * @return
+     */
+    int64_t getAffectedRows() const {
+        return _affectedRows;
+    }
+
+private:
+    SqlStream _sqlstream;
+    int64_t _rowId = -1;
+    int64_t _affectedRows = -1;
+    bool _throwAble = true;
+};
+
+} /* namespace toolkit */
+#endif /* SQL_SQLPOOL_H_ */

+ 147 - 0
3rdparty/ZLToolKit/include/Util/TimeTicker.h

@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef UTIL_TIMETICKER_H_
+#define UTIL_TIMETICKER_H_
+
+#include <cassert>
+#include "logger.h"
+
+namespace toolkit {
+
+class Ticker {
+public:
+    /**
+     * 此对象可以用于代码执行时间统计,以可以用于一般计时
+     * @param min_ms 开启码执行时间统计时,如果代码执行耗时超过该参数,则打印警告日志
+     * @param ctx 日志上下文捕获,用于捕获当前日志代码所在位置
+     * @param print_log 是否打印代码执行时间
+     */
+    Ticker(uint64_t min_ms = 0,
+           LogContextCapture ctx = LogContextCapture(Logger::Instance(), LWarn, __FILE__, "", __LINE__),
+           bool print_log = false) : _ctx(std::move(ctx)) {
+        if (!print_log) {
+            _ctx.clear();
+        }
+        _created = _begin = getCurrentMillisecond();
+        _min_ms = min_ms;
+    }
+
+    ~Ticker() {
+        uint64_t tm = createdTime();
+        if (tm > _min_ms) {
+            _ctx << "take time: " << tm << "ms" << ", thread may be overloaded";
+        } else {
+            _ctx.clear();
+        }
+    }
+
+    /**
+     * 获取上次resetTime后至今的时间,单位毫秒
+     */
+    uint64_t elapsedTime() const {
+        return getCurrentMillisecond() - _begin;
+    }
+
+    /**
+     * 获取从创建至今的时间,单位毫秒
+     */
+    uint64_t createdTime() const {
+        return getCurrentMillisecond() - _created;
+    }
+
+    /**
+     * 重置计时器
+     */
+    void resetTime() {
+        _begin = getCurrentMillisecond();
+    }
+
+private:
+    uint64_t _min_ms;
+    uint64_t _begin;
+    uint64_t _created;
+    LogContextCapture _ctx;
+};
+
+class SmoothTicker {
+public:
+    /**
+     * 此对象用于生成平滑的时间戳
+     * @param reset_ms 时间戳重置间隔,没间隔reset_ms毫秒, 生成的时间戳会同步一次系统时间戳
+     */
+    SmoothTicker(uint64_t reset_ms = 10000) {
+        _reset_ms = reset_ms;
+        _ticker.resetTime();
+    }
+
+    ~SmoothTicker() {}
+
+    /**
+     * 返回平滑的时间戳,防止由于网络抖动导致时间戳不平滑
+     */
+    uint64_t elapsedTime() {
+        auto now_time = _ticker.elapsedTime();
+        if (_first_time == 0) {
+            if (now_time < _last_time) {
+                auto last_time = _last_time - _time_inc;
+                double elapse_time = (now_time - last_time);
+                _time_inc += (elapse_time / ++_pkt_count) / 3;
+                auto ret_time = last_time + _time_inc;
+                _last_time = (uint64_t) ret_time;
+                return (uint64_t) ret_time;
+            }
+            _first_time = now_time;
+            _last_time = now_time;
+            _pkt_count = 0;
+            _time_inc = 0;
+            return now_time;
+        }
+
+        auto elapse_time = (now_time - _first_time);
+        _time_inc += elapse_time / ++_pkt_count;
+        auto ret_time = _first_time + _time_inc;
+        if (elapse_time > _reset_ms) {
+            _first_time = 0;
+        }
+        _last_time = (uint64_t) ret_time;
+        return (uint64_t) ret_time;
+    }
+
+    /**
+     * 时间戳重置为0开始
+     */
+    void resetTime() {
+        _first_time = 0;
+        _pkt_count = 0;
+        _ticker.resetTime();
+    }
+
+private:
+    double _time_inc = 0;
+    uint64_t _first_time = 0;
+    uint64_t _last_time = 0;
+    uint64_t _pkt_count = 0;
+    uint64_t _reset_ms;
+    Ticker _ticker;
+};
+
+#if !defined(NDEBUG)
+#define TimeTicker() Ticker __ticker(5,WarnL,true)
+#define TimeTicker1(tm) Ticker __ticker1(tm,WarnL,true)
+#define TimeTicker2(tm, log) Ticker __ticker2(tm,log,true)
+#else
+#define TimeTicker()
+#define TimeTicker1(tm)
+#define TimeTicker2(tm,log)
+#endif
+
+} /* namespace toolkit */
+#endif /* UTIL_TIMETICKER_H_ */

+ 71 - 0
3rdparty/ZLToolKit/include/Util/base64.h

@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
+#ifndef AVUTIL_BASE64_H
+#define AVUTIL_BASE64_H
+
+#include <cstdint>
+#include <string>
+
+/**
+ * Decode a base64-encoded string.
+ *
+ * @param out      buffer for decoded data
+ * @param in       null-terminated input string
+ * @param out_size size in bytes of the out buffer, must be at
+ *                 least 3/4 of the length of in
+ * @return         number of bytes written, or a negative value in case of
+ *                 invalid input
+ */
+int av_base64_decode(uint8_t *out, const char *in, int out_size);
+
+/**
+ * Encode data to base64 and null-terminate.
+ *
+ * @param out      buffer for encoded data
+ * @param out_size size in bytes of the output buffer, must be at
+ *                 least AV_BASE64_SIZE(in_size)
+ * @param in_size  size in bytes of the 'in' buffer
+ * @return         'out' or NULL in case of error
+ */
+char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size);
+
+/**
+ * Calculate the output size needed to base64-encode x bytes.
+ */
+#define AV_BASE64_SIZE(x)  (((x)+2) / 3 * 4 + 1)
+
+
+/**
+ * 编码base64
+ * @param txt 明文
+ * @return 密文
+ */
+std::string encodeBase64(const std::string &txt);
+
+/**
+ * 解码base64
+ * @param txt 密文
+ * @return 明文
+ */
+std::string decodeBase64(const std::string &txt);
+
+#endif /* AVUTIL_BASE64_H */

+ 55 - 0
3rdparty/ZLToolKit/include/Util/function_traits.h

@@ -0,0 +1,55 @@
+#ifndef SRC_UTIL_FUNCTION_TRAITS_H_
+#define SRC_UTIL_FUNCTION_TRAITS_H_
+
+#include <tuple>
+#include <functional>
+
+namespace toolkit {
+
+template<typename T>
+struct function_traits;
+
+//普通函数
+template<typename Ret, typename... Args>
+struct function_traits<Ret(Args...)>
+{
+public:
+    enum { arity = sizeof...(Args) };
+    typedef Ret function_type(Args...);
+    typedef Ret return_type;
+    using stl_function_type = std::function<function_type>;
+    typedef Ret(*pointer)(Args...);
+
+    template<size_t I>
+    struct args
+    {
+        static_assert(I < arity, "index is out of range, index must less than sizeof Args");
+        using type = typename std::tuple_element<I, std::tuple<Args...> >::type;
+    };
+};
+
+//函数指针
+template<typename Ret, typename... Args>
+struct function_traits<Ret(*)(Args...)> : function_traits<Ret(Args...)>{};
+
+//std::function
+template <typename Ret, typename... Args>
+struct function_traits<std::function<Ret(Args...)>> : function_traits<Ret(Args...)>{};
+
+//member function
+#define FUNCTION_TRAITS(...) \
+    template <typename ReturnType, typename ClassType, typename... Args>\
+    struct function_traits<ReturnType(ClassType::*)(Args...) __VA_ARGS__> : function_traits<ReturnType(Args...)>{}; \
+
+FUNCTION_TRAITS()
+FUNCTION_TRAITS(const)
+FUNCTION_TRAITS(volatile)
+FUNCTION_TRAITS(const volatile)
+
+//函数对象
+template<typename Callable>
+struct function_traits : function_traits<decltype(&Callable::operator())>{};
+
+} /* namespace toolkit */
+
+#endif /* SRC_UTIL_FUNCTION_TRAITS_H_ */

+ 15 - 0
3rdparty/ZLToolKit/include/Util/local_time.h

@@ -0,0 +1,15 @@
+//
+// Created by alex on 2022/5/29.
+//
+
+#ifndef UTIL_LOCALTIME_H
+#define UTIL_LOCALTIME_H
+#include <time.h>
+
+namespace toolkit {
+void no_locks_localtime(struct tm *tmp, time_t t);
+void local_time_init();
+int get_daylight_active();
+
+} // namespace toolkit
+#endif // UTIL_LOCALTIME_H

+ 442 - 0
3rdparty/ZLToolKit/include/Util/logger.h

@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef UTIL_LOGGER_H_
+#define UTIL_LOGGER_H_
+
+#include <cstdarg>
+#include <set>
+#include <map>
+#include <fstream>
+#include <thread>
+#include <memory>
+#include <mutex>
+#include "util.h"
+#include "List.h"
+#include "Thread/semaphore.h"
+
+namespace toolkit {
+
+class LogContext;
+class LogChannel;
+class LogWriter;
+class Logger;
+
+using LogContextPtr = std::shared_ptr<LogContext>;
+
+typedef enum {
+    LTrace = 0, LDebug, LInfo, LWarn, LError
+} LogLevel;
+
+Logger &getLogger();
+void setLogger(Logger *logger);
+
+/**
+* 日志类
+*/
+class Logger : public std::enable_shared_from_this<Logger>, public noncopyable {
+public:
+    friend class AsyncLogWriter;
+    using Ptr = std::shared_ptr<Logger>;
+
+    /**
+     * 获取日志单例
+     * @return
+     */
+    static Logger &Instance();
+
+    explicit Logger(const std::string &loggerName);
+    ~Logger();
+
+    /**
+     * 添加日志通道,非线程安全的
+     * @param channel log通道
+     */
+    void add(const std::shared_ptr<LogChannel> &channel);
+
+    /**
+     * 删除日志通道,非线程安全的
+     * @param name log通道名
+     */
+    void del(const std::string &name);
+
+    /**
+     * 获取日志通道,非线程安全的
+     * @param name log通道名
+     * @return 线程通道
+     */
+    std::shared_ptr<LogChannel> get(const std::string &name);
+
+    /**
+     * 设置写log器,非线程安全的
+     * @param writer 写log器
+     */
+    void setWriter(const std::shared_ptr<LogWriter> &writer);
+
+    /**
+     * 设置所有日志通道的log等级
+     * @param level log等级
+     */
+    void setLevel(LogLevel level);
+
+    /**
+     * 获取logger名
+     * @return logger名
+     */
+    const std::string &getName() const;
+
+    /**
+     * 写日志
+     * @param ctx 日志信息
+     */
+    void write(const LogContextPtr &ctx);
+
+private:
+    /**
+     * 写日志到各channel,仅供AsyncLogWriter调用
+     * @param ctx 日志信息
+     */
+    void writeChannels(const LogContextPtr &ctx);
+    void writeChannels_l(const LogContextPtr &ctx);
+
+private:
+    LogContextPtr _last_log;
+    std::string _logger_name;
+    std::shared_ptr<LogWriter> _writer;
+    std::map<std::string, std::shared_ptr<LogChannel> > _channels;
+};
+
+///////////////////LogContext///////////////////
+/**
+* 日志上下文
+*/
+class LogContext : public std::ostringstream {
+public:
+    //_file,_function改成string保存,目的是有些情况下,指针可能会失效
+    //比如说动态库中打印了一条日志,然后动态库卸载了,那么指向静态数据区的指针就会失效
+    LogContext() = default;
+    LogContext(LogLevel level, const char *file, const char *function, int line, const char *module_name, const char *flag);
+    ~LogContext() = default;
+
+    LogLevel _level;
+    int _line;
+    int _repeat = 0;
+    std::string _file;
+    std::string _function;
+    std::string _thread_name;
+    std::string _module_name;
+    std::string _flag;
+    struct timeval _tv;
+
+    const std::string &str();
+
+private:
+    bool _got_content = false;
+    std::string _content;
+};
+
+/**
+ * 日志上下文捕获器
+ */
+class LogContextCapture {
+public:
+    using Ptr = std::shared_ptr<LogContextCapture>;
+
+    LogContextCapture(Logger &logger, LogLevel level, const char *file, const char *function, int line, const char *flag = "");
+    LogContextCapture(const LogContextCapture &that);
+    ~LogContextCapture();
+
+    /**
+     * 输入std::endl(回车符)立即输出日志
+     * @param f std::endl(回车符)
+     * @return 自身引用
+     */
+    LogContextCapture &operator<<(std::ostream &(*f)(std::ostream &));
+
+    template<typename T>
+    LogContextCapture &operator<<(T &&data) {
+        if (!_ctx) {
+            return *this;
+        }
+        (*_ctx) << std::forward<T>(data);
+        return *this;
+    }
+
+    void clear();
+
+private:
+    LogContextPtr _ctx;
+    Logger &_logger;
+};
+
+
+///////////////////LogWriter///////////////////
+/**
+ * 写日志器
+ */
+class LogWriter : public noncopyable {
+public:
+    LogWriter() = default;
+    virtual ~LogWriter() = default;
+
+    virtual void write(const LogContextPtr &ctx, Logger &logger) = 0;
+};
+
+class AsyncLogWriter : public LogWriter {
+public:
+    AsyncLogWriter();
+    ~AsyncLogWriter();
+
+private:
+    void run();
+    void flushAll();
+    void write(const LogContextPtr &ctx, Logger &logger) override;
+
+private:
+    bool _exit_flag;
+    semaphore _sem;
+    std::mutex _mutex;
+    std::shared_ptr<std::thread> _thread;
+    List<std::pair<LogContextPtr, Logger *> > _pending;
+};
+
+///////////////////LogChannel///////////////////
+/**
+ * 日志通道
+ */
+class LogChannel : public noncopyable {
+public:
+    LogChannel(const std::string &name, LogLevel level = LTrace);
+    virtual ~LogChannel();
+
+    virtual void write(const Logger &logger, const LogContextPtr &ctx) = 0;
+    const std::string &name() const;
+    void setLevel(LogLevel level);
+    static std::string printTime(const timeval &tv);
+
+protected:
+    /**
+    * 打印日志至输出流
+    * @param ost 输出流
+    * @param enable_color 是否启用颜色
+    * @param enable_detail 是否打印细节(函数名、源码文件名、源码行)
+    */
+    virtual void format(const Logger &logger, std::ostream &ost, const LogContextPtr &ctx, bool enable_color = true, bool enable_detail = true);
+
+protected:
+    std::string _name;
+    LogLevel _level;
+};
+
+/**
+ * 输出日至到广播
+ */
+class EventChannel : public LogChannel {
+public:
+    //输出日志时的广播名
+    static const std::string kBroadcastLogEvent;
+    //日志广播参数类型和列表
+    #define BroadcastLogEventArgs const Logger &logger, const LogContextPtr &ctx
+
+    EventChannel(const std::string &name = "EventChannel", LogLevel level = LTrace);
+    ~EventChannel() override = default;
+
+    void write(const Logger &logger, const LogContextPtr &ctx) override;
+};
+
+/**
+ * 输出日志至终端,支持输出日志至android logcat
+ */
+class ConsoleChannel : public LogChannel {
+public:
+    ConsoleChannel(const std::string &name = "ConsoleChannel", LogLevel level = LTrace);
+    ~ConsoleChannel() override = default;
+
+    void write(const Logger &logger, const LogContextPtr &logContext) override;
+};
+
+/**
+ * 输出日志至文件
+ */
+class FileChannelBase : public LogChannel {
+public:
+    FileChannelBase(const std::string &name = "FileChannelBase", const std::string &path = exePath() + ".log", LogLevel level = LTrace);
+    ~FileChannelBase() override;
+
+    void write(const Logger &logger, const LogContextPtr &ctx) override;
+    bool setPath(const std::string &path);
+    const std::string &path() const;
+
+protected:
+    virtual bool open();
+    virtual void close();
+    virtual size_t size();
+
+protected:
+    std::string _path;
+    std::ofstream _fstream;
+};
+
+class Ticker;
+
+/**
+ * 自动清理的日志文件通道
+ * 默认最多保存30天的日志
+ */
+class FileChannel : public FileChannelBase {
+public:
+    FileChannel(const std::string &name = "FileChannel", const std::string &dir = exeDir() + "log/", LogLevel level = LTrace);
+    ~FileChannel() override = default;
+
+    /**
+     * 写日志时才会触发新建日志文件或者删除老的日志文件
+     * @param logger
+     * @param stream
+     */
+    void write(const Logger &logger, const LogContextPtr &ctx) override;
+
+    /**
+     * 设置日志最大保存天数
+     * @param max_day 天数
+     */
+    void setMaxDay(size_t max_day);
+
+    /**
+     * 设置日志切片文件最大大小
+     * @param max_size 单位MB
+     */
+    void setFileMaxSize(size_t max_size);
+
+    /**
+     * 设置日志切片文件最大个数
+     * @param max_count 个数
+     */
+    void setFileMaxCount(size_t max_count);
+
+private:
+    /**
+     * 删除日志切片文件,条件为超过最大保存天数与最大切片个数
+     */
+    void clean();
+
+    /**
+     * 检查当前日志切片文件大小,如果超过限制,则创建新的日志切片文件
+     */
+    void checkSize(time_t second);
+
+    /**
+     * 创建并切换到下一个日志切片文件
+     */
+    void changeFile(time_t second);
+
+private:
+    bool _can_write = false;
+    //默认最多保存30天的日志文件
+    size_t _log_max_day = 30;
+    //每个日志切片文件最大默认128MB
+    size_t _log_max_size = 128;
+    //最多默认保持30个日志切片文件
+    size_t _log_max_count = 30;
+    //当前日志切片文件索引
+    size_t _index = 0;
+    int64_t _last_day = -1;
+    time_t _last_check_time = 0;
+    std::string _dir;
+    std::set<std::string> _log_file_map;
+};
+
+#if defined(__MACH__) || ((defined(__linux) || defined(__linux__)) && !defined(ANDROID))
+class SysLogChannel : public LogChannel {
+public:
+    SysLogChannel(const std::string &name = "SysLogChannel", LogLevel level = LTrace);
+    ~SysLogChannel() override = default;
+
+    void write(const Logger &logger, const LogContextPtr &logContext) override;
+};
+
+#endif//#if defined(__MACH__) || ((defined(__linux) || defined(__linux__)) &&  !defined(ANDROID))
+
+class BaseLogFlagInterface {
+protected:
+    virtual ~BaseLogFlagInterface() {}
+    // 获得日志标记Flag
+    const char* getLogFlag(){
+        return _log_flag;
+    }
+    void setLogFlag(const char *flag) { _log_flag = flag; }
+private:
+    const char *_log_flag = "";
+};
+
+class LoggerWrapper {
+public:
+    template<typename First, typename ...ARGS>
+    static inline void printLogArray(Logger &logger, LogLevel level, const char *file, const char *function, int line, First &&first, ARGS &&...args) {
+        LogContextCapture log(logger, level, file, function, line);
+        log << std::forward<First>(first);
+        appendLog(log, std::forward<ARGS>(args)...);
+    }
+
+    static inline void printLogArray(Logger &logger, LogLevel level, const char *file, const char *function, int line) {
+        LogContextCapture log(logger, level, file, function, line);
+    }
+
+    template<typename Log, typename First, typename ...ARGS>
+    static inline void appendLog(Log &out, First &&first, ARGS &&...args) {
+        out << std::forward<First>(first);
+        appendLog(out, std::forward<ARGS>(args)...);
+    }
+
+    template<typename Log>
+    static inline void appendLog(Log &out) {}
+
+    //printf样式的日志打印
+    static void printLog(Logger &logger, int level, const char *file, const char *function, int line, const char *fmt, ...);
+    static void printLogV(Logger &logger, int level, const char *file, const char *function, int line, const char *fmt, va_list ap);
+};
+
+//可重置默认值
+extern Logger *g_defaultLogger;
+
+//用法: DebugL << 1 << "+" << 2 << '=' << 3;
+#define WriteL(level) ::toolkit::LogContextCapture(::toolkit::getLogger(), level, __FILE__, __FUNCTION__, __LINE__)
+#define TraceL WriteL(::toolkit::LTrace)
+#define DebugL WriteL(::toolkit::LDebug)
+#define InfoL WriteL(::toolkit::LInfo)
+#define WarnL WriteL(::toolkit::LWarn)
+#define ErrorL WriteL(::toolkit::LError)
+
+//只能在虚继承BaseLogFlagInterface的类中使用
+#define WriteF(level) ::toolkit::LogContextCapture(::toolkit::getLogger(), level, __FILE__, __FUNCTION__, __LINE__, getLogFlag())
+#define TraceF WriteF(::toolkit::LTrace)
+#define DebugF WriteF(::toolkit::LDebug)
+#define InfoF WriteF(::toolkit::LInfo)
+#define WarnF WriteF(::toolkit::LWarn)
+#define ErrorF WriteF(::toolkit::LError)
+
+//用法: PrintD("%d + %s = %c", 1 "2", 'c');
+#define PrintLog(level, ...) ::toolkit::LoggerWrapper::printLog(::toolkit::getLogger(), level, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define PrintT(...) PrintLog(::toolkit::LTrace, ##__VA_ARGS__)
+#define PrintD(...) PrintLog(::toolkit::LDebug, ##__VA_ARGS__)
+#define PrintI(...) PrintLog(::toolkit::LInfo, ##__VA_ARGS__)
+#define PrintW(...) PrintLog(::toolkit::LWarn, ##__VA_ARGS__)
+#define PrintE(...) PrintLog(::toolkit::LError, ##__VA_ARGS__)
+
+//用法: LogD(1, "+", "2", '=', 3);
+//用于模板实例化的原因,如果每次打印参数个数和类型不一致,可能会导致二进制代码膨胀
+#define LogL(level, ...) ::toolkit::LoggerWrapper::printLogArray(::toolkit::getLogger(), (LogLevel)level, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define LogT(...) LogL(::toolkit::LTrace, ##__VA_ARGS__)
+#define LogD(...) LogL(::toolkit::LDebug, ##__VA_ARGS__)
+#define LogI(...) LogL(::toolkit::LInfo, ##__VA_ARGS__)
+#define LogW(...) LogL(::toolkit::LWarn, ##__VA_ARGS__)
+#define LogE(...) LogL(::toolkit::LError, ##__VA_ARGS__)
+
+} /* namespace toolkit */
+#endif /* UTIL_LOGGER_H_ */

+ 186 - 0
3rdparty/ZLToolKit/include/Util/mini.h

@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015 r-lyeh (https://github.com/r-lyeh)
+ * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ * 
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ * 
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+#ifndef UTIL_MINI_H
+#define UTIL_MINI_H
+
+#include <cctype>
+#include <map>
+#include <string>
+#include <vector>
+#include <fstream>
+#include "util.h"
+
+namespace toolkit {
+
+template<typename key, typename variant>
+class mINI_basic : public std::map<key, variant> {
+    // Public API : existing map<> interface plus following methods
+public:
+    void parse(const std::string &text) {
+        // reset, split lines and parse
+        std::vector<std::string> lines = tokenize(text, "\n");
+        std::string symbol, tag;
+        for (auto &line : lines) {
+            // trim blanks
+            line = trim(line);
+            // split line into tokens and parse tokens
+            if (line.empty() || line.front() == ';' || line.front() == '#') {
+                continue;
+            }
+            if (line.size() >= 3 && line.front() == '[' && line.back() == ']') {
+                tag = trim(line.substr(1, line.size() - 2));
+            } else {
+                auto at = line.find('=');
+                symbol = trim(tag + "." + line.substr(0, at));
+                (*this)[symbol] = (at == std::string::npos ? std::string() : trim(line.substr(at + 1)));
+            }
+        }
+    }
+
+    void parseFile(const std::string &fileName = exePath() + ".ini") {
+        std::ifstream in(fileName, std::ios::in | std::ios::binary | std::ios::ate);
+        if (!in.good()) {
+            throw std::invalid_argument("Invalid ini file: " + fileName);
+        }
+        auto size = in.tellg();
+        in.seekg(0, std::ios::beg);
+        std::string buf;
+        buf.resize(size);
+        in.read((char *) buf.data(), size);
+        parse(buf);
+    }
+
+    std::string dump(const std::string &header = "; auto-generated by mINI class {",
+                     const std::string &footer = "; } ---") const {
+        std::string front(header + (header.empty() ? "" : "\r\n")), output, tag;
+        std::vector<std::string> kv;
+        for (auto &pr : *this) {
+            auto pos = pr.first.find('.');
+            if (pos == std::string::npos) {
+                kv = {"", pr.first};
+            } else {
+                kv = {pr.first.substr(0, pos), pr.first.substr(pos + 1)};
+            }
+            if (kv[0].empty()) {
+                front += kv[1] + "=" + pr.second + "\r\n";
+                continue;
+            }
+            if (tag != kv[0]) {
+                output += "\r\n[" + (tag = kv[0]) + "]\r\n";
+            }
+            output += kv[1] + "=" + pr.second + "\r\n";
+        }
+        return front + output + "\r\n" + footer + (footer.empty() ? "" : "\r\n");
+    }
+
+    void dumpFile(const std::string &fileName = exePath() + ".ini") {
+        std::ofstream out(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
+        auto dmp = dump();
+        out.write(dmp.data(), dmp.size());
+    }
+
+    static mINI_basic &Instance();
+
+private:
+    std::vector<std::string> tokenize(const std::string &self, const std::string &chars) const {
+        std::vector<std::string> tokens(1);
+        std::string map(256, '\0');
+        for (char ch : chars) {
+            map[(uint8_t) ch] = '\1';
+        }
+        for (char ch : self) {
+            if (!map.at((uint8_t) ch)) {
+                tokens.back().push_back(ch);
+            } else if (tokens.back().size()) {
+                tokens.push_back(std::string());
+            }
+        }
+        while (tokens.size() && tokens.back().empty()) {
+            tokens.pop_back();
+        }
+        return tokens;
+    }
+};
+
+//  handy variant class as key/values
+struct variant : public std::string {
+    template<typename T>
+    variant(const T &t) :
+            std::string(std::to_string(t)) {
+    }
+
+    template<size_t N>
+    variant(const char (&s)[N]) :
+            std::string(s, N) {
+    }
+
+    variant(const char *cstr) :
+            std::string(cstr) {
+    }
+
+    variant(const std::string &other = std::string()) :
+            std::string(other) {
+    }
+
+    template <typename T>
+    operator T() const {
+        return as<T>();
+    }
+
+    template<typename T>
+    bool operator==(const T &t) const {
+        return 0 == this->compare(variant(t));
+    }
+
+    bool operator==(const char *t) const {
+        return this->compare(t) == 0;
+    }
+
+    template <typename T>
+    typename std::enable_if<!std::is_class<T>::value, T>::type as() const {
+        return as_default<T>();
+    }
+
+    template <typename T>
+    typename std::enable_if<std::is_class<T>::value, T>::type as() const {
+        return T((const std::string &)*this);
+    }
+
+private:
+    template <typename T>
+    T as_default() const {
+        T t;
+        std::stringstream ss;
+        return ss << *this && ss >> t ? t : T();
+    }
+};
+
+template <>
+bool variant::as<bool>() const;
+
+template <>
+uint8_t variant::as<uint8_t>() const;
+
+using mINI = mINI_basic<std::string, variant>;
+
+}  // namespace toolkit
+#endif //UTIL_MINI_H
+

+ 51 - 0
3rdparty/ZLToolKit/include/Util/onceToken.h

@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+*
+* This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+*
+* Use of this source code is governed by MIT license that can be found in the
+* LICENSE file in the root of the source tree. All contributing project authors
+* may be found in the AUTHORS file in the root of the source tree.
+*/
+
+#ifndef UTIL_ONCETOKEN_H_
+#define UTIL_ONCETOKEN_H_
+
+#include <functional>
+#include <type_traits>
+
+namespace toolkit {
+
+class onceToken {
+public:
+    using task = std::function<void(void)>;
+
+    template<typename FUNC>
+    onceToken(const FUNC &onConstructed, task onDestructed = nullptr) {
+        onConstructed();
+        _onDestructed = std::move(onDestructed);
+    }
+
+    onceToken(std::nullptr_t, task onDestructed = nullptr) {
+        _onDestructed = std::move(onDestructed);
+    }
+
+    ~onceToken() {
+        if (_onDestructed) {
+            _onDestructed();
+        }
+    }
+
+private:
+    onceToken() = delete;
+    onceToken(const onceToken &) = delete;
+    onceToken(onceToken &&) = delete;
+    onceToken &operator=(const onceToken &) = delete;
+    onceToken &operator=(onceToken &&) = delete;
+
+private:
+    task _onDestructed;
+};
+
+} /* namespace toolkit */
+#endif /* UTIL_ONCETOKEN_H_ */

+ 10 - 0
3rdparty/ZLToolKit/include/Util/strptime_win.h

@@ -0,0 +1,10 @@
+#ifndef ZLMEDIAKIT_STRPTIME_WIN_H
+#define ZLMEDIAKIT_STRPTIME_WIN_H
+
+#include <ctime>
+#ifdef _WIN32
+//window上自己实现strptime函数,linux已经提供strptime
+//strptime函数windows平台上实现
+char * strptime(const char *buf, const char *fmt, struct tm *tm);
+#endif
+#endif //ZLMEDIAKIT_STRPTIME_WIN_H

+ 384 - 0
3rdparty/ZLToolKit/include/Util/util.h

@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
+ *
+ * Use of this source code is governed by MIT license that can be found in the
+ * LICENSE file in the root of the source tree. All contributing project authors
+ * may be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef UTIL_UTIL_H_
+#define UTIL_UTIL_H_
+
+#include <ctime>
+#include <cstdio>
+#include <cstring>
+#include <memory>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <atomic>
+#include <unordered_map>
+#include "function_traits.h"
+#if defined(_WIN32)
+#undef FD_SETSIZE
+//修改默认64为1024路
+#define FD_SETSIZE 1024
+#include <winsock2.h>
+#pragma comment (lib,"WS2_32")
+#else
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <cstddef>
+#endif // defined(_WIN32)
+
+#if defined(__APPLE__)
+#include "TargetConditionals.h"
+#if TARGET_IPHONE_SIMULATOR
+#define OS_IPHONE
+#elif TARGET_OS_IPHONE
+#define OS_IPHONE
+#endif
+#endif //__APPLE__
+
+#define INSTANCE_IMP(class_name, ...) \
+class_name &class_name::Instance() { \
+    static std::shared_ptr<class_name> s_instance(new class_name(__VA_ARGS__)); \
+    static class_name &s_instance_ref = *s_instance; \
+    return s_instance_ref; \
+}
+
+namespace toolkit {
+
+#define StrPrinter ::toolkit::_StrPrinter()
+class _StrPrinter : public std::string {
+public:
+    _StrPrinter() {}
+
+    template<typename T>
+    _StrPrinter& operator <<(T && data) {
+        _stream << std::forward<T>(data);
+        this->std::string::operator=(_stream.str());
+        return *this;
+    }
+
+    std::string operator <<(std::ostream&(*f)(std::ostream&)) const {
+        return *this;
+    }
+
+private:
+    std::stringstream _stream;
+};
+
+//禁止拷贝基类
+class noncopyable {
+protected:
+    noncopyable() {}
+    ~noncopyable() {}
+private:
+    //禁止拷贝
+    noncopyable(const noncopyable &that) = delete;
+    noncopyable(noncopyable &&that) = delete;
+    noncopyable &operator=(const noncopyable &that) = delete;
+    noncopyable &operator=(noncopyable &&that) = delete;
+};
+
+//可以保存任意的对象
+class Any{
+public:
+    using Ptr = std::shared_ptr<Any>;
+
+    Any() = default;
+    ~Any() = default;
+
+    template <typename C,typename ...ArgsType>
+    void set(ArgsType &&...args){
+        _data.reset(new C(std::forward<ArgsType>(args)...),[](void *ptr){
+            delete (C*) ptr;
+        });
+    }
+    template <typename C>
+    C& get(){
+        if(!_data){
+            throw std::invalid_argument("Any is empty");
+        }
+        C *ptr = (C *)_data.get();
+        return *ptr;
+    }
+
+    operator bool() {
+        return _data.operator bool ();
+    }
+    bool empty(){
+        return !bool();
+    }
+private:
+    std::shared_ptr<void> _data;
+};
+
+//用于保存一些外加属性
+class AnyStorage : public std::unordered_map<std::string,Any>{
+public:
+    AnyStorage() = default;
+    ~AnyStorage() = default;
+    using Ptr = std::shared_ptr<AnyStorage>;
+};
+
+#ifndef CLASS_FUNC_TRAITS
+#define CLASS_FUNC_TRAITS(func_name) \
+template<typename T, typename ... ARGS> \
+constexpr bool Has_##func_name(decltype(&T::on##func_name) /*unused*/) { \
+    using RET = typename function_traits<decltype(&T::on##func_name)>::return_type; \
+    using FuncType = RET (T::*)(ARGS...);   \
+    return std::is_same<decltype(&T::on ## func_name), FuncType>::value; \
+} \
+\
+template<class T, typename ... ARGS> \
+constexpr bool Has_##func_name(...) { \
+    return false; \
+} \
+\
+template<typename T, typename ... ARGS> \
+static void InvokeFunc_##func_name(typename std::enable_if<!Has_##func_name<T, ARGS...>(nullptr), T>::type &obj, ARGS ...args) {} \
+\
+template<typename T, typename ... ARGS>\
+static typename function_traits<decltype(&T::on##func_name)>::return_type InvokeFunc_##func_name(typename std::enable_if<Has_##func_name<T, ARGS...>(nullptr), T>::type &obj, ARGS ...args) {\
+    return obj.on##func_name(std::forward<ARGS>(args)...);\
+}
+#endif //CLASS_FUNC_TRAITS
+
+#ifndef CLASS_FUNC_INVOKE
+#define CLASS_FUNC_INVOKE(T, obj, func_name, ...) InvokeFunc_##func_name<T>(obj, ##__VA_ARGS__)
+#endif //CLASS_FUNC_INVOKE
+
+CLASS_FUNC_TRAITS(Destory)
+CLASS_FUNC_TRAITS(Create)
+
+/**
+ * 对象安全的构建和析构,构建后执行onCreate函数,析构前执行onDestory函数
+ * 在函数onCreate和onDestory中可以执行构造或析构中不能调用的方法,比如说shared_from_this或者虚函数
+ * @warning onDestory函数确保参数个数为0;否则会被忽略调用
+ */
+class Creator {
+public:
+    /**
+     * 创建对象,用空参数执行onCreate和onDestory函数
+     * @param args 对象构造函数参数列表
+     * @return args对象的智能指针
+     */
+    template<typename C, typename ...ArgsType>
+    static std::shared_ptr<C> create(ArgsType &&...args) {
+        std::shared_ptr<C> ret(new C(std::forward<ArgsType>(args)...), [](C *ptr) {
+            try {
+                CLASS_FUNC_INVOKE(C, *ptr, Destory);
+            } catch (std::exception &ex){
+                onDestoryException(typeid(C), ex);
+            }
+            delete ptr;
+        });
+        CLASS_FUNC_INVOKE(C, *ret, Create);
+        return ret;
+    }
+
+    /**
+     * 创建对象,用指定参数执行onCreate函数
+     * @param args 对象onCreate函数参数列表
+     * @warning args参数类型和个数必须与onCreate函数类型匹配(不可忽略默认参数),否则会由于模板匹配失败导致忽略调用
+     * @return args对象的智能指针
+     */
+    template<typename C, typename ...ArgsType>
+    static std::shared_ptr<C> create2(ArgsType &&...args) {
+        std::shared_ptr<C> ret(new C(), [](C *ptr) {
+            try {
+                CLASS_FUNC_INVOKE(C, *ptr, Destory);
+            } catch (std::exception &ex){
+                onDestoryException(typeid(C), ex);
+            }
+            delete ptr;
+        });
+        CLASS_FUNC_INVOKE(C, *ret, Create, std::forward<ArgsType>(args)...);
+        return ret;
+    }
+
+private:
+    static void onDestoryException(const std::type_info &info, const std::exception &ex);
+
+private:
+    Creator() = default;
+    ~Creator() = default;
+};
+
+template <class C>
+class ObjectStatistic{
+public:
+    ObjectStatistic(){
+        ++getCounter();
+    }
+
+    ~ObjectStatistic(){
+        --getCounter();
+    }
+
+    static size_t count(){
+        return getCounter().load();
+    }
+
+private:
+    static std::atomic<size_t> & getCounter();
+};
+
+#define StatisticImp(Type)  \
+    template<> \
+    std::atomic<size_t>& ObjectStatistic<Type>::getCounter(){ \
+        static std::atomic<size_t> instance(0); \
+        return instance; \
+    }
+
+std::string makeRandStr(int sz, bool printable = true);
+std::string hexdump(const void *buf, size_t len);
+std::string hexmem(const void* buf, size_t len);
+std::string exePath(bool isExe = true);
+std::string exeDir(bool isExe = true);
+std::string exeName(bool isExe = true);
+
+std::vector<std::string> split(const std::string& s, const char *delim);
+//去除前后的空格、回车符、制表符...
+std::string& trim(std::string &s,const std::string &chars=" \r\n\t");
+std::string trim(std::string &&s,const std::string &chars=" \r\n\t");
+// string转小写
+std::string &strToLower(std::string &str);
+std::string strToLower(std::string &&str);
+// string转大写
+std::string &strToUpper(std::string &str);
+std::string strToUpper(std::string &&str);
+//替换子字符串
+void replace(std::string &str, const std::string &old_str, const std::string &new_str, std::string::size_type b_pos = 0) ;
+//判断是否为ip
+bool isIP(const char *str);
+//字符串是否以xx开头
+bool start_with(const std::string &str, const std::string &substr);
+//字符串是否以xx结尾
+bool end_with(const std::string &str, const std::string &substr);
+//拼接格式字符串
+template<typename... Args>
+std::string str_format(const std::string &format, Args... args) {
+#if __cplusplus > 202002L
+    return std::format(format, args...);
+#else
+    // Calculate the buffer size
+    auto size_buf = snprintf(nullptr, 0, format.c_str(), args ...) + 1;
+    // Allocate the buffer
+#if __cplusplus >= 201703L
+    // C++17
+    auto buf = std::make_unique<char[]>(size_buf);
+#else
+    // C++11
+    std:: unique_ptr<char[]> buf(new(std::nothrow) char[size_buf]);
+#endif
+    // Check if the allocation is successful
+    if (buf == nullptr) {
+        return {};
+    }
+    // Fill the buffer with formatted string
+    auto result = snprintf(buf.get(), size_buf, format.c_str(), args ...);
+    // Return the formatted string
+    return std::string(buf.get(), buf.get() + result);
+#endif
+}
+
+#ifndef bzero
+#define bzero(ptr,size)  memset((ptr),0,(size));
+#endif //bzero
+
+#if defined(ANDROID)
+template <typename T>
+std::string to_string(T value){
+    std::ostringstream os ;
+    os <<  std::forward<T>(value);
+    return os.str() ;
+}
+#endif//ANDROID
+
+#if defined(_WIN32)
+int gettimeofday(struct timeval *tp, void *tzp);
+void usleep(int micro_seconds);
+void sleep(int second);
+int vasprintf(char **strp, const char *fmt, va_list ap);
+int asprintf(char **strp, const char *fmt, ...);
+const char *strcasestr(const char *big, const char *little);
+
+#if !defined(strcasecmp)
+    #define strcasecmp _stricmp
+#endif
+
+#ifndef ssize_t
+    #ifdef _WIN64
+        #define ssize_t int64_t
+    #else
+        #define ssize_t int32_t
+    #endif
+#endif
+#endif //WIN32
+
+/**
+ * 获取时间差, 返回值单位为秒
+ */
+long getGMTOff();
+
+/**
+ * 获取1970年至今的毫秒数
+ * @param system_time 是否为系统时间(系统时间可以回退),否则为程序启动时间(不可回退)
+ */
+uint64_t getCurrentMillisecond(bool system_time = false);
+
+/**
+ * 获取1970年至今的微秒数
+ * @param system_time 是否为系统时间(系统时间可以回退),否则为程序启动时间(不可回退)
+ */
+uint64_t getCurrentMicrosecond(bool system_time = false);
+
+/**
+ * 获取时间字符串
+ * @param fmt 时间格式,譬如%Y-%m-%d %H:%M:%S
+ * @return 时间字符串
+ */
+std::string getTimeStr(const char *fmt,time_t time = 0);
+
+/**
+ * 根据unix时间戳获取本地时间
+ * @param sec unix时间戳
+ * @return tm结构体
+ */
+struct tm getLocalTime(time_t sec);
+
+/**
+ * 设置线程名
+ */
+void setThreadName(const char *name);
+
+/**
+ * 获取线程名
+ */
+std::string getThreadName();
+
+/**
+ * 设置当前线程cpu亲和性
+ * @param i cpu索引,如果为-1,那么取消cpu亲和性
+ * @return 是否成功,目前只支持linux
+ */
+bool setThreadAffinity(int i);
+
+/**
+ * 根据typeid(class).name()获取类名
+ */
+std::string demangle(const char *mangled);
+
+/**
+ * 获取环境变量内容,以'$'开头
+ */
+std::string getEnv(const std::string &key);
+
+}  // namespace toolkit
+#endif /* UTIL_UTIL_H_ */

+ 524 - 0
3rdparty/ZLToolKit/include/Util/uv_errno.h

@@ -0,0 +1,524 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+*  Copyright (c) 2016-2019 xiongziliang <771730766@qq.com>
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to
+* deal in the Software without restriction, including without limitation the
+* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+* sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+* IN THE SOFTWARE.
+*/
+
+#ifndef UV_ERRNO_H_
+#define UV_ERRNO_H_
+
+#include <cerrno>
+
+#define UV__EOF     (-4095)
+#define UV__UNKNOWN (-4094)
+
+#define UV__EAI_ADDRFAMILY  (-3000)
+#define UV__EAI_AGAIN       (-3001)
+#define UV__EAI_BADFLAGS    (-3002)
+#define UV__EAI_CANCELED    (-3003)
+#define UV__EAI_FAIL        (-3004)
+#define UV__EAI_FAMILY      (-3005)
+#define UV__EAI_MEMORY      (-3006)
+#define UV__EAI_NODATA      (-3007)
+#define UV__EAI_NONAME      (-3008)
+#define UV__EAI_OVERFLOW    (-3009)
+#define UV__EAI_SERVICE     (-3010)
+#define UV__EAI_SOCKTYPE    (-3011)
+#define UV__EAI_BADHINTS    (-3013)
+#define UV__EAI_PROTOCOL    (-3014)
+
+/* Only map to the system errno on non-Windows platforms. It's apparently
+* a fairly common practice for Windows programmers to redefine errno codes.
+*/
+#if defined(E2BIG) && !defined(_WIN32)
+# define UV__E2BIG (-E2BIG)
+#else
+# define UV__E2BIG (-4093)
+#endif
+
+#if defined(EACCES) && !defined(_WIN32)
+# define UV__EACCES (-EACCES)
+#else
+# define UV__EACCES (-4092)
+#endif
+
+#if defined(EADDRINUSE) && !defined(_WIN32)
+# define UV__EADDRINUSE (-EADDRINUSE)
+#else
+# define UV__EADDRINUSE (-4091)
+#endif
+
+#if defined(EADDRNOTAVAIL) && !defined(_WIN32)
+# define UV__EADDRNOTAVAIL (-EADDRNOTAVAIL)
+#else
+# define UV__EADDRNOTAVAIL (-4090)
+#endif
+
+#if defined(EAFNOSUPPORT) && !defined(_WIN32)
+# define UV__EAFNOSUPPORT (-EAFNOSUPPORT)
+#else
+# define UV__EAFNOSUPPORT (-4089)
+#endif
+
+#if defined(EAGAIN) && !defined(_WIN32)
+# define UV__EAGAIN (-EAGAIN)
+#else
+# define UV__EAGAIN (-4088)
+#endif
+
+#if defined(EALREADY) && !defined(_WIN32)
+# define UV__EALREADY (-EALREADY)
+#else
+# define UV__EALREADY (-4084)
+#endif
+
+#if defined(EBADF) && !defined(_WIN32)
+# define UV__EBADF (-EBADF)
+#else
+# define UV__EBADF (-4083)
+#endif
+
+#if defined(EBUSY) && !defined(_WIN32)
+# define UV__EBUSY (-EBUSY)
+#else
+# define UV__EBUSY (-4082)
+#endif
+
+#if defined(ECANCELED) && !defined(_WIN32)
+# define UV__ECANCELED (-ECANCELED)
+#else
+# define UV__ECANCELED (-4081)
+#endif
+
+#if defined(ECHARSET) && !defined(_WIN32)
+# define UV__ECHARSET (-ECHARSET)
+#else
+# define UV__ECHARSET (-4080)
+#endif
+
+#if defined(ECONNABORTED) && !defined(_WIN32)
+# define UV__ECONNABORTED (-ECONNABORTED)
+#else
+# define UV__ECONNABORTED (-4079)
+#endif
+
+#if defined(ECONNREFUSED) && !defined(_WIN32)
+# define UV__ECONNREFUSED (-ECONNREFUSED)
+#else
+# define UV__ECONNREFUSED (-4078)
+#endif
+
+#if defined(ECONNRESET) && !defined(_WIN32)
+# define UV__ECONNRESET (-ECONNRESET)
+#else
+# define UV__ECONNRESET (-4077)
+#endif
+
+#if defined(EDESTADDRREQ) && !defined(_WIN32)
+# define UV__EDESTADDRREQ (-EDESTADDRREQ)
+#else
+# define UV__EDESTADDRREQ (-4076)
+#endif
+
+#if defined(EEXIST) && !defined(_WIN32)
+# define UV__EEXIST (-EEXIST)
+#else
+# define UV__EEXIST (-4075)
+#endif
+
+#if defined(EFAULT) && !defined(_WIN32)
+# define UV__EFAULT (-EFAULT)
+#else
+# define UV__EFAULT (-4074)
+#endif
+
+#if defined(EHOSTUNREACH) && !defined(_WIN32)
+# define UV__EHOSTUNREACH (-EHOSTUNREACH)
+#else
+# define UV__EHOSTUNREACH (-4073)
+#endif
+
+#if defined(EINTR) && !defined(_WIN32)
+# define UV__EINTR (-EINTR)
+#else
+# define UV__EINTR (-4072)
+#endif
+
+#if defined(EINVAL) && !defined(_WIN32)
+# define UV__EINVAL (-EINVAL)
+#else
+# define UV__EINVAL (-4071)
+#endif
+
+#if defined(EIO) && !defined(_WIN32)
+# define UV__EIO (-EIO)
+#else
+# define UV__EIO (-4070)
+#endif
+
+#if defined(EISCONN) && !defined(_WIN32)
+# define UV__EISCONN (-EISCONN)
+#else
+# define UV__EISCONN (-4069)
+#endif
+
+#if defined(EISDIR) && !defined(_WIN32)
+# define UV__EISDIR (-EISDIR)
+#else
+# define UV__EISDIR (-4068)
+#endif
+
+#if defined(ELOOP) && !defined(_WIN32)
+# define UV__ELOOP (-ELOOP)
+#else
+# define UV__ELOOP (-4067)
+#endif
+
+#if defined(EMFILE) && !defined(_WIN32)
+# define UV__EMFILE (-EMFILE)
+#else
+# define UV__EMFILE (-4066)
+#endif
+
+#if defined(EMSGSIZE) && !defined(_WIN32)
+# define UV__EMSGSIZE (-EMSGSIZE)
+#else
+# define UV__EMSGSIZE (-4065)
+#endif
+
+#if defined(ENAMETOOLONG) && !defined(_WIN32)
+# define UV__ENAMETOOLONG (-ENAMETOOLONG)
+#else
+# define UV__ENAMETOOLONG (-4064)
+#endif
+
+#if defined(ENETDOWN) && !defined(_WIN32)
+# define UV__ENETDOWN (-ENETDOWN)
+#else
+# define UV__ENETDOWN (-4063)
+#endif
+
+#if defined(ENETUNREACH) && !defined(_WIN32)
+# define UV__ENETUNREACH (-ENETUNREACH)
+#else
+# define UV__ENETUNREACH (-4062)
+#endif
+
+#if defined(ENFILE) && !defined(_WIN32)
+# define UV__ENFILE (-ENFILE)
+#else
+# define UV__ENFILE (-4061)
+#endif
+
+#if defined(ENOBUFS) && !defined(_WIN32)
+# define UV__ENOBUFS (-ENOBUFS)
+#else
+# define UV__ENOBUFS (-4060)
+#endif
+
+#if defined(ENODEV) && !defined(_WIN32)
+# define UV__ENODEV (-ENODEV)
+#else
+# define UV__ENODEV (-4059)
+#endif
+
+#if defined(ENOENT) && !defined(_WIN32)
+# define UV__ENOENT (-ENOENT)
+#else
+# define UV__ENOENT (-4058)
+#endif
+
+#if defined(ENOMEM) && !defined(_WIN32)
+# define UV__ENOMEM (-ENOMEM)
+#else
+# define UV__ENOMEM (-4057)
+#endif
+
+#if defined(ENONET) && !defined(_WIN32)
+# define UV__ENONET (-ENONET)
+#else
+# define UV__ENONET (-4056)
+#endif
+
+#if defined(ENOSPC) && !defined(_WIN32)
+# define UV__ENOSPC (-ENOSPC)
+#else
+# define UV__ENOSPC (-4055)
+#endif
+
+#if defined(ENOSYS) && !defined(_WIN32)
+# define UV__ENOSYS (-ENOSYS)
+#else
+# define UV__ENOSYS (-4054)
+#endif
+
+#if defined(ENOTCONN) && !defined(_WIN32)
+# define UV__ENOTCONN (-ENOTCONN)
+#else
+# define UV__ENOTCONN (-4053)
+#endif
+
+#if defined(ENOTDIR) && !defined(_WIN32)
+# define UV__ENOTDIR (-ENOTDIR)
+#else
+# define UV__ENOTDIR (-4052)
+#endif
+
+#if defined(ENOTEMPTY) && !defined(_WIN32)
+# define UV__ENOTEMPTY (-ENOTEMPTY)
+#else
+# define UV__ENOTEMPTY (-4051)
+#endif
+
+#if defined(ENOTSOCK) && !defined(_WIN32)
+# define UV__ENOTSOCK (-ENOTSOCK)
+#else
+# define UV__ENOTSOCK (-4050)
+#endif
+
+#if defined(ENOTSUP) && !defined(_WIN32)
+# define UV__ENOTSUP (-ENOTSUP)
+#else
+# define UV__ENOTSUP (-4049)
+#endif
+
+#if defined(EPERM) && !defined(_WIN32)
+# define UV__EPERM (-EPERM)
+#else
+# define UV__EPERM (-4048)
+#endif
+
+#if defined(EPIPE) && !defined(_WIN32)
+# define UV__EPIPE (-EPIPE)
+#else
+# define UV__EPIPE (-4047)
+#endif
+
+#if defined(EPROTO) && !defined(_WIN32)
+# define UV__EPROTO (-EPROTO)
+#else
+# define UV__EPROTO (-4046)
+#endif
+
+#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
+# define UV__EPROTONOSUPPORT (-EPROTONOSUPPORT)
+#else
+# define UV__EPROTONOSUPPORT (-4045)
+#endif
+
+#if defined(EPROTOTYPE) && !defined(_WIN32)
+# define UV__EPROTOTYPE (-EPROTOTYPE)
+#else
+# define UV__EPROTOTYPE (-4044)
+#endif
+
+#if defined(EROFS) && !defined(_WIN32)
+# define UV__EROFS (-EROFS)
+#else
+# define UV__EROFS (-4043)
+#endif
+
+#if defined(ESHUTDOWN) && !defined(_WIN32)
+# define UV__ESHUTDOWN (-ESHUTDOWN)
+#else
+# define UV__ESHUTDOWN (-4042)
+#endif
+
+#if defined(ESPIPE) && !defined(_WIN32)
+# define UV__ESPIPE (-ESPIPE)
+#else
+# define UV__ESPIPE (-4041)
+#endif
+
+#if defined(ESRCH) && !defined(_WIN32)
+# define UV__ESRCH (-ESRCH)
+#else
+# define UV__ESRCH (-4040)
+#endif
+
+#if defined(ETIMEDOUT) && !defined(_WIN32)
+# define UV__ETIMEDOUT (-ETIMEDOUT)
+#else
+# define UV__ETIMEDOUT (-4039)
+#endif
+
+#if defined(ETXTBSY) && !defined(_WIN32)
+# define UV__ETXTBSY (-ETXTBSY)
+#else
+# define UV__ETXTBSY (-4038)
+#endif
+
+#if defined(EXDEV) && !defined(_WIN32)
+# define UV__EXDEV (-EXDEV)
+#else
+# define UV__EXDEV (-4037)
+#endif
+
+#if defined(EFBIG) && !defined(_WIN32)
+# define UV__EFBIG (-EFBIG)
+#else
+# define UV__EFBIG (-4036)
+#endif
+
+#if defined(ENOPROTOOPT) && !defined(_WIN32)
+# define UV__ENOPROTOOPT (-ENOPROTOOPT)
+#else
+# define UV__ENOPROTOOPT (-4035)
+#endif
+
+#if defined(ERANGE) && !defined(_WIN32)
+# define UV__ERANGE (-ERANGE)
+#else
+# define UV__ERANGE (-4034)
+#endif
+
+#if defined(ENXIO) && !defined(_WIN32)
+# define UV__ENXIO (-ENXIO)
+#else
+# define UV__ENXIO (-4033)
+#endif
+
+#if defined(EMLINK) && !defined(_WIN32)
+# define UV__EMLINK (-EMLINK)
+#else
+# define UV__EMLINK (-4032)
+#endif
+
+/* EHOSTDOWN is not visible on BSD-like systems when _POSIX_C_SOURCE is
+* defined. Fortunately, its value is always 64 so it's possible albeit
+* icky to hard-code it.
+*/
+#if defined(EHOSTDOWN) && !defined(_WIN32)
+# define UV__EHOSTDOWN (-EHOSTDOWN)
+#elif defined(__APPLE__) || \
+      defined(__DragonFly__) || \
+      defined(__FreeBSD__) || \
+      defined(__FreeBSD_kernel__) || \
+      defined(__NetBSD__) || \
+      defined(__OpenBSD__)
+# define UV__EHOSTDOWN (-64)
+#else
+# define UV__EHOSTDOWN (-4031)
+#endif
+
+#if defined(EREMOTEIO) && !defined(_WIN32)
+# define UV__EREMOTEIO (-EREMOTEIO)
+#else
+# define UV__EREMOTEIO (-4030)
+#endif
+
+
+#define UV_ERRNO_MAP(XX)                                                      \
+  XX(E2BIG, "argument list too long")                                         \
+  XX(EACCES, "permission denied")                                             \
+  XX(EADDRINUSE, "address already in use")                                    \
+  XX(EADDRNOTAVAIL, "address not available")                                  \
+  XX(EAFNOSUPPORT, "address family not supported")                            \
+  XX(EAGAIN, "resource temporarily unavailable")                              \
+  XX(EAI_ADDRFAMILY, "address family not supported")                          \
+  XX(EAI_AGAIN, "temporary failure")                                          \
+  XX(EAI_BADFLAGS, "bad ai_flags value")                                      \
+  XX(EAI_BADHINTS, "invalid value for hints")                                 \
+  XX(EAI_CANCELED, "request canceled")                                        \
+  XX(EAI_FAIL, "permanent failure")                                           \
+  XX(EAI_FAMILY, "ai_family not supported")                                   \
+  XX(EAI_MEMORY, "out of memory")                                             \
+  XX(EAI_NODATA, "no address")                                                \
+  XX(EAI_NONAME, "unknown node or service")                                   \
+  XX(EAI_OVERFLOW, "argument buffer overflow")                                \
+  XX(EAI_PROTOCOL, "resolved protocol is unknown")                            \
+  XX(EAI_SERVICE, "service not available for socket type")                    \
+  XX(EAI_SOCKTYPE, "socket type not supported")                               \
+  XX(EALREADY, "connection already in progress")                              \
+  XX(EBADF, "bad file descriptor")                                            \
+  XX(EBUSY, "resource busy or locked")                                        \
+  XX(ECANCELED, "operation canceled")                                         \
+  XX(ECHARSET, "invalid Unicode character")                                   \
+  XX(ECONNABORTED, "software caused connection abort")                        \
+  XX(ECONNREFUSED, "connection refused")                                      \
+  XX(ECONNRESET, "connection reset by peer")                                  \
+  XX(EDESTADDRREQ, "destination address required")                            \
+  XX(EEXIST, "file already exists")                                           \
+  XX(EFAULT, "bad address in system call argument")                           \
+  XX(EFBIG, "file too large")                                                 \
+  XX(EHOSTUNREACH, "host is unreachable")                                     \
+  XX(EINTR, "interrupted system call")                                        \
+  XX(EINVAL, "invalid argument")                                              \
+  XX(EIO, "i/o error")                                                        \
+  XX(EISCONN, "socket is already connected")                                  \
+  XX(EISDIR, "illegal operation on a directory")                              \
+  XX(ELOOP, "too many symbolic links encountered")                            \
+  XX(EMFILE, "too many open files")                                           \
+  XX(EMSGSIZE, "message too long")                                            \
+  XX(ENAMETOOLONG, "name too long")                                           \
+  XX(ENETDOWN, "network is down")                                             \
+  XX(ENETUNREACH, "network is unreachable")                                   \
+  XX(ENFILE, "file table overflow")                                           \
+  XX(ENOBUFS, "no buffer space available")                                    \
+  XX(ENODEV, "no such device")                                                \
+  XX(ENOENT, "no such file or directory")                                     \
+  XX(ENOMEM, "not enough memory")                                             \
+  XX(ENONET, "machine is not on the network")                                 \
+  XX(ENOPROTOOPT, "protocol not available")                                   \
+  XX(ENOSPC, "no space left on device")                                       \
+  XX(ENOSYS, "function not implemented")                                      \
+  XX(ENOTCONN, "socket is not connected")                                     \
+  XX(ENOTDIR, "not a directory")                                              \
+  XX(ENOTEMPTY, "directory not empty")                                        \
+  XX(ENOTSOCK, "socket operation on non-socket")                              \
+  XX(ENOTSUP, "operation not supported on socket")                            \
+  XX(EPERM, "operation not permitted")                                        \
+  XX(EPIPE, "broken pipe")                                                    \
+  XX(EPROTO, "protocol error")                                                \
+  XX(EPROTONOSUPPORT, "protocol not supported")                               \
+  XX(EPROTOTYPE, "protocol wrong type for socket")                            \
+  XX(ERANGE, "result too large")                                              \
+  XX(EROFS, "read-only file system")                                          \
+  XX(ESHUTDOWN, "cannot send after transport endpoint shutdown")              \
+  XX(ESPIPE, "invalid seek")                                                  \
+  XX(ESRCH, "no such process")                                                \
+  XX(ETIMEDOUT, "connection timed out")                                       \
+  XX(ETXTBSY, "text file is busy")                                            \
+  XX(EXDEV, "cross-device link not permitted")                                \
+  XX(UNKNOWN, "unknown error")                                                \
+  XX(EOF, "end of file")                                                      \
+  XX(ENXIO, "no such device or address")                                      \
+  XX(EMLINK, "too many links")                                                \
+  XX(EHOSTDOWN, "host is down")                                               \
+  XX(EREMOTEIO, "remote I/O error")                                           \
+
+namespace toolkit {
+
+typedef enum {
+#define XX(code, _) UV_ ## code = UV__ ## code,
+    UV_ERRNO_MAP(XX)
+#undef XX
+    UV_ERRNO_MAX = UV__EOF - 1
+} uv_errno_t;
+
+const char *uv_err_name(int err);
+const char *uv_strerror(int err);
+int uv_translate_posix_error(int err);
+//netErr参数在windows平台下才有效
+int get_uv_error(bool netErr = true);
+//netErr参数在windows平台下才有效
+const char *get_uv_errmsg(bool netErr = true);
+
+}//namespace toolkit
+
+#endif /* UV_ERRNO_H_ */

BIN
3rdparty/ZLToolKit/lib/libZLToolKit.a


BIN
3rdparty/ZLToolKit/lib/libZLToolKit.so


+ 9 - 0
cmake/FindZLToolKit.cmake

@@ -0,0 +1,9 @@
+set(ZLTOOLKIT_DIR ${PROJECT_SOURCE_DIR}/3rdparty/ZLToolKit)
+
+set(ZLTOOLKIT_INCLUDE_DIRS ${ZLTOOLKIT_DIR}/include)
+
+set(ZLTOOLKIT_LINK_DIRS ${ZLTOOLKIT_DIR}/lib)
+
+set(ZLTOOLKIT_LIBRARIES
+        ZLToolkit;
+)

BIN
lib/libgsd_core.so


BIN
lib/libgsd_modules.so


BIN
lib/libgsd_plugins.so


+ 5 - 0
modules/CMakeLists.txt

@@ -31,6 +31,11 @@ set(3RDPARTY_LIBS "")
 
 set(CMAKE_MODULE_PATH ${GSD_ROOT_DIR}/cmake)
 
+# ---[ ZLToolKit
+find_package(ZLToolKit REQUIRED)
+link_directories(${ZLTOOLKIT_LINK_DIRS})
+include_directories(${ZLTOOLKIT_INCLUDE_DIRS})
+
 # ---[ rapidjson
 include_directories(${GSD_ROOT_DIR}/3rdparty/)
 include_directories(${GSD_ROOT_DIR}/3rdparty/httplib)

+ 16 - 0
plugins/CMakeLists.txt

@@ -28,6 +28,11 @@ set(3RDPARTY_LIBS "")
 
 set(CMAKE_MODULE_PATH ${GSD_ROOT_DIR}/cmake)
 
+# ---[ ZLToolKit
+find_package(ZLToolKit REQUIRED)
+link_directories(${ZLTOOLKIT_LINK_DIRS})
+include_directories(${ZLTOOLKIT_INCLUDE_DIRS})
+
 # ---[ rapidjson
 include_directories(${GSD_ROOT_DIR}/3rdparty/)
 include_directories(${GSD_ROOT_DIR}/3rdparty/httplib/)
@@ -71,6 +76,17 @@ if(build_AuditPlugin)
   install(DIRECTORY AuditPlugin/include/ DESTINATION include)
 endif()
 
+set(ENABLE_MYSQL ON CACHE BOOL "enable mysql")
+#查找mysql是否安装
+find_package(MYSQL QUIET)
+if(MYSQL_FOUND AND ENABLE_MYSQL)
+    message(STATUS "找到mysqlclient库:\"${MYSQL_INCLUDE_DIR}\",ENABLE_MYSQL宏已打开")
+    include_directories(${MYSQL_INCLUDE_DIR})
+    include_directories(${MYSQL_INCLUDE_DIR}/mysql)
+    add_definitions(-DENABLE_MYSQL)
+    list(APPEND 3RDPARTY_LIBS ${MYSQL_LIBRARIES})
+endif()
+
 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 
 foreach(module ${module_list})

+ 17 - 0
source/CMakeLists.txt

@@ -35,8 +35,25 @@ if(build_kafka)
   endif()
 endif()
 
+set(ENABLE_MYSQL ON CACHE BOOL "enable mysql")
+#查找mysql是否安装
+find_package(MYSQL QUIET)
+if(MYSQL_FOUND AND ENABLE_MYSQL)
+    message(STATUS "找到mysqlclient库:\"${MYSQL_INCLUDE_DIR}\",ENABLE_MYSQL宏已打开")
+    include_directories(${MYSQL_INCLUDE_DIR})
+    include_directories(${MYSQL_INCLUDE_DIR}/mysql)
+    add_definitions(-DENABLE_MYSQL)
+    list(APPEND 3RDPARTY_LIBS ${MYSQL_LIBRARIES})
+endif()
+
+
 set(CMAKE_MODULE_PATH ${CNSTREAM_ROOT_DIR}/cmake/sanitizers ${CNSTREAM_ROOT_DIR}/cmake)
 
+# ---[ ZLToolKit
+find_package(ZLToolKit REQUIRED)
+link_directories(${ZLTOOLKIT_LINK_DIRS})
+include_directories(${ZLTOOLKIT_INCLUDE_DIRS})
+
 # ---[ rapidjson
 include_directories(${CNSTREAM_ROOT_DIR}/3rdparty/)