2013-02-21 2 views
1

Я использую Boost :: ASIO версии 1.52.0 для Windows с версией SSL C на тестовой машине с Win 8 с кодом Visual Studio 2008 в VC++.Использование ip-адреса вместо url в asio

У меня есть некоторый код, который успешно подключается к серверу TCP с заданной URL:

// Create the resolver and query objects to resolve the host name in serverPath to an ip address. 
boost::asio::ip::tcp::resolver resolver(*IOService); 
boost::asio::ip::tcp::resolver::query query(serverPath, port); 
boost::asio::ip::tcp::resolver::iterator EndpointIterator = resolver.resolve(query); 
// Set up an SSL context. 
boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client); 
// Specify to not verify the server certificiate right now. 
ctx.set_verify_mode(boost::asio::ssl::context::verify_none); 
// Init the socket object used to initially communicate with the server. 
pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx); 
// 
// The thread we are on now, is most likely the user interface thread. Create a thread to handle all incoming socket work messages. 
// This thread is created for each connection to a server. 
if (!RcvThreadCreated) 
{ 
    WorkerThreads.create_thread(boost::bind(&SSLSocket::RcvWorkerThread, this)); 
    RcvThreadCreated = true; 
    WorkerThreads.create_thread(boost::bind(&SSLSocket::SendWorkerThread, this)); 
} 
// Try to connect to the server. Note - add timeout logic at some point. 
boost::asio::async_connect(pSocket->lowest_layer(), EndpointIterator, 
    boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholders::error)); 

На основании некоторых исследований, приведенный выше код, который разрешает IP-адрес не может быть использован, если IP-адрес подставляется для URL-адреса в serverPath. Похоже, что правильный подход заключается в создании конечной точки, как это:

const boost::asio::ip::address IP(boost::asio::ip::address::from_string(serverPath)); 
int iport = atoi(port.c_str()); 
boost::asio::ip::tcp::endpoint EP(IP, iport); 

Эта часть кажется компилировать нормально. Но позже в методе async_connect:

// Try to connect to the server. Note - add timeout logic at some point. 
boost::asio::async_connect(pSocket->lowest_layer(), EP, 
boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholders::error)); 

он генерирует ошибку. Я предполагаю, что метод async_connect хочет видеть итератор для второго аргумента. Но я не уверен, как его создать.

Согласно следующему link, ответ предполагает, что можно использовать метод соединения на объекте сокета. Но, когда я пытаюсь сделать это:

pSocket->connect(EP); 

Компилятор выдает ошибку - ошибка C2039:

'connect' : is not a member of 'boost::asio::ssl::stream<Stream>' 

Так, может кто-то пожалуйста, покажите простой код, который предоставляет возможность подключения к серверу с IP-адрес вместо URL-адреса?

Если это невозможно, то есть ли способ сделать обратный поиск с IP-адреса, чтобы получить URL-адрес?

+0

Неясно, где ваш отказ от компиляции, можете ли вы объединить свои фрагменты в один пример кода? –

ответ

1

Ваш async_connect () строка кода не компилируется потому что вы передаете указатель функции-члена, не привязывая к нему экземпляр. Вы связали функцию-член правильно в других местах вашего кода, поэтому я думаю, что это просто надзор.Правильная линия будет что-то вроде:

pSocket->next_layer().async_connect(
    EP, 
    boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholder::error)); 

Что касается исходного вопроса, получение конечных точек для IP-адресов, используя IP :: Tcp :: распознаватель на IP-адрес запроса работает нормально, так что вы не должны имеют отдельные коды для имен и адресов. Использование метода low_layer() в ssl :: stream для доступа к базовому ip :: tcp :: socket - это правильный способ доступа к connect() и async_connect().

Помимо создания ssl :: stream с помощью ssl :: context и использования async_handshake() после установления соединения, ваш код SSL должен выглядеть почти идентично вашему TCP-коду. Вы также можете использовать low_layer() в своем TCP-коде (он просто возвращает себя), что может подчеркнуть сходство.

Я не гарантирую этот код компилируется, потому что я упростил его из рабочего кода, но если вы делаете async_resolve(), ваш метод обработчика решительность будет выглядеть примерно так (sp_ это сокет/указатель потока):

void Pimpl::handleResolve(
    const boost::system::error_code& ec, 
    boost::asio::ip::tcp::resolver::iterator endpointIterator) { 
    if (ec) { 
    // error handling here 
    return;  
    } 
    sp_->lowest_layer().async_connect( 
    *endpointIterator, 
    boost::bind(&Pimpl::handleConnect, this, endpointIterator, boost::asio::placeholder::error)); 
} 

Тогда ваш обработчик подключения будет выглядеть (это пытается конечные точки до тех пор, пока не получит то, что работает или там не больше):

void Pimpl::handleConnect(
    boost::asio::ip::tcp::resolver::iterator endpointIterator, 
    const boost::system::error_code& ec) { 
    if (!ec) { 
    sp_->async_handshake(
     boost::asio::ssl::stream_base::client, 
     boost::bind(&Pimpl::handleHandshake, this, boost::asio::placeholder::error)); 
    } 
    else if (++endpointIterator != boost::asio::ip::tcp::resolver::iterator()) { 
    // Try connecting to the next endpoint. 
    sp_->lowest_layer().close(); 
    sp_->lowest_layer().async_connect(
     *endpointIterator, 
     boost::bind(&Pimpl::handleConnect, this, endpointIterator, boost::asio::placeholder::error)); 
    } 
    else { 
    // error handling here 
    } 
} 

Единственная линия, которая делает это специфичным для Ssl :: указатель потока а не указатель ip :: tcp :: socket вызов async_handshake().

+0

Спасибо. Я попробую, когда я получу запасной момент. –

0

Я нашел работу вокруг проблемы. Я использую класс ssl :: stream как объект сокета, и причина ошибки заключается в том, что у него нет метода подключения. Однако у него есть метод next_layer(), который возвращает объект, который может вызывать метод connect или async_connect. У меня возникли проблемы с получением async_connect для компиляции, но метод connect работает. Затем я позвонил моему методу HandleConnect впоследствии так:

boost::system::error_code EC; 
pSocket->next_layer().connect(EP, EC); 
HandleConnect(EC); 

В ответ на @SamMiller запрос на код, он приводится ниже. Мне все же хотелось бы знать, как создать итератор для конечной точки для вызова boost :: asio :: async_connect, а также как вызвать метод async_connect для объекта next_layer.

void SSLSocket::Connect(SSLSocket* psSLS, const string& serverPath, string& port) 
{ 
    // Connects to the server. 
    // serverPath - specifies the path to the server. Can be either an ip address or url. 
    // port - port server is listening on. 
    // 
    try 
    { 
     Locking CodeLock(SocketLock); // Single thread the code. 
     // If the user has tried to connect before, then make sure everything is clean before trying to do so again. 
     if (pSocket) 
     { 
     delete pSocket; 
     pSocket = 0; 
     }                         
     // If serverPath is a URL, then resolve the address. 
     if ((serverPath[0] < '0') || (serverPath[0] > '9')) // Assumes that the first char of the server path is not a number when resolving to an ip addr. 
     { 
     // Create the resolver and query objects to resolve the host name in serverPath to an ip address. 
     boost::asio::ip::tcp::resolver resolver(*IOService); 
     boost::asio::ip::tcp::resolver::query query(serverPath, port); 
     boost::asio::ip::tcp::resolver::iterator EndpointIterator = resolver.resolve(query); 
     // Set up an SSL context. 
     boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client); 
     // Specify to not verify the server certificiate right now. 
     ctx.set_verify_mode(boost::asio::ssl::context::verify_none); 
     // Init the socket object used to initially communicate with the server. 
     pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx); 
     // 
     // The thread we are on now, is most likely the user interface thread. Create a thread to handle all incoming socket work messages. 
     // This thread is created for each connection to a server. 
     if (!RcvThreadCreated) 
     { 
      WorkerThreads.create_thread(boost::bind(&SSLSocket::RcvWorkerThread, this)); 
      RcvThreadCreated = true; 
      WorkerThreads.create_thread(boost::bind(&SSLSocket::SendWorkerThread, this)); 
     } 
     // Try to connect to the server. Note - add timeout logic at some point. 
     boost::asio::async_connect(pSocket->lowest_layer(), EndpointIterator, 
      boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholders::error)); 
     } 
     else 
     { 
     // serverPath is an ip address, so try to connect using that. 
     // 
     // Create an endpoint with the specified ip address. 
     const boost::asio::ip::address IP(boost::asio::ip::address::from_string(serverPath)); 
     int iport = atoi(port.c_str()); 
     const boost::asio::ip::tcp::endpoint EP(IP, iport); 
     // Set up an SSL context. 
     boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client); 
     // Specify to not verify the server certificiate right now. 
     ctx.set_verify_mode(boost::asio::ssl::context::verify_none); 
     // Init the socket object used to initially communicate with the server. 
     pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx); 
     // 
     // The thread we are on now, is most likely the user interface thread. Create a thread to handle all incoming socket work messages. 
     // This thread is created for each connection to a server. 
     if (!RcvThreadCreated) 
     { 
      WorkerThreads.create_thread(boost::bind(&SSLSocket::RcvWorkerThread, this)); 
      RcvThreadCreated = true; 
      WorkerThreads.create_thread(boost::bind(&SSLSocket::SendWorkerThread, this)); 
     } 
     // Try to connect to the server. Note - add timeout logic at some point. 
     // pSocket->next_layer().async_connect(EP, &SSLSocket::HandleConnect); 
     boost::system::error_code EC; 
     pSocket->next_layer().connect(EP, EC); 
     if (EC) 
     { 
      // Log an error. This worker thread should exit gracefully after this. 
      stringstream ss; 
      ss << "SSLSocket::Connect: connect failed to " << sClientIp << " : " << uiClientPort << ". Error: " << EC.message() + ".\n"; 
      Log.LogString(ss.str(), LogError); 
     } 
     HandleConnect(EC); 
     } 
    } 
    catch (std::exception& e) 
    { 
     stringstream ss; 
     ss << "SSLSocket::Connect: threw an error - " << e.what() << ".\n"; 
     Log.LogString(ss.str(), LogError); 
     Stop(); 
    } 
} 

Это ошибка, которая возникает, когда следующая строка:

pSocket->next_layer().async_connect(EP, &SSLSocket::HandleConnect); // Does not compile 

подменяется:

boost::system::error_code EC; 
pSocket->next_layer().connect(EP, EC); // Compiles and works properly. 

Сообщение об ошибке:

1>c:\boost_1_52_0\boost\asio\basic_socket.hpp(706) : error C2064: term does not evaluate to a function taking 1 arguments 
1>  c:\users\bob\documents\visual studio 2008\projects\attackpoker1\win32client\sslsockets\sslsocket.cpp(114) : see reference to function template instantiation 'void boost::asio::basic_socket<Protocol,SocketService>::async_connect<void(__thiscall SSLSocket::*)(const boost::system::error_code &)>(const boost::asio::ip::basic_endpoint<InternetProtocol> &,const ConnectHandler &)' being compiled 
1>  with 
1>  [ 
1>   Protocol=boost::asio::ip::tcp, 
1>   SocketService=boost::asio::stream_socket_service<boost::asio::ip::tcp>, 
1>   InternetProtocol=boost::asio::ip::tcp, 
1>   ConnectHandler=void (__thiscall SSLSocket::*)(const boost::system::error_code &) 
1>  ] 
Смежные вопросы