OSDN Git Service

プロトコルバージョンを3に変更
[mmo/main.git] / server / Server.cpp
index 4e721ec..59e6912 100644 (file)
-//
-// Server.cpp
-//
-
-#include "Server.hpp"
-#include <algorithm>
-#include <boost/make_shared.hpp>
-#include "../common/Logger.hpp"
-#include "../common/network/Command.hpp"
-#include "../common/network/Utils.hpp"
-
-namespace network {
-
-    Server::Server(uint16_t port) :
-            endpoint_(tcp::v4(), port),
-            acceptor_(io_service_, endpoint_),
-            socket_udp_(io_service_, udp::endpoint(udp::v4(), port)),
-            udp_packet_count_(0),
-            max_total_read_average_(5000),
-            max_session_read_average_(600),
-            min_session_read_average_(100),
-            session_read_average_(200)
-    {
-    }
-
-    void Server::Start(CallbackFuncPtr callback)
-    {
-        callback_ = std::make_shared<CallbackFunc>(
-                [&](network::Command c){
-
-            // ログアウト
-            if (c.header() == network::header::FatalConnectionError) {
-                // 受信制限量を更新
-                /*
-                auto new_average = GetSessionReadAverageLimit();
-                if (session_read_average_ != new_average) {
-                    session_read_average_ = new_average;
-                    SendAll(network::ClientReceiveWriteAverageLimitUpdate(session_read_average_));
-                }
-                */
-            }
-
-            // 通信量制限を越えていた場合、強制的に切断
-            else if (auto session = c.session().lock()) {
-                if (session->GetReadByteAverage() > session_read_average_) {
-                                       Logger::Info(_T("Banished session: %d"), session->id());
-                    session->Close();
-                }
-            }
-
-            if (callback) {
-                (*callback)(c);
-            }
-        });
-
-        {
-        auto new_session = boost::make_shared<ServerSession>(io_service_);
-        acceptor_.async_accept(new_session->tcp_socket(),
-                              boost::bind(&Server::ReceiveSession, this, new_session, boost::asio::placeholders::error));
-        }
-
-        {
-            socket_udp_.async_receive_from(
-                boost::asio::buffer(receive_buf_udp_, UDP_MAX_RECEIVE_LENGTH), sender_endpoint_,
-                boost::bind(&Server::ReceiveUDP, this,
-                  boost::asio::placeholders::error,
-                  boost::asio::placeholders::bytes_transferred));
-        }
-
-        boost::asio::io_service::work work(io_service_);
-        io_service_.run();
-    }
-
-    void Server::Stop()
-    {
-        io_service_.stop();
-    }
-
-    bool Server::Empty() const
-    {
-        return sessions_.size() == 0;
-    }
-
-    void Server::ReceiveSession(const SessionPtr& session, const boost::system::error_code& error)
-    {
-        if (session_read_average_ > min_session_read_average_) {
-            session->set_on_receive(callback_);
-            session->Start();
-            sessions_.push_back(SessionWeakPtr(session));
-
-            // クライアント情報を要求
-            session->Send(ClientRequestedClientInfo());
-
-            // 受信制限量を更新
-            auto new_average = GetSessionReadAverageLimit();
-            session->Send(network::ClientReceiveWriteAverageLimitUpdate(session_read_average_));
-
-            if (session_read_average_ != new_average) {
-                session_read_average_ = new_average;
-                SendOthers(network::ClientReceiveWriteAverageLimitUpdate(session_read_average_),
-                        session);
-            }
-
-        } else {
-            Logger::Info("Refuse Session");
-            session->SyncSend(ClientReceiveServerCrowdedError());
-            session->Close();
-        }
-
-        auto new_session = boost::make_shared<ServerSession>(io_service_);
-         acceptor_.async_accept(new_session->tcp_socket(),
-                 boost::bind(&Server::ReceiveSession, this, new_session, boost::asio::placeholders::error));
-
-        // 使用済のセッションのポインタを破棄
-        auto it = std::remove_if(sessions_.begin(), sessions_.end(),
-                [](const SessionWeakPtr& ptr){
-            return ptr.expired();
-        });
-        sessions_.erase(it, sessions_.end());
-
-    }
-
-    void Server::SendAll(const Command& command)
-    {
-        BOOST_FOREACH(SessionWeakPtr& ptr, sessions_) {
-            if (auto session = ptr.lock()) {
-                session->Send(command);
-            }
-        }
-    }
-
-    void Server::SendOthers(const Command& command, SessionWeakPtr self_ptr)
-    {
-        BOOST_FOREACH(SessionWeakPtr& ptr, sessions_) {
-            if (auto session = ptr.lock()) {
-                if (auto self = self_ptr.lock()) {
-                    if (*session != *self) {
-                        session->Send(command);
-                    }
-                }
-            }
-        }
-    }
-
-    void Server::SendUDPTestPacket(const std::string& ip_address, uint16_t port)
-    {
-        using boost::asio::ip::udp;
-
-        std::stringstream port_str;
-        port_str << (int)port;
-
-        udp::resolver resolver(io_service_);
-        udp::resolver::query query(udp::v4(), ip_address.c_str(), port_str.str().c_str());
-        udp::resolver::iterator iterator = resolver.resolve(query);
-
-        static char request[] = "MMO UDP Test Packet";
-        for (int i = 0; i < UDP_TEST_PACKET_TIME; i++) {
-
-            io_service_.post(boost::bind(&Server::DoWriteUDP, this, request, *iterator));
-        }
-    }
-
-    void Server::ReceiveUDP(const boost::system::error_code& error, size_t bytes_recvd)
-    {
-        if (bytes_recvd > 0) {
-            std::string buffer(receive_buf_udp_, bytes_recvd);
-            FetchUDP(buffer);
-        }
-        if (!error) {
-          socket_udp_.async_receive_from(
-              boost::asio::buffer(receive_buf_udp_, UDP_MAX_RECEIVE_LENGTH), sender_endpoint_,
-              boost::bind(&Server::ReceiveUDP, this,
-                boost::asio::placeholders::error,
-                boost::asio::placeholders::bytes_transferred));
-        } else {
-            Logger::Error("%s", error.message());
-        }
-    }
-
-    void Server::DoWriteUDP(const std::string& msg, const udp::endpoint& endpoint)
-    {
-        boost::shared_ptr<std::string> s = 
-              boost::make_shared<std::string>(msg.data(), msg.size());
-
-        socket_udp_.async_send_to(
-            boost::asio::buffer(s->data(), s->size()), endpoint,
-            boost::bind(&Server::WriteUDP, this,
-              boost::asio::placeholders::error, s));
-    }
-
-    void Server::WriteUDP(const boost::system::error_code& error, boost::shared_ptr<std::string> holder)
-    {
-//        if (!error) {
-//            if (!send_queue_.empty()) {
-//                  send_queue_.pop();
-//                  if (!send_queue_.empty())
-//                  {
-//                    boost::asio::async_write(socket_tcp_,
-//                        boost::asio::buffer(send_queue_.front().data(),
-//                          send_queue_.front().size()),
-//                        boost::bind(&Session::WriteTCP, this,
-//                          boost::asio::placeholders::error));
-//                  }
-//            }
-//        } else {
-//            FatalError();
-//        }
-    }
-
-    Command Server::FetchUDP(const std::string& buffer)
-    {
-        uint32_t user_id;
-        unsigned char count;
-        header::CommandHeader header;
-        std::string body;
-        SessionPtr session;
-
-        size_t readed = network::Utils::Deserialize(buffer, &user_id, &count, &header);
-        if (readed < buffer.size()) {
-            body = buffer.substr(readed);
-        }
-
-        return Command(header, body, session);
-    }
-
-    void Server::ServerSession::Start()
-    {
-        online_ = true;
-
-        // Nagleアルゴリズムを無効化
-        socket_tcp_.set_option(boost::asio::ip::tcp::no_delay(true));
-
-        // IPアドレスを取得
-        global_ip_ = socket_tcp_.remote_endpoint().address().to_string();
-
-        boost::asio::async_read_until(socket_tcp_,
-            receive_buf_, NETWORK_UTILS_DELIMITOR,
-            boost::bind(
-              &ServerSession::ReceiveTCP, shared_from_this(),
-              boost::asio::placeholders::error));
-    }
-
-    int Server::GetSessionReadAverageLimit()
-    {
-        int byte = max_total_read_average_ / (sessions_.size() + 1);
-        byte = std::min(byte, max_session_read_average_);
-        
-        return byte;
-    }
-
-    int Server::max_total_read_average() const
-    {
-        return max_total_read_average_;
-    }
-
-    int Server::max_session_read_average() const
-    {
-        return max_session_read_average_;
-    }
-
-    int Server::min_session_read_average() const
-    {
-        return min_session_read_average_;
-    }
-
-    void Server::set_max_total_read_average(int byte)
-    {
-        max_total_read_average_ = byte;
-    }
-
-    void Server::set_max_session_read_average(int byte)
-    {
-        max_session_read_average_ = byte;
-    }
-
-    void Server::set_min_session_read_average(int byte)
-    {
-        min_session_read_average_ = byte;
-    }
-
-}
+//\r
+// Server.cpp\r
+//\r
+\r
+#include "Server.hpp"\r
+#include "version.hpp"\r
+#include <algorithm>\r
+#include <boost/make_shared.hpp>\r
+#include <boost/foreach.hpp>\r
+#include <boost/archive/text_oarchive.hpp>\r
+#include <boost/property_tree/ptree_serialization.hpp>\r
+#include "../common/Logger.hpp"\r
+#include "../common/network/Command.hpp"\r
+#include "../common/network/Utils.hpp"\r
+\r
+namespace network {\r
+\r
+    Server::Server() :\r
+            endpoint_(tcp::v4(), config_.port()),\r
+            acceptor_(io_service_, endpoint_),\r
+            socket_udp_(io_service_, udp::endpoint(udp::v4(), config_.port())),\r
+            udp_packet_count_(0),\r
+                       recent_chat_log_(10)\r
+    {\r
+    }\r
+\r
+    void Server::Start(CallbackFuncPtr callback)\r
+    {\r
+        callback_ = std::make_shared<CallbackFunc>(\r
+                [&](network::Command c){\r
+\r
+            // ログアウト\r
+            if (c.header() == network::header::FatalConnectionError || \r
+                               c.header() == network::header::UserFatalConnectionError) {\r
+                if (callback) {\r
+                                       (*callback)(c);\r
+                               }\r
+            } else if (auto session = c.session().lock()) {\r
+                               auto read_average = session->GetReadByteAverage();\r
+                               if (read_average > config_.receive_limit_2()) {\r
+                                       Logger::Info(_T("Banished a session: %d %dbyte/s"), session->id(), read_average);\r
+                                       session->Close();\r
+                               } else if(read_average > config_.receive_limit_1()) {\r
+                                       Logger::Info(_T("Receive limit exceeded: %d: %d byte/s"), session->id(), read_average);\r
+                               } else {\r
+                                       if (callback) {\r
+                                               (*callback)(c);\r
+                                       }\r
+                }\r
+            }\r
+\r
+        });\r
+\r
+               BOOST_FOREACH(const auto& host, config().lobby_servers()) {\r
+                       udp::resolver resolver(io_service_);\r
+                       udp::resolver::query query(udp::v4(), host.c_str(), "39380");\r
+                       lobby_hosts_.push_back(resolver.resolve(query));\r
+               }\r
+\r
+        {\r
+        auto new_session = boost::make_shared<ServerSession>(io_service_);\r
+        acceptor_.async_accept(new_session->tcp_socket(),\r
+                              boost::bind(&Server::ReceiveSession, this, new_session, boost::asio::placeholders::error));\r
+        }\r
+\r
+        {\r
+            socket_udp_.async_receive_from(\r
+                boost::asio::buffer(receive_buf_udp_, UDP_MAX_RECEIVE_LENGTH), sender_endpoint_,\r
+                boost::bind(&Server::ReceiveUDP, this,\r
+                  boost::asio::placeholders::error,\r
+                  boost::asio::placeholders::bytes_transferred));\r
+        }\r
+\r
+        boost::asio::io_service::work work(io_service_);\r
+        io_service_.run();\r
+    }\r
+\r
+    void Server::Stop()\r
+    {\r
+        io_service_.stop();\r
+               Logger::Info("stop server");\r
+    }\r
+    void Server::Stop(int innterrupt_type)\r
+    {\r
+        io_service_.stop();\r
+       Logger::Info(_T("stop server innterrupt_type=%d"),innterrupt_type);\r
+    }\r
+\r
+       int Server::GetUserCount() const\r
+       {\r
+               auto count = std::count_if(sessions_.begin(), sessions_.end(),\r
+                       [](const SessionWeakPtr& s){ \r
+                               return !s.expired() && s.lock()->online() && s.lock()->id() > 0; \r
+                       });\r
+\r
+               return count;\r
+       }\r
+\r
+       std::string Server::GetStatusJSON() const\r
+       {\r
+               auto msg = (\r
+                                       boost::format("{\"nam\":\"%s\",\"ver\":\"%d.%d.%d\",\"cnt\":%d,\"cap\":%d,\"stg\":\"%s\"}")\r
+                                               % config_.server_name()\r
+                                               % MMO_VERSION_MAJOR % MMO_VERSION_MINOR % MMO_VERSION_REVISION\r
+                                               % GetUserCount()\r
+                                               % config_.capacity()\r
+                                               % config_.stage()\r
+                                       ).str();\r
+\r
+               return msg;\r
+       }\r
+\r
+       std::string Server::GetFullStatus() const\r
+       {\r
+               using namespace boost::property_tree;\r
+               ptree xml_ptree;\r
+\r
+               xml_ptree.put_child("config", config_.pt());\r
+               xml_ptree.put("version", (boost::format("%d.%d.%d") \r
+                       % MMO_VERSION_MAJOR % MMO_VERSION_MINOR % MMO_VERSION_REVISION).str());\r
+               xml_ptree.put("protocol_version", MMO_PROTOCOL_VERSION);\r
+\r
+               {\r
+                       ptree player_array;\r
+                       auto id_list = account_.GetIDList();\r
+                       BOOST_FOREACH(const auto& s, sessions_) {\r
+                               if (!s.expired() && s.lock()->online() && s.lock()->id() > 0) {\r
+                                       auto id = s.lock()->id();\r
+                                       ptree player;\r
+                                       player.put("name", account_.GetUserName(id));\r
+                                       player.put("model_name", account_.GetUserModelName(id));\r
+                                       player_array.push_back(std::make_pair("", player));\r
+                               }\r
+                       }\r
+                       xml_ptree.put_child("players", player_array);\r
+               }\r
+\r
+               //{\r
+               //      ptree log_array;\r
+               //      BOOST_FOREACH(const std::string& msg, recent_chat_log_) {\r
+               //              log_array.push_back(std::make_pair("", msg));\r
+               //      }\r
+               //      xml_ptree.put_child("recent_chat_log", log_array);\r
+               //}\r
+\r
+               xml_ptree.put_child("channels", channel_.pt());\r
+               std::stringstream stream;\r
+               boost::archive::text_oarchive oa(stream);\r
+               oa << xml_ptree;\r
+\r
+               return stream.str();\r
+       }\r
+\r
+       const Config& Server::config() const\r
+       {\r
+               return config_;\r
+       }\r
+\r
+       Account& Server::account()\r
+       {\r
+               return account_;\r
+       }\r
+       \r
+       void Server::AddChatLog(const std::string& msg)\r
+       {\r
+               recent_chat_log_.push_back(msg);\r
+       }\r
+\r
+    bool Server::Empty() const\r
+    {\r
+        return GetUserCount() == 0;\r
+    }\r
+\r
+       bool Server::IsBlockedAddress(const boost::asio::ip::address& address)\r
+       {\r
+               BOOST_FOREACH(const auto& pattern, config_.blocking_address_patterns()) {\r
+                       if (network::Utils::MatchWithWildcard(pattern, address.to_string())) {\r
+                               return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+\r
+    void Server::ReceiveSession(const SessionPtr& session, const boost::system::error_code& error)\r
+    {\r
+               \r
+               config_.Reload();\r
+\r
+               const auto address = session->tcp_socket().remote_endpoint().address();\r
+\r
+               // 拒否IPでないか判定\r
+               if(IsBlockedAddress(address)) {\r
+                       Logger::Info("Blocked IP Address: %s", address);\r
+            session->Close();\r
+\r
+               } else {\r
+            session->set_on_receive(callback_);\r
+            session->Start();\r
+            sessions_.push_back(SessionWeakPtr(session));\r
+\r
+            // クライアント情報を要求\r
+            session->Send(ClientRequestedClientInfo());\r
+        }\r
+\r
+        auto new_session = boost::make_shared<ServerSession>(io_service_);\r
+        acceptor_.async_accept(new_session->tcp_socket(),\r
+                boost::bind(&Server::ReceiveSession, this, new_session, boost::asio::placeholders::error));\r
+\r
+               RefreshSession();\r
+    }\r
+\r
+       void Server::RefreshSession()\r
+       {\r
+               // 使用済のセッションのポインタを破棄\r
+        auto it = std::remove_if(sessions_.begin(), sessions_.end(),\r
+                [](const SessionWeakPtr& ptr){\r
+            return ptr.expired();\r
+        });\r
+        sessions_.erase(it, sessions_.end());\r
+               Logger::Info("Active connection: %d", GetUserCount());\r
+       }\r
+\r
+    void Server::SendAll(const Command& command, int channel, bool limited)\r
+    {\r
+        BOOST_FOREACH(SessionWeakPtr& ptr, sessions_) {\r
+            if (auto session = ptr.lock()) {\r
+                               if (channel < 0 || (channel >= 0 && session->channel() == channel)) {\r
+                                       if (!limited || session->write_average_limit() > session->GetWriteByteAverage()) {\r
+                                               if (session->id() > 0) {\r
+                                                       session->Send(command);\r
+                                               }\r
+                                       }\r
+                               }\r
+            }\r
+        }\r
+    }\r
+\r
+    void Server::SendOthers(const Command& command, uint32_t self_id, int channel, bool limited)\r
+    {\r
+        BOOST_FOREACH(SessionWeakPtr& ptr, sessions_) {\r
+            if (auto session = ptr.lock()) {\r
+                               if (channel < 0 || (channel >= 0 && session->channel() == channel)) {\r
+                                       if (!limited || session->write_average_limit() > session->GetWriteByteAverage()) {\r
+                                               if (session->id() > 0 && session->id() != self_id) {\r
+                                                       session->Send(command);\r
+                                               }\r
+                                       }\r
+                               }\r
+            }\r
+        }\r
+    }\r
+       \r
+    void Server::SendTo(const Command& command, uint32_t user_id)\r
+       {\r
+               auto it = std::find_if(sessions_.begin(), sessions_.end(),\r
+                       [user_id](SessionWeakPtr& ptr){\r
+                               return ptr.lock()->id() == user_id;\r
+                       });\r
+               \r
+               if (it != sessions_.end()) {\r
+                       it->lock()->Send(command);\r
+               }\r
+       }\r
+\r
+    void Server::SendUDPTestPacket(const std::string& ip_address, uint16_t port)\r
+    {\r
+        using boost::asio::ip::udp;\r
+\r
+        std::stringstream port_str;\r
+        port_str << (int)port;\r
+\r
+        udp::resolver resolver(io_service_);\r
+        udp::resolver::query query(udp::v4(), ip_address.c_str(), port_str.str().c_str());\r
+        udp::resolver::iterator iterator = resolver.resolve(query);\r
+\r
+        static char request[] = "MMO UDP Test Packet";\r
+        for (int i = 0; i < UDP_TEST_PACKET_TIME; i++) {\r
+\r
+            io_service_.post(boost::bind(&Server::DoWriteUDP, this, request, *iterator));\r
+        }\r
+    }\r
+\r
+       void Server::SendPublicPing()\r
+       {\r
+               static char request[] = "P";\r
+               BOOST_FOREACH(const auto& iterator, lobby_hosts_) {\r
+                       io_service_.post(boost::bind(&Server::DoWriteUDP, this, request, *iterator));\r
+               }\r
+       }\r
+\r
+    void Server::SendUDP(const std::string& message, const boost::asio::ip::udp::endpoint endpoint)\r
+    {\r
+               io_service_.post(boost::bind(&Server::DoWriteUDP, this, message, endpoint));\r
+    }\r
+\r
+    void Server::ReceiveUDP(const boost::system::error_code& error, size_t bytes_recvd)\r
+    {\r
+        if (bytes_recvd > 0) {\r
+            std::string buffer(receive_buf_udp_, bytes_recvd);\r
+            FetchUDP(buffer, sender_endpoint_);\r
+        }\r
+        if (!error) {\r
+          socket_udp_.async_receive_from(\r
+              boost::asio::buffer(receive_buf_udp_, UDP_MAX_RECEIVE_LENGTH), sender_endpoint_,\r
+              boost::bind(&Server::ReceiveUDP, this,\r
+                boost::asio::placeholders::error,\r
+                boost::asio::placeholders::bytes_transferred));\r
+        } else {\r
+            Logger::Error("%s", error.message());\r
+        }\r
+    }\r
+\r
+    void Server::DoWriteUDP(const std::string& msg, const udp::endpoint& endpoint)\r
+    {\r
+        boost::shared_ptr<std::string> s = \r
+              boost::make_shared<std::string>(msg.data(), msg.size());\r
+\r
+        socket_udp_.async_send_to(\r
+            boost::asio::buffer(s->data(), s->size()), endpoint,\r
+            boost::bind(&Server::WriteUDP, this,\r
+              boost::asio::placeholders::error, s));\r
+    }\r
+\r
+    void Server::WriteUDP(const boost::system::error_code& error, boost::shared_ptr<std::string> holder)\r
+    {\r
+//        if (!error) {\r
+//            if (!send_queue_.empty()) {\r
+//                  send_queue_.pop();\r
+//                  if (!send_queue_.empty())\r
+//                  {\r
+//                    boost::asio::async_write(socket_tcp_,\r
+//                        boost::asio::buffer(send_queue_.front().data(),\r
+//                          send_queue_.front().size()),\r
+//                        boost::bind(&Session::WriteTCP, this,\r
+//                          boost::asio::placeholders::error));\r
+//                  }\r
+//            }\r
+//        } else {\r
+//            FatalError();\r
+//        }\r
+    }\r
+\r
+    void Server::FetchUDP(const std::string& buffer, const boost::asio::ip::udp::endpoint endpoint)\r
+    {\r
+        uint8_t header;\r
+        std::string body;\r
+        SessionWeakPtr session;\r
+\r
+               // IPアドレスとポートからセッションを特定\r
+               auto it = std::find_if(sessions_.begin(), sessions_.end(),\r
+                       [&endpoint](const SessionWeakPtr& session) -> bool {\r
+                               if (auto session_ptr = session.lock()) {\r
+\r
+                                       const auto session_endpoint = session_ptr->tcp_socket().remote_endpoint();\r
+                                       const auto session_port = session_ptr->udp_port();\r
+\r
+                                       return (session_endpoint.address() == endpoint.address() &&\r
+                                               session_port == endpoint.port());\r
+\r
+                               } else {\r
+                                       return false;\r
+                               }\r
+                       });\r
+\r
+               if (it != sessions_.end()) {\r
+                       session = *it;\r
+                       Logger::Debug("Receive UDP Command: %d", session.lock()->id());\r
+               } else {\r
+                       Logger::Debug("Receive anonymous UDP Command");\r
+               }\r
+\r
+        if (buffer.size() > network::Utils::Deserialize(buffer, &header)) {\r
+                       body = buffer.substr(sizeof(header));\r
+               }\r
+\r
+        // 復号\r
+        if (session.lock() && header == header::ENCRYPT_HEADER) {\r
+            body.erase(0, sizeof(header));\r
+                       body = session.lock()->encrypter().Decrypt(body);\r
+            Utils::Deserialize(body, &header);\r
+                       body = buffer.substr(sizeof(header));\r
+        }\r
+\r
+               if (header == network::header::ServerRequstedStatus) {\r
+                       SendUDP(GetStatusJSON(), endpoint);\r
+               } else {\r
+                       if (callback_) {\r
+                               (*callback_)(Command(static_cast<network::header::CommandHeader>(header), body, session));\r
+                       }\r
+               }\r
+\r
+    }\r
+\r
+    void Server::ServerSession::Start()\r
+    {\r
+        online_ = true;\r
+\r
+        // Nagleアルゴリズムを無効化\r
+        socket_tcp_.set_option(boost::asio::ip::tcp::no_delay(true));\r
+\r
+               // バッファサイズを変更 1MiB\r
+               boost::asio::socket_base::receive_buffer_size option(1048576);\r
+               socket_tcp_.set_option(option);\r
+\r
+        // IPアドレスを取得\r
+        global_ip_ = socket_tcp_.remote_endpoint().address().to_string();\r
+\r
+        boost::asio::async_read_until(socket_tcp_,\r
+            receive_buf_, NETWORK_UTILS_DELIMITOR,\r
+            boost::bind(\r
+              &ServerSession::ReceiveTCP, shared_from_this(),\r
+              boost::asio::placeholders::error));\r
+    }\r
+}\r