ana/src/asio_proxy_connection.cpp

Go to the documentation of this file.
00001 /* $Id: asio_proxy_connection.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 
00003 /**
00004  * @file
00005  * @brief Implementation of the client side proxy connection for the ana project.
00006  *
00007  * ana: Asynchronous Network API.
00008  * Copyright (C) 2010 - 2012 Guillermo Biset.
00009  *
00010  * This file is part of the ana project.
00011  *
00012  * System:         ana
00013  * Language:       C++
00014  *
00015  * Author:         Guillermo Biset
00016  * E-Mail:         billybiset AT gmail DOT com
00017  *
00018  * ana is free software: you can redistribute it and/or modify
00019  * it under the terms of the GNU General Public License as published by
00020  * the Free Software Foundation, either version 2 of the License, or
00021  * (at your option) any later version.
00022  *
00023  * ana is distributed in the hope that it will be useful,
00024  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00025  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00026  * GNU General Public License for more details.
00027  *
00028  * You should have received a copy of the GNU General Public License
00029  * along with ana.  If not, see <http://www.gnu.org/licenses/>.
00030  *
00031  */
00032 
00033 #include <sstream>
00034 
00035 #include "asio_proxy_connection.hpp"
00036 
00037 proxy_connection::proxy_connection(tcp::socket&      socket,
00038                                    proxy_information pi,
00039                                    ana::address      address,
00040                                    ana::port         port,
00041                                    ana::timer*       timer) :
00042     socket_(socket),
00043     proxy_info_(pi),
00044     address_(address),
00045     port_(port),
00046     manager_( NULL ),
00047     conn_handler_( NULL ),
00048     authenticating_( false ),
00049     timer_( timer )
00050 {
00051 }
00052 
00053 
00054 std::string* proxy_connection::generate_connect_request() const
00055 {
00056     return new std::string
00057     (
00058         "CONNECT " + address_ + ":" + port_ + " HTTP/1.0\n"
00059         "User-agent: ana 0.1 \n"
00060         "\n"
00061     );
00062 }
00063 
00064 std::string* proxy_connection::generate_base64_credentials() const
00065 {
00066     const std::string user_and_pass( proxy_info_.user_name + ':' + proxy_info_.password );
00067     return new std::string
00068     (
00069         "CONNECT " + address_ + ":" + port_ + " HTTP/1.0\n"
00070         "User-agent: ana 0.1 \n"
00071         "Proxy-Connection: keep-alive\n"
00072         "Proxy-Authorization: Basic " + base64_encode(user_and_pass.c_str(),
00073                                                       user_and_pass.size() ) + "\n"
00074         "\n"
00075     );
00076 }
00077 
00078 std::string proxy_connection::base64_encode(char const* bytes_to_encode, unsigned int in_len) const
00079 {
00080     std::string ret;
00081     int i = 0;
00082     int j = 0;
00083     unsigned char char_array_3[3];
00084     unsigned char char_array_4[4];
00085     const char base64_chars[(1 << 6) + 2]
00086                = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
00087 
00088     while (in_len--) {
00089         char_array_3[i++] = *(bytes_to_encode++);
00090         if (i == 3) {
00091             char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
00092             char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
00093             char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
00094             char_array_4[3] = char_array_3[2] & 0x3f;
00095 
00096             for(i = 0; (i <4) ; i++)
00097                 ret += base64_chars[char_array_4[i]];
00098             i = 0;
00099         }
00100     }
00101 
00102     if (i)
00103     {
00104         for(j = i; j < 3; j++)
00105             char_array_3[j] = '\0';
00106 
00107         char_array_4[0] = (char_array_3[0]  & 0xfc) >> 2;
00108         char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
00109         char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
00110         char_array_4[3] = char_array_3[2]   & 0x3f;
00111 
00112         for (j = 0; (j < i + 1); j++)
00113             ret += base64_chars[char_array_4[j]];
00114 
00115         while((i++ < 3))
00116             ret += '=';
00117 
00118     }
00119 
00120     return ret;
00121 }
00122 
00123 bool proxy_connection::finds( const std::string& source, char const* pattern )
00124 {
00125     const size_t find_pos = source.find( std::string( pattern ) );
00126 
00127     return find_pos < source.size();
00128 }
00129 
00130 void proxy_connection::handle_response(boost::asio::streambuf*          buf,
00131                                        const boost::system::error_code& ec,
00132                                        size_t                           /*bytes_read*/)
00133 {
00134     std::stringstream ss;
00135     ss << buf;
00136     delete buf;
00137 
00138     if ( ec )
00139         manager_->handle_proxy_connection( ec, conn_handler_, timer_ );
00140     else
00141     {
00142         if ( finds( ss.str(), "200" ) )
00143             manager_->handle_proxy_connection( ec, conn_handler_, timer_ );
00144         else
00145         {
00146             if ( ( ! authenticating_ ) && finds( ss.str(), "407" ) )
00147             {
00148                 if ( finds( ss.str(), "Proxy-Authenticate: Basic" ) )
00149                 {
00150                     authenticating_ = true;
00151                     socket_.close();
00152 
00153                     do_connect( );
00154                 }
00155                 else //TODO: digest authentication support here
00156                     manager_->handle_proxy_connection( ana::generic_error, conn_handler_, timer_);
00157 
00158             }
00159             else //Can't connect, wrong password or wasn't offered the possibility to authenticate
00160                 manager_->handle_proxy_connection( ana::generic_error, conn_handler_, timer_);
00161         }
00162     }
00163 }
00164 
00165 void proxy_connection::handle_sent_request(const boost::system::error_code& /*ec*/,
00166                                            std::string*                     request)
00167 {
00168     delete request;
00169 
00170     boost::asio::streambuf* buf = new boost::asio::streambuf( );
00171 
00172     boost::asio::async_read_until(socket_, *buf,
00173                                   "\r\n\r\n",
00174                                   boost::bind(&proxy_connection::handle_response, this,
00175                                               buf, boost::asio::placeholders::error,_2));
00176 }
00177 
00178 void proxy_connection::handle_connect(const boost::system::error_code& ec,
00179                                       tcp::resolver::iterator          endpoint_iterator)
00180 {
00181     if ( ! ec )
00182     {
00183         std::string* request( NULL );
00184 
00185         if ( authenticating_ )
00186             request = generate_base64_credentials();
00187         else
00188             request = generate_connect_request();
00189 
00190         socket_.async_send(boost::asio::buffer( *request ),
00191                                  boost::bind(&proxy_connection::handle_sent_request,this,
00192                                              boost::asio::placeholders::error,
00193                                              request));
00194     }
00195     else
00196     {
00197         if ( endpoint_iterator == tcp::resolver::iterator() ) // could not connect to proxy
00198             manager_->handle_proxy_connection( ec, conn_handler_, timer_ );
00199         else
00200         {
00201             //retry
00202             socket_.close();
00203 
00204             tcp::endpoint endpoint = *endpoint_iterator;
00205             socket_.async_connect(endpoint,
00206                                 boost::bind(&proxy_connection::handle_connect, this,
00207                                             boost::asio::placeholders::error, ++endpoint_iterator));
00208         }
00209     }
00210 }
00211 
00212 void proxy_connection::do_connect()
00213 {
00214     try
00215     {
00216         tcp::resolver resolver( socket_.get_io_service() );
00217         tcp::resolver::query query(proxy_info_.proxy_address.c_str(),
00218                                    proxy_info_.proxy_port.c_str() );
00219         tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
00220 
00221         tcp::endpoint endpoint = *endpoint_iterator;
00222 
00223         socket_.async_connect(endpoint,
00224                               boost::bind(&proxy_connection::handle_connect, this,
00225                                           boost::asio::placeholders::error, ++endpoint_iterator));
00226     }
00227     catch (const std::exception&)
00228     {
00229         manager_->handle_proxy_connection(ana::generic_error, conn_handler_, timer_ );
00230     }
00231 }
00232 
00233 void proxy_connection::connect( proxy_connection_manager* manager,
00234                                 ana::connection_handler* handler )
00235 {
00236     manager_        = manager;
00237     conn_handler_   = handler;
00238     authenticating_ = false;
00239 
00240     do_connect();
00241 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Tue May 22 2012 01:03:40 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs