00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "global.hpp"
00022
00023 #include "gettext.hpp"
00024 #include "log.hpp"
00025 #include "network_worker.hpp"
00026 #include "serialization/string_utils.hpp"
00027 #include "thread.hpp"
00028 #include "util.hpp"
00029 #include "config.hpp"
00030
00031 #include "filesystem.hpp"
00032
00033
00034 #include <cerrno>
00035 #include <queue>
00036 #include <iomanip>
00037 #include <set>
00038 #include <cstring>
00039 #include <stdexcept>
00040
00041 #include <signal.h>
00042 #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
00043 #undef INADDR_ANY
00044 #undef INADDR_BROADCAST
00045 #undef INADDR_NONE
00046 #include <windows.h>
00047 #else
00048 #include <sys/types.h>
00049 #include <sys/socket.h>
00050 #include <netinet/in.h>
00051 #include <netinet/tcp.h>
00052 #ifdef __BEOS__
00053 #include <socket.h>
00054 #else
00055 #include <fcntl.h>
00056 #endif
00057 #define SOCKET int
00058 #endif
00059
00060 static lg::log_domain log_network("network");
00061 #define DBG_NW LOG_STREAM(debug, log_network)
00062 #define LOG_NW LOG_STREAM(info, log_network)
00063 #define WRN_NW LOG_STREAM(warn, log_network)
00064 #define ERR_NW LOG_STREAM(err, log_network)
00065
00066
00067 namespace {
00068
00069
00070
00071
00072 struct connection_details {
00073 connection_details(TCPsocket sock, const std::string& host, int port)
00074 : sock(sock), host(host), port(port), remote_handle(0),
00075 connected_at(SDL_GetTicks())
00076 {}
00077
00078 TCPsocket sock;
00079 std::string host;
00080 int port;
00081
00082
00083
00084 int remote_handle;
00085
00086 int connected_at;
00087 };
00088
00089 typedef std::map<network::connection,connection_details> connection_map;
00090 connection_map connections;
00091
00092 network::connection connection_id = 1;
00093
00094
00095 time_t last_ping, last_ping_check = 0;
00096
00097 }
00098
00099 static int create_connection(TCPsocket sock, const std::string& host, int port)
00100 {
00101 connections.insert(std::pair<network::connection,connection_details>(connection_id,connection_details(sock,host,port)));
00102 return connection_id++;
00103 }
00104
00105 static connection_details& get_connection_details(network::connection handle)
00106 {
00107 const connection_map::iterator i = connections.find(handle);
00108 if(i == connections.end()) {
00109 throw network::error(_("invalid network handle"));
00110 }
00111
00112 return i->second;
00113 }
00114
00115 static TCPsocket get_socket(network::connection handle)
00116 {
00117 return get_connection_details(handle).sock;
00118 }
00119
00120 static void remove_connection(network::connection handle)
00121 {
00122 connections.erase(handle);
00123 }
00124
00125 static bool is_pending_remote_handle(network::connection handle)
00126 {
00127 const connection_details& details = get_connection_details(handle);
00128 return details.host != "" && details.remote_handle == 0;
00129 }
00130
00131 static void set_remote_handle(network::connection handle, int remote_handle)
00132 {
00133 get_connection_details(handle).remote_handle = remote_handle;
00134 }
00135
00136 static void check_error()
00137 {
00138 const TCPsocket sock = network_worker_pool::detect_error();
00139 if(sock) {
00140 for(connection_map::const_iterator i = connections.begin(); i != connections.end(); ++i) {
00141 if(i->second.sock == sock) {
00142 throw network::error(_("Client disconnected"),i->first);
00143 }
00144 }
00145 }
00146 }
00147
00148
00149
00150
00151
00152
00153
00154 static void check_timeout()
00155 {
00156 if (network::nconnections() == 0) {
00157 LOG_NW << "No network connections but last_ping is: " << last_ping;
00158 last_ping = 0;
00159 return;
00160 }
00161 const time_t& now = time(NULL);
00162 DBG_NW << "Last ping: '" << last_ping << "' Current time: '" << now
00163 << "' Time since last ping: " << now - last_ping << "s\n";
00164
00165 if (last_ping_check + 10 <= now) last_ping = now;
00166 if (static_cast<time_t>(last_ping + network::ping_interval + network::ping_timeout) <= now) {
00167
00168 time_t timeout = now - last_ping;
00169 ERR_NW << "No server ping since " << timeout
00170 << " seconds. Connection timed out.\n";
00171 utils::string_map symbols;
00172 symbols["timeout"] = lexical_cast<std::string>(timeout);
00173 throw network::error(std::string("No server ping since " + lexical_cast<std::string>(timeout) + " second. "
00174 "Connection timed out."));
00175 }
00176 last_ping_check = now;
00177 }
00178
00179
00180 namespace {
00181
00182 SDLNet_SocketSet socket_set = 0;
00183 std::set<network::connection> waiting_sockets;
00184 typedef std::vector<network::connection> sockets_list;
00185 sockets_list sockets;
00186
00187
00188 struct partial_buffer {
00189 partial_buffer() :
00190 buf(),
00191 upto(0)
00192 {
00193 }
00194
00195 std::vector<char> buf;
00196 size_t upto;
00197 };
00198
00199 TCPsocket server_socket;
00200
00201 std::deque<network::connection> disconnection_queue;
00202 std::set<network::connection> bad_sockets;
00203
00204 network_worker_pool::manager* worker_pool_man = NULL;
00205
00206 }
00207
00208 namespace network {
00209
00210
00211
00212
00213
00214
00215 unsigned int ping_timeout = 0;
00216
00217 connection_stats::connection_stats(int sent, int received, int connected_at)
00218 : bytes_sent(sent), bytes_received(received), time_connected(SDL_GetTicks() - connected_at)
00219 {}
00220
00221 connection_stats get_connection_stats(connection connection_num)
00222 {
00223 connection_details& details = get_connection_details(connection_num);
00224 return connection_stats(get_send_stats(connection_num).total,get_receive_stats(connection_num).total,details.connected_at);
00225 }
00226
00227 error::error(const std::string& msg, connection sock) : game::error(msg), socket(sock)
00228 {
00229 if(socket) {
00230 bad_sockets.insert(socket);
00231 }
00232 }
00233
00234 void error::disconnect()
00235 {
00236 if(socket) network::disconnect(socket);
00237 }
00238
00239 pending_statistics get_pending_stats()
00240 {
00241 return network_worker_pool::get_pending_stats();
00242 }
00243
00244 manager::manager(size_t min_threads, size_t max_threads) : free_(true)
00245 {
00246 DBG_NW << "NETWORK MANAGER CALLED!\n";
00247
00248 if(socket_set) {
00249 free_ = false;
00250 return;
00251 }
00252
00253 if(SDLNet_Init() == -1) {
00254 ERR_NW << "could not initialize SDLNet; throwing error...\n";
00255 throw error(SDL_GetError());
00256 }
00257
00258 socket_set = SDLNet_AllocSocketSet(512);
00259
00260 worker_pool_man = new network_worker_pool::manager(min_threads, max_threads);
00261 }
00262
00263 manager::~manager()
00264 {
00265 if(free_) {
00266 disconnect();
00267 delete worker_pool_man;
00268 worker_pool_man = NULL;
00269 SDLNet_FreeSocketSet(socket_set);
00270 socket_set = 0;
00271 waiting_sockets.clear();
00272 SDLNet_Quit();
00273 }
00274 }
00275
00276 void set_raw_data_only()
00277 {
00278 network_worker_pool::set_raw_data_only();
00279 }
00280
00281
00282 void enable_connection_through_proxy()
00283 {
00284 throw std::runtime_error("Proxy not available while using SDL_net. Use ANA instead.");
00285 }
00286 void set_proxy_address ( const std::string& )
00287 {
00288 throw std::runtime_error("Proxy not available while using SDL_net. Use ANA instead.");
00289 }
00290
00291 void set_proxy_port ( const std::string& )
00292 {
00293 throw std::runtime_error("Proxy not available while using SDL_net. Use ANA instead.");
00294 }
00295
00296 void set_proxy_user ( const std::string& )
00297 {
00298 throw std::runtime_error("Proxy not available while using SDL_net. Use ANA instead.");
00299 }
00300
00301 void set_proxy_password( const std::string& )
00302 {
00303 throw std::runtime_error("Proxy not available while using SDL_net. Use ANA instead.");
00304 }
00305
00306
00307 server_manager::server_manager(int port, CREATE_SERVER create_server) : free_(false), connection_(0)
00308 {
00309 if(create_server != NO_SERVER && !server_socket) {
00310 try {
00311 connection_ = connect("",port);
00312 server_socket = get_socket(connection_);
00313 } catch(network::error&) {
00314 if(create_server == MUST_CREATE_SERVER) {
00315 throw;
00316 } else {
00317 return;
00318 }
00319 }
00320
00321 DBG_NW << "server socket initialized: " << server_socket << "\n";
00322 free_ = true;
00323 }
00324 }
00325
00326 server_manager::~server_manager()
00327 {
00328 stop();
00329 }
00330
00331 void server_manager::stop()
00332 {
00333 if(free_) {
00334 SDLNet_TCP_Close(server_socket);
00335 remove_connection(connection_);
00336 server_socket = 0;
00337 free_ = false;
00338 }
00339 }
00340
00341 bool server_manager::is_running() const
00342 {
00343 return server_socket != NULL;
00344 }
00345
00346 size_t nconnections()
00347 {
00348 return sockets.size();
00349 }
00350
00351 bool is_server()
00352 {
00353 return server_socket != 0;
00354 }
00355
00356 namespace {
00357
00358 class connect_operation : public threading::async_operation
00359 {
00360 public:
00361 connect_operation(const std::string& host, int port) : host_(host), port_(port), error_(), connect_(0)
00362 {}
00363
00364 void check_error();
00365 void run();
00366
00367 network::connection result() const { return connect_; }
00368
00369 private:
00370 std::string host_;
00371 int port_;
00372 std::string error_;
00373 network::connection connect_;
00374 };
00375
00376 void connect_operation::check_error()
00377 {
00378 if(!error_.empty()) {
00379 throw error(error_);
00380 }
00381 }
00382
00383 namespace {
00384 struct _TCPsocket {
00385 int ready;
00386 SOCKET channel;
00387 IPaddress remoteAddress;
00388 IPaddress localAddress;
00389 int sflag;
00390 };
00391 }
00392
00393 void connect_operation::run()
00394 {
00395 char* const hostname = host_.empty() ? NULL : const_cast<char*>(host_.c_str());
00396 IPaddress ip;
00397 if(SDLNet_ResolveHost(&ip,hostname,port_) == -1) {
00398 error_ = N_("Could not connect to host.");
00399 return;
00400 }
00401
00402 TCPsocket sock = SDLNet_TCP_Open(&ip);
00403 if(!sock) {
00404 error_ = hostname == NULL
00405 ? "Could not bind to port"
00406 : N_("Could not connect to host.");
00407 return;
00408 }
00409 _TCPsocket* raw_sock = reinterpret_cast<_TCPsocket*>(sock);
00410 #ifdef TCP_NODELAY
00411
00412
00413 {
00414 int no = 0;
00415 setsockopt(raw_sock->channel, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&no), sizeof(no));
00416 }
00417 #endif
00418
00419
00420 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
00421 {
00422 unsigned long mode = 1;
00423 ioctlsocket (raw_sock->channel, FIONBIO, &mode);
00424 }
00425 #elif !defined(__BEOS__)
00426 int flags;
00427 flags = fcntl(raw_sock->channel, F_GETFL, 0);
00428 #if defined(O_NONBLOCK)
00429 flags |= O_NONBLOCK;
00430 #elif defined(O_NDELAY)
00431 flags |= O_NDELAY;
00432 #elif defined(FNDELAY)
00433 flags |= FNDELAY;
00434 #endif
00435 if (fcntl(raw_sock->channel, F_SETFL, flags) == -1) {
00436 error_ = "Could not make socket non-blocking: " + std::string(strerror(errno));
00437 SDLNet_TCP_Close(sock);
00438 return;
00439 }
00440 #else
00441 int on = 1;
00442 if (setsockopt(raw_sock->channel, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0) {
00443 error_ = "Could not make socket non-blocking: " + std::string(strerror(errno));
00444 SDLNet_TCP_Close(sock);
00445 return;
00446 }
00447
00448 int fd_flags = fcntl(raw_sock->channel, F_GETFD, 0);
00449 fd_flags |= FD_CLOEXEC;
00450 if (fcntl(raw_sock->channel, F_SETFD, fd_flags) == -1) {
00451 WRN_NW << "could not make socket " << sock << " close-on-exec: " << strerror(errno);
00452 } else {
00453 DBG_NW << "made socket " << sock << " close-on-exec\n";
00454 }
00455 #endif
00456
00457
00458 if(hostname == NULL) {
00459 const threading::lock l(get_mutex());
00460 connect_ = create_connection(sock,"",port_);
00461 return;
00462 }
00463
00464
00465 union
00466 {
00467 char data[4] ALIGN_4;
00468 Uint32 num;
00469 } buf;
00470 SDLNet_Write32(0, &buf);
00471 const int nbytes = SDLNet_TCP_Send(sock,&buf,4);
00472 if(nbytes != 4) {
00473 SDLNet_TCP_Close(sock);
00474 error_ = "Could not send initial handshake";
00475 return;
00476 }
00477
00478
00479 const threading::lock l(get_mutex());
00480 DBG_NW << "sent handshake...\n";
00481
00482 if(is_aborted()) {
00483 DBG_NW << "connect operation aborted by calling thread\n";
00484 SDLNet_TCP_Close(sock);
00485 return;
00486 }
00487
00488
00489 connect_ = create_connection(sock,host_,port_);
00490
00491 const int res = SDLNet_TCP_AddSocket(socket_set,sock);
00492 if(res == -1) {
00493 SDLNet_TCP_Close(sock);
00494 error_ = "Could not add socket to socket set";
00495 return;
00496 }
00497
00498 waiting_sockets.insert(connect_);
00499
00500 sockets.push_back(connect_);
00501
00502 while(!notify_finished()) {};
00503 }
00504
00505
00506 }
00507
00508
00509 connection connect(const std::string& host, int port)
00510 {
00511 connect_operation op(host,port);
00512 op.run();
00513 op.check_error();
00514 return op.result();
00515 }
00516
00517 connection connect(const std::string& host, int port, threading::waiter& waiter)
00518 {
00519 const threading::async_operation_ptr op(new connect_operation(host,port));
00520 const connect_operation::RESULT res = op->execute(op, waiter);
00521 if(res == connect_operation::ABORTED) {
00522 return 0;
00523 }
00524
00525 static_cast<connect_operation*>(op.get())->check_error();
00526 return static_cast<connect_operation*>(op.get())->result();
00527 }
00528
00529 namespace {
00530
00531 connection accept_connection_pending(std::vector<TCPsocket>& pending_sockets,
00532 SDLNet_SocketSet& pending_socket_set)
00533 {
00534 DBG_NW << "pending socket activity...\n";
00535
00536 std::vector<TCPsocket>::iterator i = pending_sockets.begin();
00537 while (i != pending_sockets.end() && !SDLNet_SocketReady(*i)) ++i;
00538
00539 if (i == pending_sockets.end()) return 0;
00540
00541
00542
00543 union
00544 {
00545 char data[4] ALIGN_4;
00546 Uint32 num;
00547 } buf;
00548
00549 const TCPsocket psock = *i;
00550 SDLNet_TCP_DelSocket(pending_socket_set,psock);
00551 pending_sockets.erase(i);
00552
00553 DBG_NW << "receiving data from pending socket...\n";
00554
00555 const int len = SDLNet_TCP_Recv(psock,&buf,4);
00556 if(len != 4) {
00557 WRN_NW << "pending socket disconnected\n";
00558 SDLNet_TCP_Close(psock);
00559 return 0;
00560 }
00561
00562 const int handle = SDLNet_Read32(&buf);
00563
00564 DBG_NW << "received handshake from client: '" << handle << "'\n";
00565
00566 const int res = SDLNet_TCP_AddSocket(socket_set,psock);
00567 if(res == -1) {
00568 ERR_NW << "SDLNet_GetError() is " << SDLNet_GetError() << "\n";
00569 SDLNet_TCP_Close(psock);
00570
00571 throw network::error(_("Could not add socket to socket set"));
00572 }
00573
00574 const connection connect = create_connection(psock,"",0);
00575
00576
00577 SDLNet_Write32(connect, &buf);
00578 const int nbytes = SDLNet_TCP_Send(psock,&buf,4);
00579 if(nbytes != 4) {
00580 SDLNet_TCP_DelSocket(socket_set,psock);
00581 SDLNet_TCP_Close(psock);
00582 remove_connection(connect);
00583 throw network::error(_("Could not send initial handshake"));
00584 }
00585
00586 waiting_sockets.insert(connect);
00587 sockets.push_back(connect);
00588 return connect;
00589 }
00590
00591 }
00592
00593 connection accept_connection()
00594 {
00595 if(!server_socket) {
00596 return 0;
00597 }
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607 static std::vector<TCPsocket> pending_sockets;
00608 static SDLNet_SocketSet pending_socket_set = 0;
00609
00610 const TCPsocket sock = SDLNet_TCP_Accept(server_socket);
00611 if(sock) {
00612 #if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)
00613 _TCPsocket* raw_sock = reinterpret_cast<_TCPsocket*>(sock);
00614 int fd_flags = fcntl(raw_sock->channel, F_GETFD, 0);
00615 fd_flags |= FD_CLOEXEC;
00616 if (fcntl(raw_sock->channel, F_SETFD, fd_flags) == -1) {
00617 WRN_NW << "could not make socket " << sock << " close-on-exec: " << strerror(errno);
00618 } else {
00619 DBG_NW << "made socket " << sock << " close-on-exec\n";
00620 }
00621 #endif
00622
00623 DBG_NW << "received connection. Pending handshake...\n";
00624
00625 if(pending_socket_set == 0) {
00626 pending_socket_set = SDLNet_AllocSocketSet(32);
00627 }
00628
00629 if(pending_socket_set != 0) {
00630 int res = SDLNet_TCP_AddSocket(pending_socket_set,sock);
00631
00632 if (res != -1) {
00633 pending_sockets.push_back(sock);
00634 } else {
00635 ERR_NW << "Pending socket set is full! Disconnecting " << sock << " connection\n";
00636 ERR_NW << "SDLNet_GetError() is " << SDLNet_GetError() << "\n";
00637
00638 SDLNet_TCP_Close(sock);
00639 }
00640 } else {
00641 ERR_NW << "Error in SDLNet_AllocSocketSet\n";
00642 }
00643 }
00644
00645 if(pending_socket_set == 0) {
00646 return 0;
00647 }
00648
00649 const int set_res = SDLNet_CheckSockets(pending_socket_set,0);
00650 if(set_res <= 0) {
00651 return 0;
00652 }
00653
00654 return accept_connection_pending(pending_sockets, pending_socket_set);
00655 }
00656
00657 bool disconnect(connection s)
00658 {
00659 if(s == 0) {
00660 while(sockets.empty() == false) {
00661 assert(sockets.back() != 0);
00662 while(disconnect(sockets.back()) == false) {
00663 SDL_Delay(1);
00664 }
00665 }
00666 return true;
00667 }
00668 if (!is_server()) last_ping = 0;
00669
00670 const connection_map::iterator info = connections.find(s);
00671 if(info != connections.end()) {
00672 if (info->second.sock == server_socket)
00673 {
00674 return true;
00675 }
00676 if (!network_worker_pool::close_socket(info->second.sock)) {
00677 return false;
00678 }
00679 }
00680
00681 bad_sockets.erase(s);
00682
00683 std::deque<network::connection>::iterator dqi = std::find(disconnection_queue.begin(),disconnection_queue.end(),s);
00684 if(dqi != disconnection_queue.end()) {
00685 disconnection_queue.erase(dqi);
00686 }
00687
00688 const sockets_list::iterator i = std::find(sockets.begin(),sockets.end(),s);
00689 if(i != sockets.end()) {
00690 sockets.erase(i);
00691
00692 const TCPsocket sock = get_socket(s);
00693
00694 waiting_sockets.erase(s);
00695 SDLNet_TCP_DelSocket(socket_set,sock);
00696 SDLNet_TCP_Close(sock);
00697
00698 remove_connection(s);
00699 } else {
00700 if(sockets.size() == 1) {
00701 DBG_NW << "valid socket: " << static_cast<int>(*sockets.begin()) << "\n";
00702 }
00703 }
00704
00705 return true;
00706 }
00707
00708 void queue_disconnect(network::connection sock)
00709 {
00710 disconnection_queue.push_back(sock);
00711 }
00712
00713 connection receive_data(config& cfg, connection connection_num, unsigned int timeout, bandwidth_in_ptr* bandwidth_in)
00714 {
00715 unsigned int start_ticks = SDL_GetTicks();
00716 while(true) {
00717 const connection res = receive_data(
00718 cfg,connection_num, bandwidth_in);
00719 if(res != 0) {
00720 return res;
00721 }
00722
00723 if(timeout > SDL_GetTicks() - start_ticks) {
00724 SDL_Delay(1);
00725 }
00726 else
00727 {
00728 break;
00729 }
00730
00731 }
00732
00733 return 0;
00734 }
00735
00736 connection receive_data(config& cfg, connection connection_num, bandwidth_in_ptr* bandwidth_in)
00737 {
00738 if(!socket_set) {
00739 return 0;
00740 }
00741
00742 check_error();
00743
00744 if(disconnection_queue.empty() == false) {
00745 const network::connection sock = disconnection_queue.front();
00746 disconnection_queue.pop_front();
00747 throw error("",sock);
00748 }
00749
00750 if(bad_sockets.count(connection_num) || bad_sockets.count(0)) {
00751 return 0;
00752 }
00753
00754 if(sockets.empty()) {
00755 return 0;
00756 }
00757
00758 const int res = SDLNet_CheckSockets(socket_set,0);
00759
00760 for(std::set<network::connection>::iterator i = waiting_sockets.begin(); res != 0 && i != waiting_sockets.end(); ) {
00761 connection_details& details = get_connection_details(*i);
00762 const TCPsocket sock = details.sock;
00763 if(SDLNet_SocketReady(sock)) {
00764
00765
00766
00767 if(is_pending_remote_handle(*i)) {
00768 union {
00769 char data[4] ALIGN_4;
00770 } buf;
00771 int len = SDLNet_TCP_Recv(sock,&buf,4);
00772 if(len != 4) {
00773 throw error("Remote host disconnected",*i);
00774 }
00775
00776 const int remote_handle = SDLNet_Read32(&buf);
00777 set_remote_handle(*i,remote_handle);
00778
00779 continue;
00780 }
00781
00782 waiting_sockets.erase(i++);
00783 SDLNet_TCP_DelSocket(socket_set,sock);
00784 network_worker_pool::receive_data(sock);
00785 } else {
00786 ++i;
00787 }
00788 }
00789
00790
00791 TCPsocket sock = connection_num == 0 ? 0 : get_socket(connection_num);
00792 TCPsocket s = sock;
00793 bandwidth_in_ptr temp;
00794 if (!bandwidth_in)
00795 {
00796 bandwidth_in = &temp;
00797 }
00798 sock = network_worker_pool::get_received_data(sock,cfg, *bandwidth_in);
00799 if (sock == NULL) {
00800 if (!is_server() && last_ping != 0 && ping_timeout != 0)
00801 {
00802 if (connection_num == 0)
00803 {
00804 s = get_socket(sockets.back());
00805 }
00806 if (!network_worker_pool::is_locked(s))
00807 {
00808 check_timeout();
00809 }
00810 }
00811 return 0;
00812 }
00813
00814 int set_res = SDLNet_TCP_AddSocket(socket_set,sock);
00815 if (set_res == -1)
00816 {
00817 ERR_NW << "Socket set is full! Disconnecting " << sock << " connection\n";
00818 SDLNet_TCP_Close(sock);
00819 return 0;
00820 }
00821
00822 connection result = 0;
00823 for(connection_map::const_iterator j = connections.begin(); j != connections.end(); ++j) {
00824 if(j->second.sock == sock) {
00825 result = j->first;
00826 break;
00827 }
00828 }
00829 if(!cfg.empty()) {
00830 DBG_NW << "RECEIVED from: " << result << ": " << cfg;
00831 }
00832
00833 assert(result != 0);
00834 waiting_sockets.insert(result);
00835 if(!is_server()) {
00836 const time_t& now = time(NULL);
00837 if (cfg.has_attribute("ping")) {
00838 LOG_NW << "Lag: " << (now - lexical_cast<time_t>(cfg["ping"])) << "\n";
00839 last_ping = now;
00840 } else if (last_ping != 0) {
00841 last_ping = now;
00842 }
00843 }
00844 return result;
00845 }
00846
00847 connection receive_data(std::vector<char>& buf, bandwidth_in_ptr* bandwidth_in)
00848 {
00849 if(!socket_set) {
00850 return 0;
00851 }
00852
00853 check_error();
00854
00855 if(disconnection_queue.empty() == false) {
00856 const network::connection sock = disconnection_queue.front();
00857 disconnection_queue.pop_front();
00858 throw error("",sock);
00859 }
00860
00861 if(bad_sockets.count(0)) {
00862 return 0;
00863 }
00864
00865 if(sockets.empty()) {
00866 return 0;
00867 }
00868
00869 const int res = SDLNet_CheckSockets(socket_set,0);
00870
00871 for(std::set<network::connection>::iterator i = waiting_sockets.begin(); res != 0 && i != waiting_sockets.end(); ) {
00872 connection_details& details = get_connection_details(*i);
00873 const TCPsocket sock = details.sock;
00874 if(SDLNet_SocketReady(sock)) {
00875
00876
00877
00878 if(is_pending_remote_handle(*i)) {
00879 union {
00880 char data[4] ALIGN_4;
00881 } buf;
00882 int len = SDLNet_TCP_Recv(sock,&buf,4);
00883 if(len != 4) {
00884 throw error("Remote host disconnected",*i);
00885 }
00886
00887 const int remote_handle = SDLNet_Read32(&buf);
00888 set_remote_handle(*i,remote_handle);
00889
00890 continue;
00891 }
00892
00893 waiting_sockets.erase(i++);
00894 SDLNet_TCP_DelSocket(socket_set,sock);
00895 network_worker_pool::receive_data(sock);
00896 } else {
00897 ++i;
00898 }
00899 }
00900
00901
00902 TCPsocket sock = network_worker_pool::get_received_data(buf);
00903 if (sock == NULL) {
00904 return 0;
00905 }
00906
00907 {
00908 bandwidth_in_ptr temp;
00909 if (!bandwidth_in)
00910 {
00911 bandwidth_in = &temp;
00912 }
00913 const int headers = 4;
00914 bandwidth_in->reset(new network::bandwidth_in(buf.size() + headers));
00915 }
00916
00917 int set_res = SDLNet_TCP_AddSocket(socket_set,sock);
00918
00919 if (set_res == -1)
00920 {
00921 ERR_NW << "Socket set is full! Disconnecting " << sock << " connection\n";
00922 SDLNet_TCP_Close(sock);
00923 return 0;
00924 }
00925 connection result = 0;
00926 for(connection_map::const_iterator j = connections.begin(); j != connections.end(); ++j) {
00927 if(j->second.sock == sock) {
00928 result = j->first;
00929 break;
00930 }
00931 }
00932
00933 assert(result != 0);
00934 waiting_sockets.insert(result);
00935 return result;
00936 }
00937 struct bandwidth_stats {
00938 int out_packets;
00939 int out_bytes;
00940 int in_packets;
00941 int in_bytes;
00942 int day;
00943 const static size_t type_width = 16;
00944 const static size_t packet_width = 7;
00945 const static size_t bytes_width = 10;
00946 bandwidth_stats& operator+=(const bandwidth_stats& a)
00947 {
00948 out_packets += a.out_packets;
00949 out_bytes += a.out_bytes;
00950 in_packets += a.in_packets;
00951 in_bytes += a.in_bytes;
00952
00953 return *this;
00954 }
00955 };
00956 typedef std::map<const std::string, bandwidth_stats> bandwidth_map;
00957 typedef std::vector<bandwidth_map> hour_stats_vector;
00958 hour_stats_vector hour_stats(24);
00959
00960
00961
00962 static bandwidth_map::iterator add_bandwidth_entry(const std::string& packet_type)
00963 {
00964 time_t now = time(0);
00965 struct tm * timeinfo = localtime(&now);
00966 int hour = timeinfo->tm_hour;
00967 int day = timeinfo->tm_mday;
00968 assert(hour < 24 && hour >= 0);
00969 std::pair<bandwidth_map::iterator,bool> insertion = hour_stats[hour].insert(std::make_pair(packet_type, bandwidth_stats()));
00970 bandwidth_map::iterator inserted = insertion.first;
00971 if (!insertion.second && day != inserted->second.day)
00972 {
00973
00974 hour_stats[hour].clear();
00975
00976 insertion = hour_stats[hour].insert(std::make_pair(packet_type, bandwidth_stats()));
00977 inserted = insertion.first;
00978 }
00979
00980 inserted->second.day = day;
00981 return inserted;
00982 }
00983
00984 typedef boost::shared_ptr<bandwidth_stats> bandwidth_stats_ptr;
00985
00986
00987 struct bandwidth_stats_output {
00988 bandwidth_stats_output(std::stringstream& ss) : ss_(ss), totals_(new bandwidth_stats())
00989 {}
00990 void operator()(const bandwidth_map::value_type& stats)
00991 {
00992
00993 ss_ << " " << std::setw(bandwidth_stats::type_width) << stats.first << "| "
00994 << std::setw(bandwidth_stats::packet_width)<< stats.second.out_packets << "| "
00995 << std::setw(bandwidth_stats::bytes_width) << stats.second.out_bytes/1024 << "| "
00996 << std::setw(bandwidth_stats::packet_width)<< stats.second.in_packets << "| "
00997 << std::setw(bandwidth_stats::bytes_width) << stats.second.in_bytes/1024 << "\n";
00998 *totals_ += stats.second;
00999 }
01000 void output_totals()
01001 {
01002 (*this)(std::make_pair(std::string("total"), *totals_));
01003 }
01004 private:
01005 std::stringstream& ss_;
01006 bandwidth_stats_ptr totals_;
01007 };
01008
01009 std::string get_bandwidth_stats_all()
01010 {
01011 std::string result;
01012 for (int hour = 0; hour < 24; ++hour)
01013 {
01014 result += get_bandwidth_stats(hour);
01015 }
01016 return result;
01017 }
01018
01019 std::string get_bandwidth_stats()
01020 {
01021 time_t now = time(0);
01022 struct tm * timeinfo = localtime(&now);
01023 int hour = timeinfo->tm_hour - 1;
01024 if (hour < 0)
01025 hour = 23;
01026 return get_bandwidth_stats(hour);
01027 }
01028
01029 std::string get_bandwidth_stats(int hour)
01030 {
01031 assert(hour < 24 && hour >= 0);
01032 std::stringstream ss;
01033
01034 ss << "Hour stat starting from " << hour << "\n " << std::left << std::setw(bandwidth_stats::type_width) << "Type of packet" << "| "
01035 << std::setw(bandwidth_stats::packet_width)<< "out #" << "| "
01036 << std::setw(bandwidth_stats::bytes_width) << "out KiB" << "| "
01037 << std::setw(bandwidth_stats::packet_width)<< "in #" << "| "
01038 << std::setw(bandwidth_stats::bytes_width) << "in KiB" << "\n";
01039
01040 bandwidth_stats_output outputer(ss);
01041 std::for_each(hour_stats[hour].begin(), hour_stats[hour].end(), outputer);
01042
01043 outputer.output_totals();
01044 return ss.str();
01045 }
01046
01047 void add_bandwidth_out(const std::string& packet_type, size_t len)
01048 {
01049 bandwidth_map::iterator itor = add_bandwidth_entry(packet_type);
01050 itor->second.out_bytes += len;
01051 ++(itor->second.out_packets);
01052 }
01053
01054 void add_bandwidth_in(const std::string& packet_type, size_t len)
01055 {
01056 bandwidth_map::iterator itor = add_bandwidth_entry(packet_type);
01057 itor->second.in_bytes += len;
01058 ++(itor->second.in_packets);
01059 }
01060
01061 bandwidth_in::~bandwidth_in()
01062 {
01063 add_bandwidth_in(type_, len_);
01064 }
01065
01066 void send_file(const std::string& filename, connection connection_num, const std::string& packet_type)
01067 {
01068 assert(connection_num > 0);
01069 if(bad_sockets.count(connection_num) || bad_sockets.count(0)) {
01070 return;
01071 }
01072
01073 const connection_map::iterator info = connections.find(connection_num);
01074 if (info == connections.end()) {
01075 ERR_NW << "Error: socket: " << connection_num
01076 << "\tnot found in connection_map. Not sending...\n";
01077 return;
01078 }
01079
01080 const int packet_headers = 4;
01081 add_bandwidth_out(packet_type, file_size(filename) + packet_headers);
01082 network_worker_pool::queue_file(info->second.sock, filename);
01083
01084 }
01085
01086 size_t send_data(const config& cfg, connection connection_num, const std::string& packet_type)
01087 {
01088 DBG_NW << "in send_data()...\n";
01089
01090 if(cfg.empty()) {
01091 return 0;
01092 }
01093
01094 if(bad_sockets.count(connection_num) || bad_sockets.count(0)) {
01095 return 0;
01096 }
01097
01098
01099 if(!connection_num) {
01100 DBG_NW << "sockets: " << sockets.size() << "\n";
01101 size_t size = 0;
01102 for(sockets_list::const_iterator i = sockets.begin();
01103 i != sockets.end(); ++i) {
01104 DBG_NW << "server socket: " << server_socket << "\ncurrent socket: " << *i << "\n";
01105 size = send_data(cfg,*i, packet_type);
01106 }
01107 return size;
01108 }
01109
01110 const connection_map::iterator info = connections.find(connection_num);
01111 if (info == connections.end()) {
01112 ERR_NW << "Error: socket: " << connection_num
01113 << "\tnot found in connection_map. Not sending...\n";
01114 return 0;
01115 }
01116
01117 LOG_NW << "SENDING to: " << connection_num << ": " << cfg;
01118 return network_worker_pool::queue_data(info->second.sock, cfg, packet_type);
01119 }
01120
01121 void send_raw_data(const char* buf, int len, connection connection_num, const std::string& packet_type)
01122 {
01123 if(len == 0) {
01124 return;
01125 }
01126
01127 if(bad_sockets.count(connection_num) || bad_sockets.count(0)) {
01128 return;
01129 }
01130
01131 if(!connection_num) {
01132 for(sockets_list::const_iterator i = sockets.begin();
01133 i != sockets.end(); ++i) {
01134 send_raw_data(buf, len, *i, packet_type);
01135 }
01136 return;
01137 }
01138
01139 const connection_map::iterator info = connections.find(connection_num);
01140 if (info == connections.end()) {
01141 ERR_NW << "Error: socket: " << connection_num
01142 << "\tnot found in connection_map. Not sending...\n";
01143 return;
01144 }
01145 const int packet_headers = 4;
01146 add_bandwidth_out(packet_type, len + packet_headers);
01147
01148 network_worker_pool::queue_raw_data(info->second.sock, buf, len);
01149 }
01150
01151 void process_send_queue(connection, size_t)
01152 {
01153 check_error();
01154 }
01155
01156 void send_data_all_except(const config& cfg, connection connection_num, const std::string& packet_type)
01157 {
01158 for(sockets_list::const_iterator i = sockets.begin(); i != sockets.end(); ++i) {
01159 if(*i == connection_num) {
01160 continue;
01161 }
01162
01163 send_data(cfg,*i, packet_type);
01164 }
01165 }
01166
01167 std::string ip_address(connection connection_num)
01168 {
01169 std::stringstream str;
01170 const IPaddress* const ip = SDLNet_TCP_GetPeerAddress(get_socket(connection_num));
01171 if(ip != NULL) {
01172 const unsigned char* buf = reinterpret_cast<const unsigned char*>(&ip->host);
01173 for(int i = 0; i != sizeof(ip->host); ++i) {
01174 str << int(buf[i]);
01175 if(i+1 != sizeof(ip->host)) {
01176 str << '.';
01177 }
01178 }
01179
01180 }
01181
01182 return str.str();
01183 }
01184
01185 statistics get_send_stats(connection handle)
01186 {
01187 return network_worker_pool::get_current_transfer_stats(handle == 0 ? get_socket(sockets.back()) : get_socket(handle)).first;
01188 }
01189 statistics get_receive_stats(connection handle)
01190 {
01191 const statistics result = network_worker_pool::get_current_transfer_stats(handle == 0 ? get_socket(sockets.back()) : get_socket(handle)).second;
01192
01193 return result;
01194 }
01195
01196 }