Menu

[r2]: / server.h  Maximize  Restore  History

Download this file

166 lines (135 with data), 5.2 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//////////////////////////////////////////////////////////////////////
#ifndef __OTSERV_SERVER_H__
#define __OTSERV_SERVER_H__
#include "definitions.h"
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/utility.hpp>
#include <boost/enable_shared_from_this.hpp>
class Connection;
typedef boost::shared_ptr<Connection> Connection_ptr;
class Protocol;
class NetworkMessage;
class ServiceBase;
class ServicePort;
typedef boost::shared_ptr<ServiceBase> Service_ptr;
typedef boost::shared_ptr<ServicePort> ServicePort_ptr;
// The Service class is very thin, it's only real job is to create dynamic
// dispatch of the protocol attributes, which would otherwise be very hard,
// and require templating of many Service functions
class ServiceBase : boost::noncopyable
{
public:
virtual ~ServiceBase() {} // Redundant, but stifles compiler warnings
virtual bool is_single_socket() const = 0;
virtual bool is_checksummed() const = 0;
virtual uint8_t get_protocol_identifier() const = 0;
virtual const char* get_protocol_name() const = 0;
virtual Protocol* make_protocol(Connection_ptr c) const = 0;
};
template <typename ProtocolType>
class Service : public ServiceBase
{
public:
bool is_single_socket() const {return ProtocolType::server_sends_first;}
bool is_checksummed() const {return ProtocolType::use_checksum;}
uint8_t get_protocol_identifier() const {return ProtocolType::protocol_identifier;}
const char* get_protocol_name() const {return ProtocolType::protocol_name();}
Protocol* make_protocol(Connection_ptr c) const {return new ProtocolType(c);}
};
// A Service Port represents a listener on a port.
// It accepts connections, and asks each Service running
// on it if it can accept the connection, and if so passes
// it on to the service
class ServicePort : boost::noncopyable, public boost::enable_shared_from_this<ServicePort>
{
public:
ServicePort(boost::asio::io_service& io_service);
~ServicePort();
static void openAcceptor(boost::weak_ptr<ServicePort> weak_service, uint16_t port);
void open(uint16_t port);
void close();
bool is_single_socket() const;
std::string get_protocol_names() const;
bool add_service(Service_ptr);
Protocol* make_protocol(bool checksummed, NetworkMessage& msg) const;
void onStopServer();
void onAccept(boost::asio::ip::tcp::socket* socket, const boost::system::error_code& error);
protected:
void accept();
boost::asio::io_service& m_io_service;
boost::asio::ip::tcp::acceptor* m_acceptor;
std::vector<Service_ptr> m_services;
uint16_t m_serverPort;
bool m_pendingStart;
static bool m_logError;
};
typedef boost::shared_ptr<ServicePort> ServicePort_ptr;
// The ServiceManager simply manages all services and handles startup/closing
class ServiceManager : boost::noncopyable
{
ServiceManager(const ServiceManager&);
public:
ServiceManager();
~ServiceManager();
// Run and start all servers
void run();
void stop();
// Adds a new service to be managed
template <typename ProtocolType>
bool add(uint16_t port);
bool is_running() const {return m_acceptors.empty() == false;}
std::list<uint16_t> get_ports() const;
protected:
void die();
std::map<uint16_t, ServicePort_ptr> m_acceptors;
boost::asio::io_service m_io_service;
boost::asio::deadline_timer death_timer;
bool running;
};
template <typename ProtocolType>
bool ServiceManager::add(uint16_t port)
{
if(port == 0){
std::cout << "ERROR: No port provided for service " << ProtocolType::protocol_name() << ". Service disabled." << std::endl;
return false;
}
ServicePort_ptr service_port;
std::map<uint16_t, ServicePort_ptr>::iterator finder =
m_acceptors.find(port);
if(finder == m_acceptors.end()){
service_port.reset(new ServicePort(m_io_service));
service_port->open(port);
m_acceptors[port] = service_port;
}
else{
service_port = finder->second;
if(service_port->is_single_socket() || ProtocolType::server_sends_first){
std::cout << "ERROR: " << ProtocolType::protocol_name() <<
" and " << service_port->get_protocol_names() <<
" cannot use the same port " << port << "." << std::endl;
return false;
}
}
return service_port->add_service(Service_ptr(new Service<ProtocolType>()));
}
#endif