基于 LwIP 协议栈实现 tun2sys-socket,网络游戏加速器(一类)

了解本文则需要参考本人提供的以下的文献内容:

1、​​​​​​轻松修改 LwIP-TCP/IP-Stack-2.13-trunk 网络协议栈令其 tcp_listen accept 任何地址的 TCP_PCB 连接。_liulilittle的博客-CSDN博客

2、LwIP C TCP/IP Stack 正确的TCP连接数据发送姿态_liulilittle的博客-CSDN博客

大概在国内网上关于 “网络游戏加速器” 相关的文章,上面两项根本文提供的实现有一定相关性,可能就我写的内容比较多,相对详细,这个东西有点敏感是一方面,另外也是会损坏 “既得利益群体” 的利润,这个东西目前来说由于各种原因把,文献/知识非常少,懂这套东西的人,都懂,不懂这套东西的人,那是真的很难懂。 

今天这篇文章就大致介绍一下实现的原理,如题目所示是基于 LwIP 协议栈的,而不基于 LwIP 协议栈,自主实现的 tun2sys-socket 的半开源,虚拟网络处理工程框架,目前应该只有我们提供的 VEthernet .NET 4.0 Framework x86 一个选项,寻求可稳定工作的 tun2socks by C# 例程;可以检索本人博客或到 github 上面搜索 VEthernet。

基于 LwIP 协议栈实现 tun2sys-socket,技术关键点只需要实现以下两个东西

1、LwIP 协议栈监听的TCP_LISTEN,允许接受来自任何IP地址 TCP_SYN(连接建立)

2、本地环路转发到 sys-socket 本地代理服务器

本文代码从我们的一个强大工程代码之中,来源为 ***-netstack 子网络堆栈实现,不过修改了一下命名空间 ,它实现了上面提到的两个东西,但本地环路代理服务器,需要各位童靴们自行实现。

使用代码可能的法务问题?不存在的,只要说明使用了我们的代码就可以,除非那个公司不要脸剽窃,不过也就仅此而已,我们几乎也不会用这个东西,只是兼容模式下可能会开启它(LwIP 子网络堆栈)因为TCP/IP吞吐速度是个硬伤,网络吞吐速度跑不到 500Mbps 以上就真的挺废的,当然这是因为只有一个线程核在跑 LwIP 协议堆栈。

LwIP 想要实现非常大的网络I/O带宽吞吐量,并非是不可以,但需要实现多进程处理架构(MPA)即一个主控进程从 tun 网卡里面收发IP帧报文,子进程来跑 LwIP 协议堆栈,一个子进程负责多少TCP_PCB process,主控进程负责调度那些 IP+TCP报文分发到那个子进程上面处理,但它无法解决单点吞吐速度不高的问题,走我们的专用主堆栈可以跑几百兆单连接,而通过基于 LwIP 协议实现的 netstack 子网络堆栈只有一百多兆单连接吞吐速度表现力。

补充:如果你不需要中转到本地环路代理服务器上面,那么就 netstack 内的系统套接字就直接连接目标服务器就可以,本实现走本地环路代理服务器这块主要是为了让IO跑的更高,毕竟就一个线程核在处理还跑协议栈,负担太重吞吐性能是个不小得问题。

打开 netstack(LwIP协议堆栈初始化及网络栈就绪)

bool netstack::open(const std::shared_ptr& tap);

本地环路代理服务器 accept 到 sys-socket 的时候,通过 “key” 查找当前的 sys-socket 在 lwip/tun 上面想要的IP/PORT链路信息。

key = 被接受的 sys-socket 的 peername 的端口号,getpeername(connect_sockfd, ...)

bool netstack::link(int key, uint32_t& srcAddr, int& srcPort, uint32_t& dstAddr, int& dstPort);

关闭 netstack 及释放持有的托管与非托管资源

void netstack::close()

1#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

namespace My {
    namespace Net {
        namespace LwIP { 
            struct netstack_tcp_socket {
                typedef struct {
                    std::shared_ptr                       p;
                    int                                         sz;
                } buffer_chunk;

                typedef struct {
                    buffer_chunk                                buf;
                    std::function        cb;
                } send_context;
                typedef std::shared_ptr           send_context_ptr;

                typedef enum {
                    ENETSTACK_TCP_SENT_LWIP,
                    ENETSTACK_TCP_SENT_SOCK,
                    ENETSTACK_TCP_SENT_MAX
                } ENETSTACK_TCP_SENT_BUFS;

                std::list                     sents[ENETSTACK_TCP_SENT_MAX];
                std::shared_ptr   socket;
                bool                                            open;

                struct tcp_pcb* pcb;
                u16_t                                           pnat;
                ip_addr_t                                       local_ip;
                u16_t                                           local_port;
                ip_addr_t                                       remote_ip;
                u16_t                                           remote_port;
                u8_t                                            buf[1400];
            };

            typedef std::shared_ptr        NetstackSocket;
            typedef std::unordered_map     Port2Socket;
            typedef std::unordered_map   Ptr2Socket;
            typedef std::recursive_mutex                        NetstackMutex;
            typedef std::lock_guard              NetstackMutexScope;

            static boost::asio::io_context                      context_;
            static boost::asio::deadline_timer                  timeout_(context_);
            static std::shared_ptr     tap_;
            static struct netif*                                netif_ = NULL;
            static struct tcp_pcb*                              pcb_   = NULL;
            static Port2Socket                                  n2ss_;
            static Ptr2Socket                                   p2ss_;
            static NetstackMutex                                lockobj_;

            inline static bool
            netstack_tcp_linksocket(int port, const std::shared_ptr& socket) {
                if (port <= My::Net::IPEndPoint::MinPort || port > My::Net::IPEndPoint::MaxPort) {
                    return false;
                }
                if (!socket) {
                    return false;
                }
                else {
                    NetstackMutexScope scope_(lockobj_);
                    std::pair r_ = n2ss_.insert(std::make_pair(port, socket));
                    if (!r_.second) {
                        return false;
                    }
                }
                socket->pnat = port;
                return true;
            }

            inline static void*
            netstack_tcp_linksocket(struct tcp_pcb* pcb, const std::shared_ptr& socket) {
                if (!pcb || !socket) {
                    return NULL;
                }

                NetstackMutexScope scope_(lockobj_);
                std::pair r_ = p2ss_.insert(std::make_pair(pcb, socket));
                return r_.second ? pcb : NULL;
            }

            inline static std::shared_ptr
            netstack_tcp_getsocket(int port) {
                if (port <= My::Net::IPEndPoint::MinPort || port > My::Net::IPEndPoint::MaxPort) {
                    return NULL;
                }

                NetstackMutexScope scope_(lockobj_);
                Port2Socket::iterator tail_ = n2ss_.find(port);
                Port2Socket::iterator endl_ = n2ss_.end();
                return tail_ != endl_ ? tail_->second : NULL;
            }

            inline static std::shared_ptr
            netstack_tcp_getsocket(void* p) {
                if (!p) {
                    return NULL;
                }

                NetstackMutexScope scope_(lockobj_);
                Ptr2Socket::iterator tail_ = p2ss_.find(p);
                Ptr2Socket::iterator endl_ = p2ss_.end();
                return tail_ != endl_ ? tail_->second : NULL;
            }

            inline static std::shared_ptr
            netstack_tcp_releasesocket(int port) {
                if (port <= My::Net::IPEndPoint::MinPort || port > My::Net::IPEndPoint::MaxPort) {
                    return NULL;
                }

                std::shared_ptr socket;
                do {
                    NetstackMutexScope scope_(lockobj_);
                    Port2Socket::iterator tail_ = n2ss_.find(port);
                    Port2Socket::iterator endl_ = n2ss_.end();
                    if (tail_ != endl_) {
                        socket = std::move(tail_->second);
                        n2ss_.erase(tail_);
                    }
                } while (0);
                return std::move(socket);
            }

            inline static std::shared_ptr
            netstack_tcp_releasesocket(void* p) {
                if (!p) {
                    return NULL;
                }

                std::shared_ptr socket;
                do {
                    NetstackMutexScope scope_(lockobj_);
                    Ptr2Socket::iterator tail_ = p2ss_.find(p);
                    Ptr2Socket::iterator endl_ = p2ss_.end();
                    if (tail_ != endl_) {
                        socket = std::move(tail_->second);
                        p2ss_.erase(tail_);
                    }
                } while (0);
                return std::move(socket);
            }

            inline static err_t
            netstack_tcp_closesocket(struct tcp_pcb* pcb);

            inline static bool
            netstack_tcp_closesocket(const std::shared_ptr& socket_);

            inline static err_t
            netstack_tcp_send(struct tcp_pcb* pcb, void* data, u16_t len, const std::function& callback) {
                if (!pcb) {
                    return ERR_ARG;
                }

                std::shared_ptr socket_ = netstack_tcp_getsocket(pcb->callback_arg);
                if (!socket_) {
                    return ERR_ABRT;
                }

                if (!data || !len) {
                    return ERR_ARG;
                }

                static auto tcp_enqueue_ = 
                [](netstack_tcp_socket* socket_, struct tcp_pcb* pcb, void* data, u16_t len, const std::function& callback) {
                    std::shared_ptr chunk_ = My::make_shared_alloc(len);
                    memcpy(chunk_.get(), data, len);

                    netstack_tcp_socket::send_context_ptr context_ = 
                        My::make_shared_object();
                    context_->buf.p = std::move(chunk_);
                    context_->buf.sz = len;
                    context_->cb = callback;
                    socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_LWIP].push_back(std::move(context_));
                    return ERR_OK;
                };
                if (!socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_LWIP].empty()) {
                    return tcp_enqueue_(socket_.get(), pcb, data, len, callback);
                }

                err_t err = tcp_write(pcb, data, len, TCP_WRITE_FLAG_COPY);
                if (err == ERR_OK) {
                    tcp_output(pcb);
                    if (callback) {
                        callback(pcb);
                    }
                    return err;
                }
                else if (err == ERR_MEM) {
                    return tcp_enqueue_(socket_.get(), pcb, data, len, callback);
                }
                return err;
            }

            inline static void
            netstack_tcp_arg(struct tcp_pcb* pcb, void* arg) {
                if (pcb) {
                    tcp_arg(pcb, arg);
                }
            }
            
            inline static void
            netstack_tcp_event(struct tcp_pcb* pcb, tcp_recv_fn recv, tcp_sent_fn sent, tcp_err_fn errf, tcp_poll_fn poll) {
                if (pcb) {
                    tcp_recv(pcb, recv ? recv : tcp_recv_null);
                    tcp_sent(pcb, sent);
                    tcp_err(pcb, errf);
                    tcp_poll(pcb, poll, poll ? 8 : 0);
                }
            }

            inline static bool
            netstack_tcp_closesocket(const std::shared_ptr& socket_) {
                if (!socket_) {
                    return false;
                }

                My::Net::Socket::Closesocket(std::move(socket_->socket));
                for (int i = netstack_tcp_socket::ENETSTACK_TCP_SENT_LWIP; i < netstack_tcp_socket::ENETSTACK_TCP_SENT_MAX; i++) {
                    socket_->sents[i].clear();
                }

                struct tcp_pcb* pcb = socket_->pcb;
                if (pcb) {
                    socket_->pcb = NULL;
                    netstack_tcp_releasesocket(pcb->callback_arg);
                }

                netstack_tcp_closesocket(pcb);
                netstack_tcp_releasesocket(socket_->pnat);
                return true;
            }

            inline static err_t
            netstack_tcp_closesocket(struct tcp_pcb* pcb) {
                if (!pcb) {
                    return ERR_ARG;
                }

                std::shared_ptr socket_ = netstack_tcp_releasesocket(pcb->callback_arg);
                netstack_tcp_arg(pcb, NULL);
                netstack_tcp_event(pcb, NULL, NULL, NULL, NULL);

                if (socket_) {
                    socket_->pcb = NULL;
                    netstack_tcp_closesocket(socket_);
                }
                return tcp_close(pcb);
            }

            inline static struct pbuf*
            netstack_pbuf_alloc(u16_t len) {
                if (!len) {
                    return NULL;
                }
                return pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
            }

            inline static void
            netstack_pbuf_free(struct pbuf* buf) {
                if (buf) {
                    pbuf_free(buf);
                }
            }

            inline static bool
            netstack_tunnel_send(const std::shared_ptr& socket_, void* data, int len, bool unsafe_);

            inline static err_t
            netstack_tcp_dorecv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) {
                LWIP_UNUSED_ARG(arg);

                if (p) {
                    std::shared_ptr socket = netstack_tcp_getsocket(pcb->callback_arg);
                    if (!socket) {
                        tcp_abort(pcb);
                        return ERR_ABRT;
                    }

                    for (struct pbuf* q = p; p; p = p->next) {
                        tcp_recved(pcb, q->len);
                        netstack_tunnel_send(socket, p->payload, p->len, true);
                    }
                    netstack_pbuf_free(p);
                }
                else if (err == ERR_OK) {
                    return netstack_tcp_closesocket(pcb);
                }
                return ERR_OK;
            }

            inline static err_t
            netstack_tcp_dosent(void* arg, struct tcp_pcb* pcb, u16_t len) {
                LWIP_UNUSED_ARG(arg);

                std::shared_ptr socket_ = netstack_tcp_getsocket(pcb->callback_arg);
                if (socket_) {
                    std::list& sents = socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_LWIP];
                    while (!sents.empty()) { // tcp_sndbuf
                        err_t err_;
                        do {
                            netstack_tcp_socket::send_context_ptr context_ = sents.front();
                            err_ = tcp_write(pcb, 
                                context_->buf.p.get(), 
                                context_->buf.sz, TCP_WRITE_FLAG_COPY);
                            if (err_ == ERR_OK) {
                                tcp_output(pcb);
                                if (context_->cb) {
                                    context_->cb(pcb);
                                }
                                sents.pop_front();
                            }
                        } while (0);
                        if (err_) {
                            if (err_ == ERR_MEM) {
                                break;
                            }
                            netstack_tcp_closesocket(socket_);
                            return ERR_ABRT;
                        }
                    }
                    return ERR_OK;
                }
                else {
                    tcp_abort(pcb);
                    return ERR_ABRT;
                }
            }

            inline static void
            netstack_tcp_doerrf(void* arg, err_t err) {
                std::shared_ptr socket_ = netstack_tcp_getsocket(arg);
                if (socket_) {
                    netstack_tcp_closesocket(socket_);
                }
            }

            inline static err_t
            netstack_tcp_dopoll(void* arg, struct tcp_pcb* pcb) {
                std::shared_ptr socket = netstack_tcp_getsocket(pcb->callback_arg);
                if (socket) {
                    std::shared_ptr p = socket->socket;
                    if (p) {
                        if (p->is_open()) {
                            return ERR_OK;
                        }
                    }
                    return ERR_ABRT;
                }
                else {
                    tcp_abort(pcb);
                    return ERR_ABRT;
                }
            }

            inline static bool
            netstack_tunnel_open(const std::shared_ptr& socket_);

            inline static err_t
            netstack_tcp_doaccept(void* arg, struct tcp_pcb* pcb, err_t err) {
                LWIP_UNUSED_ARG(arg);
                LWIP_UNUSED_ARG(err);

                std::shared_ptr socket_ = std::make_shared();
                socket_->pnat        = 0;
                socket_->pcb         = pcb;
                socket_->open        = false;
                socket_->socket      = std::make_shared(context_);
                socket_->local_ip    = pcb->remote_ip;
                socket_->local_port  = pcb->remote_port;
                socket_->remote_ip   = pcb->local_ip;
                socket_->remote_port = pcb->local_port;

                void* callback_arg = netstack_tcp_linksocket(pcb, socket_);
                netstack_tcp_arg(pcb, callback_arg);

                if (callback_arg && netstack_tunnel_open(socket_)) {
                    netstack_tcp_event(pcb, netstack_tcp_dorecv, netstack_tcp_dosent, netstack_tcp_doerrf, netstack_tcp_dopoll);
                    return ERR_OK;
                }
                else {
                    netstack_tcp_closesocket(socket_);
                    return ERR_ABRT;
                }
            }

            inline static bool
            netstack_tunnel_send(const std::shared_ptr& socket_, void* data, int len, bool unsafe_) {
                if (!socket_ || !data || len < 1) {
                    return false;
                }

                std::shared_ptr& socket = socket_->socket;
                if (!socket || !socket->is_open()) {
                    return false;
                }

                if (!socket_->open) {
                    std::shared_ptr chunk_ = My::make_shared_alloc(len);
                    memcpy(chunk_.get(), data, len);

                    netstack_tcp_socket::send_context_ptr context_ = 
                        My::make_shared_object();
                    context_->buf.p = std::move(chunk_);
                    context_->buf.sz = len;

                    socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_SOCK].push_back(std::move(context_));
                    return true;
                }

                std::shared_ptr chunk_;
                if (unsafe_) {
                    chunk_ = My::make_shared_alloc(len);
                    memcpy(chunk_.get(), data, len);
                }
                else {
                    chunk_ = *(std::shared_ptr*)data;
                }

                std::shared_ptr socket__ = socket_;
                boost::asio::async_write(*socket, boost::asio::buffer(chunk_.get(), len), [socket__, chunk_](const boost::system::error_code& ec, size_t sz) {
                    if (ec) {
                        netstack_tcp_closesocket(socket__);
                    }
                });
                return true;
            }

            inline static bool
            netstack_tunnel_dorecv(const std::shared_ptr& socket_) {
                if (!socket_) {
                    return false;
                }

                std::shared_ptr& socket = socket_->socket;
                if (!socket || !socket->is_open()) {
                    return false;
                }

                std::shared_ptr socket__ = socket_;
                socket->async_read_some(boost::asio::buffer(socket_->buf, sizeof(socket_->buf)), [socket__](const boost::system::error_code& ec, size_t sz) {
                    int by = std::max(-1, ec ? -1 : sz);
                    if (by < 1) {
                        netstack_tcp_closesocket(socket__);
                    }
                    else {
                        netstack_tcp_send(socket__->pcb, socket__->buf, by, [socket__](struct tcp_pcb*) {
                            netstack_tunnel_dorecv(socket__);
                        });
                    }
                });
                return true;
            }

            inline static bool
            nestack_tunnel_post_all_unsent(const std::shared_ptr& socket_) {
                if (!socket_) {
                    return false;
                }

                std::list& sents = socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_SOCK];
                while (!sents.empty()) {
                    netstack_tcp_socket::send_context_ptr context_ = sents.front();
                    sents.pop_front();
                    netstack_tunnel_send(socket_, std::addressof(context_->buf.p), context_->buf.sz, false);
                }
                return true;
            }

            inline static bool
            netstack_tunnel_open(const std::shared_ptr& socket_) {
                if (!socket_) {
                    return false;
                }

                std::shared_ptr taptap = tap_;
                if (!taptap) {
                    return false;
                }

                std::shared_ptr& socket = socket_->socket;
                if (!socket || socket->is_open()) {
                    return false;
                }

                boost::system::error_code ec;
                try {
                    if (IP_IS_V4_VAL(socket_->local_ip)) {
                        socket->open(boost::asio::ip::tcp::v4(), ec);
                    }
                    else if (IP_IS_V6_VAL(socket_->local_ip)) {
                        socket->open(boost::asio::ip::tcp::v6(), ec);
                    }
                    else {
                        return false;
                    }

                    if (ec) {
                        return false;
                    }
                }
                catch (std::exception&) {
                    return false;
                }
                
                boost::asio::ip::tcp::endpoint localEP = netstack::localhost();
                if (!localEP.port()) {
                    return false;
                }

                // 绑定到本地主机网卡上面
                int pnat = 0;
                try {
                    boost::asio::ip::tcp::endpoint bindEP(localEP.address(), 0);
                    socket->bind(bindEP, ec);
                    if (ec) {
                        return false;
                    }

                    bindEP = socket->local_endpoint(ec);
                    if (ec) {
                        return false;
                    }
                    pnat = bindEP.port();
                }
                catch (std::exception&) {
                    return false;
                }

                // 建立套接字链路
                if (!netstack_tcp_linksocket(pnat, socket_)) {
                    return false;
                }

                // 获取文件描述符
                int handle = My::Net::Socket::GetHandle(*socket.get());

                // 禁用 Nagle
                My::Net::Socket::SetNoDelay(handle, taptap->IsNoDelay());

                // 禁止 SIGPIPE
                My::Net::Socket::SetSignalPipeline(handle, false);

                // 允许 IPv4 Fragment
                My::Net::Socket::SetDontFragment(handle, false);

                // 设置 TypeOfService
                My::Net::Socket::SetTypeOfService(handle);

                // 链接本地虚拟网络交换机
                std::shared_ptr socket__ = socket_;
                socket->async_connect(localEP, [socket__](const boost::system::error_code& ec) {
                    if (ec) {
                        netstack_tcp_closesocket(socket__);
                        return;
                    }

                    if (socket__->open) {
                        netstack_tcp_closesocket(socket__);
                        return;
                    }
                    else {
                        socket__->open = true;
                    }

                    bool ok = netstack_tunnel_dorecv(socket__) && nestack_tunnel_post_all_unsent(socket__);
                    if (!ok) {
                        netstack_tcp_closesocket(socket__);
                        return;
                    }
                });
                return true;
            }

            inline static err_t
            netstack_ip_output(struct pbuf* p) {
                if (!p || !p->len) {
                    return ERR_BUF;
                }
                
                std::shared_ptr packet = My::make_shared_alloc(p->len);
                pbuf_copy_partial(p, packet.get(), p->len, 0);

                return netstack::output(packet, p->len);
            }

            inline static err_t
            netstack_ip_output_v4(struct netif* netif, struct pbuf* p, const ip4_addr_t* ipaddr) {
                LWIP_UNUSED_ARG(netif);
                LWIP_UNUSED_ARG(ipaddr);

                return netstack_ip_output(p);
            }

            inline static err_t
            netstack_ip_output_v6(struct netif* netif, struct pbuf* p, const ip6_addr_t* ipaddr) {
                LWIP_UNUSED_ARG(netif);
                LWIP_UNUSED_ARG(ipaddr);

                return netstack_ip_output(p);
            }

            inline static bool 
            netstack_tcp_init() {
                struct tcp_pcb* pcb = tcp_new();

                tcp_bind(pcb, IP_ADDR_ANY, 0);
                pcb = tcp_listen(pcb);
                tcp_arg(pcb, NULL);
                tcp_accept(pcb, netstack_tcp_doaccept);

                pcb_ = pcb;
                return pcb_ != NULL;
            }

            inline static void 
            netstack_check_timeouts() {
                timeout_.expires_from_now(boost::posix_time::milliseconds(250));
                timeout_.async_wait([] (const boost::system::error_code& ec) {
                    sys_check_timeouts();
                    netstack_check_timeouts();
                });
            }

            inline static int
            nestack_loopback() {
                class std_thread_id {
                public:
                    std::thread::native_handle_type	_M_thread;
                };
                std::thread loopback_thread([] {
                    boost::asio::io_context::work work_(context_);
                    boost::system::error_code ec_;
                    SetThreadPriorityToMaxLevel();
                    context_.restart();
                    netstack_check_timeouts();
                    context_.run(ec_);
                });
                std::thread::id tid = loopback_thread.get_id();
                std_thread_id& pid = *(std_thread_id*)&tid;
                loopback_thread.detach();
                return pid._M_thread;
            }

            bool
            netstack::input(const void* packet, int size) {
                if (!packet || size < 1 || !netif_) {
                    return false;
                }

                std::shared_ptr taptap = tap_;
                if (!taptap) {
                    return false;
                }

                struct pbuf* data = netstack_pbuf_alloc(size);
                if (!data) {
                    return false;
                }

                memcpy(data->payload, packet, size);
                context_.post([data, size] {
                    struct netif* netif = netif_;
                    if (!netif) {
                        pbuf_free(data);
                        return;
                    }

                    err_t err = netif->input(data, netif);
                    if (err != ERR_OK) {
                        pbuf_free(data);
                        return;
                    }
                });

                My::Net::NetworkStatistics& statistics = taptap->_statistics;
                struct ip_hdr* iphdr = (struct ip_hdr*)packet;

                int iphdr_hlen = IPH_HL_BYTES(iphdr);
                int ip_proto = IPH_PROTO(iphdr);
                switch (ip_proto) {
                case IP_PROTO_TCP:
                    {
                        My::Net::NetworkStatistics::TcpStatistics& tcp_stat = statistics.Tcp;
                        tcp_stat.OutgoingUnicastPacket++;
                        tcp_stat.OutgoingTrafficSize += std::max(0, size - iphdr_hlen);
                        break;
                    }
                case IP_PROTO_UDP:
                    {
                        My::Net::NetworkStatistics::UdpStatistics& udp_stat = statistics.Udp;
                        udp_stat.OutgoingUnicastPacket++;
                        udp_stat.OutgoingTrafficSize += std::max(0, size - iphdr_hlen);
                        break;
                    }
                case IP_PROTO_ICMP:
                    {
                        My::Net::NetworkStatistics::Statistics& icmp_stat = statistics.Icmp;
                        icmp_stat.OutgoingUnicastPacket++;
                        icmp_stat.OutgoingTrafficSize += std::max(0, size - iphdr_hlen);
                        break;
                    }
                };
                My::Net::NetworkStatistics::Statistics& ip_stat = statistics.IPv4;
                ip_stat.OutgoingUnicastPacket++;
                ip_stat.OutgoingTrafficSize += size;
                return true;
            }

            int
            netstack::output(const std::shared_ptr& packet, int size) {
                if (!packet || size < 1) {
                    return ERR_OK;
                }

                std::shared_ptr taptap = tap_;
                if (!taptap) {
                    return false;
                }

                std::shared_ptr tap = taptap->Tap;
                if (!tap) {
                    return ERR_IF;
                }

                if (!tap->Output(packet, size)) {
                    return ERR_IF;
                }

                My::Net::NetworkStatistics& statistics = taptap->_statistics;
                struct ip_hdr* iphdr = (struct ip_hdr*)packet.get();
                
                int iphdr_hlen = IPH_HL_BYTES(iphdr);
                int ip_proto = IPH_PROTO(iphdr);
                switch (ip_proto) {
                case IP_PROTO_TCP:
                    {
                        My::Net::NetworkStatistics::TcpStatistics& tcp_stat = statistics.Tcp;
                        tcp_stat.IncomingUnicastPacket++;
                        tcp_stat.IncomingTrafficSize += std::max(0, size - iphdr_hlen);
                        break;
                    }
                case IP_PROTO_UDP:
                    {
                        My::Net::NetworkStatistics::UdpStatistics& udp_stat = statistics.Udp;
                        udp_stat.IncomingUnicastPacket++;
                        udp_stat.IncomingTrafficSize += std::max(0, size - iphdr_hlen);
                        break;
                    }
                case IP_PROTO_ICMP:
                    {
                        My::Net::NetworkStatistics::Statistics& icmp_stat = statistics.Icmp;
                        icmp_stat.IncomingUnicastPacket++;
                        icmp_stat.IncomingTrafficSize += std::max(0, size - iphdr_hlen);
                        break;
                    }
                };
                My::Net::NetworkStatistics::Statistics& ip_stat = statistics.IPv4;
                ip_stat.IncomingUnicastPacket++;
                ip_stat.IncomingTrafficSize += size;
                return ERR_OK;
            }

            bool
            netstack::open(const std::shared_ptr& tap) {
                if (!tap || tap->IsDisposed()) {
                    return false;
                }

                std::shared_ptr linux_tap = std::dynamic_pointer_cast(tap->Tap);
                if (!linux_tap) {
                    return false;
                }

                #ifdef _WIN32
                sys_init();
                #endif
                lwip_init();

                struct netif* netif = netif_list;
                netif->input        = netif->input ? netif->input : ::ip_input;
                netif->output       = netstack_ip_output_v4; /*netif_loop_output_ipv4*/
                netif->output_ip6   = netstack_ip_output_v6; /*netif_loop_output_ipv6*/

                ip4_addr_t ips[] = { linux_tap->LocalAddress, linux_tap->NetworkMask, linux_tap->GatewayAddress };
                netif_set_ipaddr(netif, ips + 0);
                netif_set_netmask(netif, ips + 1);
                netif_set_gw(netif, ips + 2);

                tap_          = tap;
                netif_        = netif;
                netif_default = netif;
                if (!netstack_tcp_init()) {
                    return false;
                }
                return nestack_loopback() != 0;
            }

            boost::asio::ip::tcp::endpoint 
            netstack::localhost() {
                std::shared_ptr taptap = tap_;
                if (!taptap) {
                    return My::Net::IPEndPoint::WrapAddress(0, 0);
                }

                if (taptap->IsDisposed()) {
                    return My::Net::IPEndPoint::WrapAddress(0, 0);
                }

                std::shared_ptr tun_ = taptap->Tap;
                if (!tun_) {
                    return My::Net::IPEndPoint::WrapAddress(0, 0);
                }

                My::Net::IPEndPoint localEP(tun_->LocalAddress, taptap->_listenEP.Port);
                return My::Net::IPEndPoint::ToEndPoint(localEP);
            }

            bool 
            netstack::link(int key, uint32_t& srcAddr, int& srcPort, uint32_t& dstAddr, int& dstPort) {
                key     = ntohs(key);
                dstAddr = 0;
                dstPort = 0;
                srcAddr = 0;
                srcPort = 0;

                std::shared_ptr socket = netstack_tcp_getsocket(key);
                if (!socket) {
                    return false;
                }

                if (IP_IS_V4_VAL(socket->remote_ip)) {
                    dstAddr = ip_addr_get_ip4_u32(&socket->remote_ip);
                    dstPort = socket->remote_port;
                }
                else {
                    return false;
                }
                
                if (IP_IS_V4_VAL(socket->local_ip)) {
                    srcAddr = ip_addr_get_ip4_u32(&socket->local_ip);
                    srcPort = socket->local_port;
                    return true;
                }
                else {
                    return false;
                }
            }
        
            void
            netstack::close() {
                context_.post([] {
                    struct tcp_pcb* pcb = pcb_;
                    pcb_   = NULL;
                    netif_ = NULL;
                    tap_   = NULL;

                    boost::system::error_code ec_;
                    try {
                        timeout_.cancel(ec_);
                    }
                    catch (std::exception&) {}
                    do {
                        std::unordered_set sockets_;
                        do {
                            NetstackMutexScope scope_(lockobj_);
                            Port2Socket::iterator n2ss_tail_ = n2ss_.begin();
                            Port2Socket::iterator n2ss_endl_ = n2ss_.end();
                            for (; n2ss_tail_ != n2ss_endl_; ++n2ss_tail_) {
                                sockets_.insert(std::move(n2ss_tail_->second));
                            }

                            Ptr2Socket::iterator p2ss_tail_ = p2ss_.begin();
                            Ptr2Socket::iterator p2ss_endl_ = p2ss_.end();
                            for (; p2ss_tail_ != p2ss_endl_; ++p2ss_tail_) {
                                sockets_.insert(std::move(p2ss_tail_->second));
                            }

                            n2ss_.clear();
                            p2ss_.clear();
                        } while (0);
                        sockets_.clear();
                    }
                    while (0);
                    if (pcb) {
                        tcp_close(pcb);
                    }
                    context_.stop();
                });
            }
        }
    }
}

你可能感兴趣的:(IP,C/C++,NAT,网络)