Использование Boost Asio для приема адресов области связи IPv6

У меня есть TCP-сервер, использующий Boost ASIO. Я заметил, что при использовании адресов IPv6 с областью действия в Linux я не могу создать boost::asio::ip::tcp::acceptorбез исключения. Использование глобального IPv6-адреса или IPv4-адреса будет работать нормально.

Я почти уверен, что проблема в том, что идентификатор области не установлен правильно, но я не могу понять, как решить эту проблему.

Я разрабатываю Ubuntu 11.04 LTS, используя предоставленную Ubuntu библиотеку boost 1.40.0. Вот очень упрощенная версия кода сервера, которая у меня есть, которая показывает проблему:

#include 
#include 
#include 
#include 
#include 

/* To Compile:
g++ -Wall -o./asio-ipv6./asio-ipv6.cpp -lboost_system 
*/

typedef boost::shared_ptr   TcpSocketPtr;
typedef boost::shared_ptr TcpAcceptorPtr;
typedef boost::shared_ptr TcpEndpointPtr;

class AsioServer{
public:
  AsioServer(boost::asio::io_service& io): io_(io){};

  //throws
  void accept(const std::string& ipString,unsigned short port){
    boost::asio::ip::address addr = boost::asio::ip::address::from_string(ipString);
    std::cout << "Valid IP address " << ipString << std::endl;

    this->endpoint_.reset(new boost::asio::ip::tcp::endpoint(addr,port));
    std::cout << "Created endpoint" << std::endl;

    //Will throw if a link local IPv6 address is used
    acceptor_.reset(new boost::asio::ip::tcp::acceptor(this->io_,*(this->endpoint_)));

    std::cout << "About to accept on " << *(this->endpoint_) << std::endl;
    this->socket_.reset(new boost::asio::ip::tcp::socket(this->io_));
    this->acceptor_->async_accept(*socket_,boost::bind(&AsioServer::handle_accept,this,boost::asio::placeholders::error)); 
  }

private:
  boost::asio::io_service& io_;
  TcpSocketPtr socket_;
  TcpAcceptorPtr acceptor_;
  TcpEndpointPtr endpoint_;

  void handle_accept(const boost::system::error_code &ec){
    if(!ec){
      std::cout << "Accepted connection!" << std::endl;
    }
    else{
      std::cout << "Error accepting connection" << std::endl;
    }
  };

};

int main(int argc, char* argv[]){

  boost::asio::io_service io;

  std::string ipString("0.0.0.0");
  if(argc > 1){
    ipString.assign(argv[1]);   
  }
  std::cout << "IP Set to " << ipString << std::endl;

  AsioServer server(io);

  try{
    server.accept(ipString,4444);
  }
  catch(const std::exception& e){
    std::cout << "Error caught:  " << e.what() << std::endl;
  }

  io.run();

  std::cout << "Done!" << std::endl;

  return 0;
}

На этой машине у меня настроено следующее для eth0:

$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:0c:29:10:cf:0e  
          inet addr:192.168.97.162  Bcast:192.168.97.255  Mask:255.255.255.0
          inet6 addr: 2620:1c:8000:190:20c:29ff:fe10:cf0e/64 Scope:Global
          inet6 addr: fe80::20c:29ff:fe10:cf0e/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:112470185 errors:2 dropped:1 overruns:0 frame:0
          TX packets:5900249 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:2187237130 (2.1 GB)  TX bytes:1640094885 (1.6 GB)
          Interrupt:19 Base address:0x2000 

Запуск программы с использованием 192.168.97.162 , 0.0.0.0 , 127.0.0.1 ,::1 или 2620 :1c :8000 :190 :20c :29ff :fe10 :cf0e работает нормально, но при использовании fe80 ::20c :29ff :fe10 :cf0e не удается создать акцептор с выбрасываемым исключением «Недопустимый аргумент»..

$./asio-ipv6 fe80::20c:29ff:fe10:cf0e
IP Set to fe80::20c:29ff:fe10:cf0e
Valid IP address fe80::20c:29ff:fe10:cf0e
Created endpoint
Error caught:  Invalid argument
Done!

Это напомнило мне о том, как я использовал ping6 и увидел ту же ошибку «Неверный аргумент». Исправление состоит в том, чтобы передать интерфейс, добавленный к адресу IPv6.

$ ping6 fe80::219:b9ff:fe2b:3a53  #Won't work
connect: Invalid argument
$ ping6 fe80::219:b9ff:fe2b:3a53%eth0 #Pass the interface to use to ping6 
PING fe80::219:b9ff:fe2b:3a53%eth0(fe80::219:b9ff:fe2b:3a53) 56 data bytes

Это не работает для Boost Asio, когда я пытаюсь создать IP-адрес из строки.

$./asio-ipv6 fe80::20c:29ff:fe10:cf0e%eth0
IP Set to fe80::20c:29ff:fe10:cf0e%eth0
Error caught:  Invalid argument
Done!

У меня вопрос: как вы собираетесь прослушивать IPv6-адрес с областью действия ссылки, используя Boost ASIO? Класс boost::asio::ip::address_v6имеет область действия _идентификатор ()функцию-член , но я не уверен, где взять идентификатор области действия в виде беззнакового длинного или если это проблема.

5
задан Joel 23 April 2012 в 18:19
поделиться