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

51 篇文章 2 订阅
17 篇文章 2 订阅

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

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<My::Net::TapTap2Socket>& 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 <My/Environment.h>
#include <My/Tun/ITap.h>
#include <My/Tun/Linux/Tap.h>
#include <My/Net/LwIP/netstack.h>
#include <My/Net/IPEndPoint.h>
#include <My/Net/Socket.h>
#include <My/Net/NetworkStatistics.h>
#include <My/Net/TapTap2Socket.h>

#include <list>
#include <lwip/init.h>
#include <lwip/netif.h>
#include <lwip/tcp.h>
#include <lwip/udp.h>
#include <lwip/sys.h>
#include <lwip/timeouts.h>
#include <lwip/priv/tcp_priv.h>

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

                typedef struct {
                    buffer_chunk                                buf;
                    std::function<void(struct tcp_pcb*)>        cb;
                } send_context;
                typedef std::shared_ptr<send_context>           send_context_ptr;

                typedef enum {
                    ENETSTACK_TCP_SENT_LWIP,
                    ENETSTACK_TCP_SENT_SOCK,
                    ENETSTACK_TCP_SENT_MAX
                } ENETSTACK_TCP_SENT_BUFS;

                std::list<send_context_ptr>                     sents[ENETSTACK_TCP_SENT_MAX];
                std::shared_ptr<boost::asio::ip::tcp::socket>   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<netstack_tcp_socket>        NetstackSocket;
            typedef std::unordered_map<int, NetstackSocket>     Port2Socket;
            typedef std::unordered_map<void*, NetstackSocket>   Ptr2Socket;
            typedef std::recursive_mutex                        NetstackMutex;
            typedef std::lock_guard<NetstackMutex>              NetstackMutexScope;

            static boost::asio::io_context                      context_;
            static boost::asio::deadline_timer                  timeout_(context_);
            static std::shared_ptr<My::Net::TapTap2Socket>     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<netstack_tcp_socket>& socket) {
                if (port <= My::Net::IPEndPoint::MinPort || port > My::Net::IPEndPoint::MaxPort) {
                    return false;
                }
                if (!socket) {
                    return false;
                }
                else {
                    NetstackMutexScope scope_(lockobj_);
                    std::pair<Port2Socket::iterator, bool> 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<netstack_tcp_socket>& socket) {
                if (!pcb || !socket) {
                    return NULL;
                }

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

            inline static std::shared_ptr<netstack_tcp_socket>
            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_socket>
            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_socket>
            netstack_tcp_releasesocket(int port) {
                if (port <= My::Net::IPEndPoint::MinPort || port > My::Net::IPEndPoint::MaxPort) {
                    return NULL;
                }

                std::shared_ptr<netstack_tcp_socket> 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_socket>
            netstack_tcp_releasesocket(void* p) {
                if (!p) {
                    return NULL;
                }

                std::shared_ptr<netstack_tcp_socket> 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<netstack_tcp_socket>& socket_);

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

                std::shared_ptr<netstack_tcp_socket> 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<void(struct tcp_pcb*)>& callback) {
                    std::shared_ptr<Byte> chunk_ = My::make_shared_alloc<Byte>(len);
                    memcpy(chunk_.get(), data, len);

                    netstack_tcp_socket::send_context_ptr context_ = 
                        My::make_shared_object<netstack_tcp_socket::send_context>();
                    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<netstack_tcp_socket>& 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<netstack_tcp_socket> 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<netstack_tcp_socket>& 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<netstack_tcp_socket> 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<netstack_tcp_socket> socket_ = netstack_tcp_getsocket(pcb->callback_arg);
                if (socket_) {
                    std::list<netstack_tcp_socket::send_context_ptr>& 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<netstack_tcp_socket> 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<netstack_tcp_socket> socket = netstack_tcp_getsocket(pcb->callback_arg);
                if (socket) {
                    std::shared_ptr<boost::asio::ip::tcp::socket> 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<netstack_tcp_socket>& 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<netstack_tcp_socket> socket_ = std::make_shared<netstack_tcp_socket>();
                socket_->pnat        = 0;
                socket_->pcb         = pcb;
                socket_->open        = false;
                socket_->socket      = std::make_shared<boost::asio::ip::tcp::socket>(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<netstack_tcp_socket>& socket_, void* data, int len, bool unsafe_) {
                if (!socket_ || !data || len < 1) {
                    return false;
                }

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

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

                    netstack_tcp_socket::send_context_ptr context_ = 
                        My::make_shared_object<netstack_tcp_socket::send_context>();
                    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<Byte> chunk_;
                if (unsafe_) {
                    chunk_ = My::make_shared_alloc<Byte>(len);
                    memcpy(chunk_.get(), data, len);
                }
                else {
                    chunk_ = *(std::shared_ptr<Byte>*)data;
                }

                std::shared_ptr<netstack_tcp_socket> 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<netstack_tcp_socket>& socket_) {
                if (!socket_) {
                    return false;
                }

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

                std::shared_ptr<netstack_tcp_socket> 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<int>(-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<netstack_tcp_socket>& socket_) {
                if (!socket_) {
                    return false;
                }

                std::list<netstack_tcp_socket::send_context_ptr>& 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<netstack_tcp_socket>& socket_) {
                if (!socket_) {
                    return false;
                }

                std::shared_ptr<My::Net::TapTap2Socket> taptap = tap_;
                if (!taptap) {
                    return false;
                }

                std::shared_ptr<boost::asio::ip::tcp::socket>& 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<netstack_tcp_socket> 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<Byte> packet = My::make_shared_alloc<Byte>(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<My::Net::TapTap2Socket> 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<int>(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<int>(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<int>(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<Byte>& packet, int size) {
                if (!packet || size < 1) {
                    return ERR_OK;
                }

                std::shared_ptr<My::Net::TapTap2Socket> taptap = tap_;
                if (!taptap) {
                    return false;
                }

                std::shared_ptr<My::Tun::ITap> 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<int>(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<int>(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<int>(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<My::Net::TapTap2Socket>& tap) {
                if (!tap || tap->IsDisposed()) {
                    return false;
                }

                std::shared_ptr<My::Tun::Linux::Tap> linux_tap = std::dynamic_pointer_cast<My::Tun::Linux::Tap>(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<My::Net::TapTap2Socket> taptap = tap_;
                if (!taptap) {
                    return My::Net::IPEndPoint::WrapAddress<boost::asio::ip::tcp>(0, 0);
                }

                if (taptap->IsDisposed()) {
                    return My::Net::IPEndPoint::WrapAddress<boost::asio::ip::tcp>(0, 0);
                }

                std::shared_ptr<My::Tun::ITap> tun_ = taptap->Tap;
                if (!tun_) {
                    return My::Net::IPEndPoint::WrapAddress<boost::asio::ip::tcp>(0, 0);
                }

                My::Net::IPEndPoint localEP(tun_->LocalAddress, taptap->_listenEP.Port);
                return My::Net::IPEndPoint::ToEndPoint<boost::asio::ip::tcp>(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<netstack_tcp_socket> 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<NetstackSocket> 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();
                });
            }
        }
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: lwIP协议栈源码详解pdf是一本关于lwIP协议栈源代码的介绍和解析的书籍。lwIP协议栈是一款开源的、小型的TCP/IP协议栈,主要用于嵌入式系统中,在许多嵌入式领域都有广泛的应用。这本书详细介绍了lwIP协议栈源码的结构和实现原理,对深入理解lwIP协议栈的工作原理和实现方法具有很大的帮助。 该书主要分为7章,内容涵盖了lwIP协议栈的基本架构、源码框架、数据结构、协议栈初始化、数据包发送和接收、TCP协议的实现、以及调试工具与示例代码等方面。其中,对于数据结构的介绍较为详细,包括全局变量、链表、缓冲池等的实现方法和意义,让读者更加深入地理解lwIP协议栈的内部实现。 此外,该书还介绍了lwIP协议栈的调试工具和实例代码,可以帮助读者更加快速地理解lwIP协议栈的使用和应用。例如,书中讲解了如何使用Wireshark抓取TCP/IP通信数据包,并包含了示例代码,可以由读者自行测试。 总体来说,该书是一本非常好的lwIP协议栈源码解析书籍,对于需要深入学习和了解lwIP协议栈的工作原理以及如何使用它来实现嵌入式网络通信的开发人员非常有价值。 ### 回答2: 《lwip协议栈源码详解》是一本讲解lwip协议栈源码的书。这个协议栈是一个开源的TCP/IP协议栈,适用于嵌入式系统。它提供了包括TCP、UDP、IPv4、IPv6、ICMP、SNTP、DHCP等常用协议,并支持各种网络接口。这本书详细介绍了lwip协议栈的内部结构,包括数据结构、函数调用方式以及各个组件的实现方法。 首先,书中介绍了lwip的内存管理机制。lwip协议栈使用连续内存管理,通过定义内存池来管理内存。这个机制非常专业,并且能够提供内存保护,提高数据传输的效率。其次,书中介绍了lwip协议栈的各个模块的实现,包括TCP、UDP、ISP、IP、ICMP等。这些模块是lwip协议栈的基本构成部分。通过深入的了解这些模块的原理和实现方式,读者可以更好地掌握lwip协议栈的使用方法。 书中还介绍了lwip协议栈的一些高级功能,比如多线程支持、SNTP服务等。这些功能虽然不是lwip协议栈的基本功能,但是在网络应用中很常见。通过书中的介绍,读者可以学习如何在自己的应用程序中使用这些功能。 总之,《lwip协议栈源码详解》是一本非常好的加深对lwip协议栈的理解的书籍,能够帮助读者深入了解lwip协议栈实现原理和使用方法。同时,它也是一本好的参考书,可供嵌入式系统开发工程师和网络协议栈开发人员参考。 ### 回答3: lwIP协议栈是一个基于C语言开发的轻量级、高效的协议栈,广泛应用于嵌入式系统中,其源码详解可以帮助我们更好地了解其实现原理和工作流程。 该PDF文件详细介绍了lwIP协议栈的基本结构、各个模块的实现原理、相关API和接口函数等。其中,该协议栈的基本结构包括实现TCP/IP协议的核心模块和各种外部功能模块,如数据通道层、网络接口层、协议栈接口等等。 在协议栈实现中,数据的传输过程可以看作是一条管道,数据从上层通过协议栈的接口函数进入栈中,经过一系列处理,最终从底层网络接口层发送出去。该PDF中详细说明了数据的传输过程和相关函数的调用流程,为学习者深入了解lwIP实现提供了帮助。 此外,该文件还介绍了lwIP协议栈的多线程实现原理和实现方法,以及各种协议实现的具体方式和相关函数的调用流程。其中,针对常用的TCP和UDP协议,该文件还介绍了它们的具体原理和如何在lwIP协议栈实现。 总之,这份源码详解是一份非常实用的资料,可以帮助我们更好地理解lwIP协议栈实现原理和工作流程,对于在嵌入式系统开发中使用和调试该协议栈都十分有帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值