network_ana.cpp

Go to the documentation of this file.
00001 /* $Id: network_ana.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 
00003 /**
00004  * @file
00005  * @brief Network API implementation using ana.
00006  *
00007  * Copyright (C) 2010 - 2012 Guillermo Biset.
00008  *
00009  * Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014    (at your option) any later version.
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY.
00017  *
00018  * See the COPYING file for more details.
00019  */
00020 
00021 #include "network.hpp"
00022 #include "network_manager_ana.hpp"
00023 
00024 #include "global.hpp"
00025 
00026 #include "config.hpp"
00027 
00028 #include "gettext.hpp"
00029 #include "log.hpp"
00030 #include "serialization/string_utils.hpp"
00031 #include "serialization/parser.hpp"
00032 #include "thread.hpp"
00033 #include "util.hpp"
00034 
00035 #include "filesystem.hpp"
00036 
00037 #include <cerrno>
00038 #include <queue>
00039 #include <iomanip>
00040 #include <set>
00041 #include <cstring>
00042 
00043 #include <signal.h>
00044 #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
00045 #undef INADDR_ANY
00046 #undef INADDR_BROADCAST
00047 #undef INADDR_NONE
00048 #include <windows.h>
00049 #else
00050 #include <sys/types.h>
00051 #include <sys/socket.h>
00052 #include <netinet/in.h>
00053 #include <netinet/tcp.h>  // for TCP_NODELAY
00054 #ifdef __BEOS__
00055 #include <socket.h>
00056 #else
00057 #include <fcntl.h>
00058 #endif
00059 #define SOCKET int
00060 #endif
00061 
00062 static lg::log_domain log_network("network");
00063 #define DBG_NW LOG_STREAM(debug, log_network)
00064 #define LOG_NW LOG_STREAM(info, log_network)
00065 #define WRN_NW LOG_STREAM(warn, log_network)
00066 #define ERR_NW LOG_STREAM(err, log_network)
00067 // Only warnings and not errors to avoid DoS by log flooding
00068 namespace
00069 {
00070     ana_network_manager        ana_manager;
00071     network::bandwidth_in_ptr  global_bandwidth_in_ptr( new network::bandwidth_in(4) );
00072     //TODO: no global bandwidth
00073 
00074     size_t instances_using_the_network_module( 0 );
00075 } // end namespace
00076 
00077 namespace network {
00078 
00079     /**
00080     * Amount of seconds after the last server ping when we assume to have timed out.
00081     * When set to '0' ping timeout isn't checked.
00082     * Gets set in preferences::manager according to the preferences file.
00083     */
00084     unsigned int ping_timeout = 0;
00085 
00086     connection_stats::connection_stats(int sent, int received, int connected_at)
00087         : bytes_sent(sent), bytes_received(received), time_connected(0 - connected_at)
00088                                                         // TODO: s/SDLGetTicks/0/
00089     {
00090     }
00091 
00092     connection_stats get_connection_stats(connection connection_num)
00093     {
00094         const ana::stats* stats = ana_manager.get_stats( connection_num );
00095 
00096         if ( stats == NULL )
00097             throw std::runtime_error("Invalid connection ID to get stats from.");
00098         else
00099             return connection_stats( stats->bytes_out(),
00100                                      stats->bytes_in(),
00101                                      stats->uptime() );
00102     }
00103 
00104     error::error(const std::string& msg, connection sock) : game::error(msg), socket(sock)
00105     {
00106     }
00107 
00108     void error::disconnect()
00109     {
00110     }
00111 
00112     // --- Proxy methods
00113     void enable_connection_through_proxy()
00114     {
00115         ana_manager.enable_connection_through_proxy();
00116     }
00117     void set_proxy_address ( const std::string& address  )
00118     {
00119         ana_manager.set_proxy_address( address );
00120     }
00121 
00122     void set_proxy_port    ( const std::string& port     )
00123     {
00124         ana_manager.set_proxy_port( port );
00125     }
00126 
00127     void set_proxy_user    ( const std::string& user     )
00128     {
00129         ana_manager.set_proxy_user( user );
00130     }
00131 
00132     void set_proxy_password( const std::string& password )
00133     {
00134         ana_manager.set_proxy_password( password );
00135     }
00136     // --- End Proxy methods
00137 
00138 
00139     pending_statistics get_pending_stats()
00140     {
00141         //TODO: implement this feature, this is only to avoid segfaults when /query netstats is sent
00142         pending_statistics result;
00143 
00144         result.npending_sends       = 0;
00145         result.nbytes_pending_sends = 0;
00146 
00147         return result;
00148     }
00149 
00150     manager::manager(size_t /*min_threads*/, size_t /*max_threads*/) : free_(true)
00151     {
00152         ++instances_using_the_network_module;
00153     }
00154 
00155     manager::~manager()
00156     {
00157         if ( --instances_using_the_network_module == 0 )
00158             ana_manager.close_connections_and_cleanup();
00159     }
00160 
00161     void set_raw_data_only()
00162     {
00163     }
00164 
00165     server_manager::server_manager(int port, CREATE_SERVER create_server)
00166         : free_(false),
00167           connection_(0)
00168     {
00169         if ( create_server != NO_SERVER )
00170         {
00171             ana::net_id server_id = ana_manager.create_server( );
00172             ana_manager.run_server( server_id, port);
00173         }
00174     }
00175 
00176     server_manager::~server_manager()
00177     {
00178     }
00179 
00180     void server_manager::stop()
00181     {
00182         throw std::runtime_error("TODO:Not implemented stop");
00183     }
00184 
00185     bool server_manager::is_running() const
00186     {
00187         throw std::runtime_error("TODO:Not implemented is_running");
00188     }
00189 
00190     size_t nconnections()
00191     {
00192         return ana_manager.number_of_connections();
00193     }
00194 
00195     bool is_server()
00196     {
00197         throw std::runtime_error("TODO:Not implemented is_server");
00198     }
00199 
00200     connection connect(const std::string& host, int port)
00201     {
00202         return ana_manager.create_client_and_connect( host, port );
00203     }
00204 
00205     connection connect(const std::string& host, int port, threading::waiter& /*waiter*/)
00206     {
00207         return connect(host,port);
00208     }
00209 
00210     connection accept_connection()
00211     {
00212         return ana_manager.new_connection_id();
00213     }
00214 
00215     bool disconnect(connection handle)
00216     {
00217         return ana_manager.disconnect( handle );
00218     }
00219 
00220     void queue_disconnect(network::connection handle )
00221     {
00222         ana_manager.disconnect( handle );
00223     }
00224 
00225     connection receive_data(config&           cfg,
00226                             connection        connection_num,
00227                             unsigned int      timeout,
00228                             bandwidth_in_ptr* bandwidth_in)
00229     {
00230         ana_manager.throw_if_pending_disconnection();
00231 
00232         //TODO: temporary fix
00233         if ( bandwidth_in != NULL )
00234             *bandwidth_in = global_bandwidth_in_ptr;
00235 
00236         network::connection read_id = ana_manager.read_from( connection_num, cfg, timeout );
00237 
00238         // TODO: check timeout and return 0, or throw if error occurred
00239 
00240         return read_id;
00241     }
00242 
00243     connection receive_data(config&           cfg,
00244                             connection        connection_num,
00245                             bandwidth_in_ptr* bandwidth_in) // TODO: use this pointer
00246     {
00247         // <- just call the previous version without timeouts
00248         return receive_data(cfg,connection_num, static_cast<unsigned>(0), bandwidth_in);
00249     }
00250 
00251     connection receive_data(std::vector<char>& buf, bandwidth_in_ptr* bandwidth_in)
00252     {
00253         ana_manager.throw_if_pending_disconnection();
00254 
00255         //TODO: temporary fix
00256         if ( bandwidth_in != NULL )
00257             *bandwidth_in = global_bandwidth_in_ptr;
00258 
00259         return ana_manager.read_from_all( buf );
00260     }
00261 
00262 
00263     void add_bandwidth_out(const std::string& /*packet_type*/, size_t /*len*/)
00264     {
00265         //TODO: implement? (apparently called from network_worker only
00266     }
00267 
00268     void add_bandwidth_in(const std::string& /*packet_type*/, size_t /*len*/)
00269     {
00270         //TODO: implement? (apparently called from network_worker only
00271     }
00272 
00273 
00274     std::string get_bandwidth_stats_all()
00275     {
00276         //TODO: packet_type and widths should be modifiable
00277         const char*  packet_type  = "network";
00278 
00279         const size_t field_width  = 8;
00280         const size_t packet_width = 8;
00281         const size_t bytes_width  = 8;
00282 
00283         const ana::stats* stats = ana_manager.get_stats( );
00284 
00285         std::stringstream ss;
00286         ss  << " " << std::setw(field_width) <<  packet_type << "| "
00287             << std::setw(packet_width)<< stats->packets_out()<< "| "
00288             << std::setw(bytes_width) << stats->bytes_out() /1024 << "| "
00289             << std::setw(packet_width)<< stats->packets_in()<< "| "
00290             << std::setw(bytes_width) << stats->bytes_in() /1024 << "\n";
00291 
00292         return ss.str();
00293     }
00294 
00295     std::string get_bandwidth_stats()
00296     {
00297         //TODO: packet_type and widths should be modifiable
00298         const char*  packet_type  = "network";
00299 
00300         const size_t field_width  = 8;
00301         const size_t packet_width = 8;
00302         const size_t bytes_width  = 8;
00303 
00304         const ana::stats* stats = ana_manager.get_stats( 0, ana::HOURS );
00305 
00306 
00307         std::stringstream ss;
00308         ss  << " " << std::setw(field_width) <<  packet_type << "| "
00309             << std::setw(packet_width)<< stats->packets_out()<< "| "
00310             << std::setw(bytes_width) << stats->bytes_out() /1024 << "| "
00311             << std::setw(packet_width)<< stats->packets_in()<< "| "
00312             << std::setw(bytes_width) << stats->bytes_in() /1024 << "\n";
00313 
00314         return ss.str();
00315     }
00316 
00317     std::string get_bandwidth_stats(int /*hour*/)
00318     {
00319         return std::string(""); //TODO: implement
00320     }
00321 
00322     bandwidth_in::~bandwidth_in()
00323     {
00324     }
00325 
00326     void send_file(const std::string& /*filename*/,
00327                    connection /*connection_num*/,
00328                    const std::string& /*packet_type*/)
00329     {
00330         throw std::runtime_error("TODO:Not implemented send_file");
00331     }
00332 
00333     size_t send_data(const config&                cfg,
00334                      connection                   connection_num,
00335                      const std::string&           /*packet_type*/)
00336     {
00337         if(cfg.empty())
00338             return 0;
00339 
00340         if( connection_num == 0 )
00341             return ana_manager.send_all( cfg );
00342         else
00343             return ana_manager.send( connection_num, cfg );
00344     }
00345 
00346     void send_raw_data(const char*        buf,
00347                        int                len,
00348                        connection         connection_num,
00349                        const std::string& /*packet_type*/)
00350     {
00351         ana_manager.send_raw_data( buf, size_t( len ), connection_num );
00352     }
00353 
00354     void process_send_queue(connection, size_t)
00355     {
00356         ana_manager.throw_if_pending_disconnection();
00357     }
00358 
00359     void send_data_all_except(const config&       cfg,
00360                               connection          connection_num,
00361                               const std::string&  /*packet_type*/)
00362     {
00363         ana_manager.send_all_except(cfg, connection_num);
00364     }
00365 
00366     std::string ip_address(connection connection_num)
00367     {
00368         return ana_manager.ip_address( connection_num );
00369     }
00370 
00371     statistics get_send_stats(connection handle)
00372     {
00373         return ana_manager.get_send_stats( handle );
00374     }
00375 
00376     statistics get_receive_stats(connection handle)
00377     {
00378         return ana_manager.get_receive_stats( handle );
00379     }
00380 }// end namespace network
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:07 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs