使用boost asio在C 中发送layer2

Using boost asio to send layer2 in C++

本文关键字:layer2 boost asio 使用      更新时间:2023-10-16

当前的gnuradio udp sind/源块使用UDP将数据包发送/从NIC发送/输出。它使用Boost ASIO进行发送/接收。我需要修改这些UDP接收器/源块,以使用IP处理两个UDP,以使现有功能可以越过1GB NIC并添加Boost Raw套接字/协议,以便我们可以在没有IP上的IP上发送layer2 packept没有IP地址(接收器是一个FPGA,具有自定义错误检查/恢复等)。

仅使用C,我有测试程序,可以根据需要制作数据包并将其发送出去并在另一侧接收。他们来自:

使用Boost ASIO RAW插座创建一个2层/以太网套接字(在C 中)http://qiita.com/kadopoly/items/acafa01945e5cfe39270

由于Gnuradio在C 中,我需要修改Boost套接字/协议设置以适合UDP_SINK_IMPL.CC和UDP_SINK_IMPL.H.H文件,以便我可以发送数据包。

堆栈溢出链接似乎是最直接的(我不是经验丰富的编码器),我能够将其添加到我的gnuradio块中并传输。它不会正确发送TransMitBuffer2缓冲区(发送了一个数据包,但内容错误),但确实发送了Hello World!溪流缓冲区正确,这对我来说是未知的。但是它无法处理0x00,所以我无法使用它来测试发送的MAC地址。

这是我目前拥有的:

udp_sink_impl.h代码:

    char tmpHeaderBuff[12];  // 32-bit sync word (0xFFFFFFFF), 32-bit sequence num and 32-bit data size
    unsigned char custom_type[2] = {0x82,0x00};
    unsigned char ethHeader[12] = {0x00,0x0c,0x29,0x05,0x0d,0x15,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
    unsigned char mac_str[6];
    unsigned char dstMAC[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};    
    unsigned char srcMAC[6];
/* 1G management stuff */
        boost::asio::io_service d_io_service;
        boost::asio::ip::udp::endpoint d_endpoint;
        boost::asio::ip::udp::socket *udpsocket;
/* 1G management stuff */
/* 10G raw socket stuff */    
      typedef boost::asio::generic::raw_protocol raw_protocol_t;
      typedef boost::asio::generic::basic_endpoint<raw_protocol_t> raw_endpoint_t;      
      boost::asio::io_service d_io_service10;
      raw_protocol_t::socket *d_socket10;
/* 10G raw socket stuff */

udp_sink_impl.cc sminippet:

  getMACAddress(d_send_iface,srcMAC);
/* Begin 1G management connection */
      std::string s__port = (boost::format("%d") % port).str();
      std::string s__host = host.empty() ? std::string("localhost") : host;
      boost::asio::ip::udp::resolver resolver(d_io_service);
      boost::asio::ip::udp::resolver::query query(s__host, s__port,
          boost::asio::ip::resolver_query_base::passive);
      d_endpoint = *resolver.resolve(query);
          udpsocket = new boost::asio::ip::udp::socket(d_io_service);
        udpsocket->connect(d_endpoint);
/* End 1G management connection */
/* Begin 10G management connection */      
      sockaddr_ll sockaddr;
      memset(&sockaddr, 0, sizeof(sockaddr));
      sockaddr.sll_family = PF_PACKET;
      sockaddr.sll_protocol = htons(ETH_P_ALL);
      sockaddr.sll_ifindex = if_nametoindex(send_iface.c_str());
      sockaddr.sll_hatype = 1;
      raw_protocol_t::socket d_socket10(d_io_service10, raw_protocol_t(PF_PACKET, SOCK_RAW));   /* Needs root or cap_net_raw permissions */   
      d_socket10.bind(raw_endpoint_t(&sockaddr, sizeof(sockaddr)));
/* End 10G management connection */
/* This currently does not work for unknown reason. Transmitted packet does NOT match buffer contents expected. But the streambuf seems to work.      */
      std::vector<boost::asio::const_buffer> transmitbuffer2;        
      transmitbuffer2.clear();
      transmitbuffer2.push_back(boost::asio::buffer((const void *)srcMAC, sizeof(srcMAC)));
      transmitbuffer2.push_back(boost::asio::buffer((const void *)dstMAC, sizeof(dstMAC)));
      transmitbuffer2.push_back(boost::asio::buffer((const void *)custom_type, sizeof(custom_type)));
      d_socket10.send(boost::asio::buffer(transmitbuffer2));
/* for testing */
    boost::asio::streambuf buffer;
    std::ostream stream( &buffer );    
    unsigned char const deadbeef[] = { 0xde, 0xad, 0xbe, 0xef }; // can't handle 0x00
    stream << "Hello, World!!!"
           << reinterpret_cast< char const * >( deadbeef ); 
    d_socket10.send(buffer.data());    
    } // Close constructor
.
.
.
    udp_sink_impl::work(int noutput_items,
    gr_vector_const_void_star &input_items,
    gr_vector_void_star &output_items)
{
.
.
.
    udpsocket->send_to(transmitbuffer,d_endpoint);

最终,在UDP_SINK_IMPL ::工作功能我想替换现有的UDP调用:

udpsocket->send_to(transmitbuffer,d_endpoint); 

与:

之类的东西
d_socket10->send(transmitbuffer);

当前,当我这样做时,没有发送数据包,似乎会崩溃或退出程序,而不是连续发送数据,所以我认为这是某种崩溃。

有人可以向我解释如何实现简单堆栈溢出示例的指针或C 中的日语令牌的RAW套接字示例,用于UDP接收器/源块?接收器(发送)当前是我的优先级(接收)。

非常感谢。任何帮助或建议都非常感谢。

从散布收集io上的boost文档中,我认为发送的语法应该是:

d_socket10.send(transmitbuffer2); // don't add the extra boost::asio::buffer()

我找不到他们使用boost::asio::buffer对缓冲区向量的任何示例


对于流测试,您必须使用write成员功能而不是operator<<在流中插入时指定大小。类似:

unsigned char const deadbeef[5] = { 0x00, 0xde, 0xad, 0xbe, 0xef };
stream.write(reinterpret_cast<const char*>(&deadbeef[0]), 5);

这样,您可以处理发送空字符。


您可以显示如何构建transmitbuffer吗?它与transmitbuffer2相同吗?

编辑

segfaults表示您尝试以非法方式访问内存。只能从您的片段中进行调试很难,但是我首先要检查您发送的缓冲区仍然有效。boost::asio::buffer不会制作基础内存的副本,并且在您准备发送时需要保持有效。

您还会在摘要中混合指针和对象,因此请确保您没有任何悬挂的指针,并且每个人都处于有效状态,然后才能致电send

编辑2

在标题文件中,您声明了一个名为d_socket10的成员指针,该指针从未在构造函数中分配或创建。此电话在第147行:

raw_protocol_t::socket d_socket10(d_io_service10, raw_protocol_t(PF_PACKET, SOCK_RAW));

创建一个与您的会员指针相同名称的对象,当您退出构造函数的范围时,该对象将被破坏。稍后,您使用从未分配任何东西的会员指针致电send,因此您的segfault。

要修复它,您需要创建它并管理它的寿命,就像udpsocket相同的方式:

d_socket10 = new raw_protocol_t::socket(d_io_service10, raw_protocol_t(PF_PACKET, SOCK_RAW));

并在不再需要时调用delete