root/plugins/branches/0185_GEN_PHYSICS_REFACTOR_2/ZBoostNetworking/src/XML/XMLProtocolService.cpp @ 3447

Revision 3447, 11.5 KB (checked in by mgray, 6 months ago)

Debug and refactor of the TCP Protocol Adapter in ZBoostNetworking.

Line 
1//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
2// Zen Enterprise Framework
3//
4// Copyright (C) 2001 - 2009 Tony Richards
5// Copyright (C) 2008 - 2009 Matthew Alan Gray
6//
7//  This software is provided 'as-is', without any express or implied
8//  warranty.  In no event will the authors be held liable for any damages
9//  arising from the use of this software.
10//
11//  Permission is granted to anyone to use this software for any purpose,
12//  including commercial applications, and to alter it and redistribute it
13//  freely, subject to the following restrictions:
14//
15//  1. The origin of this software must not be misrepresented; you must not
16//     claim that you wrote the original software. If you use this software
17//     in a product, an acknowledgment in the product documentation would be
18//     appreciated but is not required.
19//  2. Altered source versions must be plainly marked as such, and must not be
20//     misrepresented as being the original software.
21//  3. This notice may not be removed or altered from any source distribution.
22//
23//  Tony Richards trichards@indiezen.com
24//  Matthew Alan Gray mgray@indiezen.org
25//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
26
27#ifndef NOMINMAX
28#define NOMINMAX
29#endif
30
31#include <boost/asio.hpp>
32
33#include "XMLProtocolService.hpp"
34
35#include "Endpoint.hpp"
36
37#include <Zen/Core/Utility/runtime_exception.hpp>
38
39#include <Zen/Core/Threading/ThreadFactory.hpp>
40#include <Zen/Core/Threading/MutexFactory.hpp>
41#include <Zen/Core/Threading/CriticalSection.hpp>
42
43#include <Zen/Core/Plugins/I_ConfigurationElement.hpp>
44
45#include <Zen/Enterprise/AppServer/I_Message.hpp>
46#include <Zen/Enterprise/AppServer/I_MessageRegistry.hpp>
47#include <Zen/Enterprise/AppServer/I_ApplicationServerManager.hpp>
48
49#include <boost/bind.hpp>
50
51#include <iostream>
52
53#include <stdlib.h>
54#include <string.h>
55
56//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
57namespace Zen {
58namespace Enterprise {
59namespace AppServer {
60namespace XML {
61//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
62XMLProtocolService::XMLProtocolService(I_ApplicationServer& _server)
63:   m_appServer(_server)
64,   m_ioService()
65,   m_acceptor(m_ioService)
66,   m_pRequestHandler(NULL)
67,   m_pLocationsGuard(Threading::MutexFactory::create())
68{
69}
70
71//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
72XMLProtocolService::~XMLProtocolService()
73{
74    Threading::MutexFactory::destroy(m_pLocationsGuard);
75}
76
77//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
78void
79XMLProtocolService::registerURL(const std::string& _url, pResourceLocation_type _pDestination)
80{
81    Threading::CriticalSection lock(m_pLocationsGuard);
82
83    m_locations.push_back(std::make_pair<std::string, pResourceLocation_type>(_url, _pDestination));
84}
85
86//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
87I_ApplicationServer&
88XMLProtocolService::getApplicationServer()
89{
90    return m_appServer;
91}
92
93//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
94void
95XMLProtocolService::setConfiguration(const Plugins::I_ConfigurationElement& _config)
96{
97    m_address = _config.getAttribute("address");
98    m_port = _config.getAttribute("port");
99    m_threadCount = strtol(_config.getAttribute("threads").c_str(), NULL, 10);
100
101    class ConfigVisitor
102    : public Zen::Plugins::I_ConfigurationElement::I_ConfigurationElementVisitor
103    {
104    public:
105        virtual void begin()
106        {
107        }
108
109        virtual void visit(const Zen::Plugins::I_ConfigurationElement& _element)
110        {
111            ;
112            ;
113
114            m_protocolService.registerURL(
115                _element.getAttribute("url"),
116                I_ApplicationServerManager::getSingleton().createLocation(_element.getAttribute("destination"))
117            );
118        }
119
120        virtual void end()
121        {
122        }
123
124        ConfigVisitor(XMLProtocolService& _protocolService)
125        :   m_protocolService(_protocolService)
126        {
127        }
128
129    private:
130        XMLProtocolService&  m_protocolService;
131    };
132
133    ConfigVisitor visitor(*this);
134    _config.getChildren("map", visitor);
135
136}
137
138//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
139XMLProtocolService::pEndpoint_type
140XMLProtocolService::resolveEndpoint(const std::string& _address, const std::string& _port)
141{
142    boost::asio::ip::tcp::resolver resolver(m_ioService);
143    // TODO _address and _port or v4() and m_port?
144    boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), m_port);
145    boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
146
147    return pEndpoint_type(new Endpoint(getSelfReference(), endpoint), boost::bind(&XMLProtocolService::destroyEndpoint, this, _1));
148}
149
150//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
151void
152XMLProtocolService::sendTo(pMessage_type _pMessage, pEndpoint_type _pEndpoint)
153{
154    // TODO Implement
155    throw Utility::runtime_exception("XMLProtocolService::sendTo(): Error, not implemented.");
156}
157
158//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
159Event::I_Event&
160XMLProtocolService::getConnectedEvent()
161{
162    throw Utility::runtime_exception("XMLProtocolService::getConnectedEvent(): Error, not implemented.");
163}
164
165//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
166Event::I_Event&
167XMLProtocolService::getDisconnectedEvent()
168{
169    throw Utility::runtime_exception("XMLProtocolService::getConnectedEvent(): Error, not implemented.");
170}
171
172//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
173void
174XMLProtocolService::setMessageRegistry(pMessageRegistry_type _pMessageRegistry)
175{
176    // TODO Use this message registry instead of the deprecated singleton
177    // See the TCP protocol adapter for a reference implementation.
178    throw Utility::runtime_exception("XMLProtocolService::setMessageRegistry(): Error, not implemented.");
179}
180
181//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
182void
183XMLProtocolService::destroyEndpoint(wpEndpoint_type _pEndpoint)
184{
185    Endpoint* pEndpoint = dynamic_cast<Endpoint*>(_pEndpoint.get());
186    if (pEndpoint != NULL)
187    {
188        delete pEndpoint;
189    }
190    else
191    {
192        // TODO Error
193    }
194}
195
196//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
197Threading::I_Condition*
198XMLProtocolService::prepareToStart(Threading::ThreadPool& _threadPool)
199{
200    // Resolve the address
201    boost::asio::ip::tcp::resolver resolver(m_ioService);
202    boost::asio::ip::tcp::resolver::query query(m_address, m_port);
203    boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
204
205    // Bind to the address
206    m_acceptor.open(endpoint.protocol());
207    m_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
208    m_acceptor.bind(endpoint);
209
210    // Create a new connection
211    createConnection();
212
213    // Ready to go, so don't bother returning a condition variable
214    return NULL;
215}
216
217//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
218void
219XMLProtocolService::start()
220{
221    // Start listening
222    boost::system::error_code ec;
223    m_acceptor.listen(boost::asio::socket_base::max_connections, ec);
224
225    if (ec)
226    {
227        std::cout << "Error: " << ec << std::endl;
228    }
229
230    // Asyncronously accept a new connection
231    asyncAccept();
232
233    class Runnable
234    :   public Threading::I_Runnable
235    {
236    public:
237        virtual void run() throw()
238        {
239            while(!m_stopping)
240            {
241                try
242                {
243                    m_ioService.run();
244                }
245                catch(...)
246                {
247                }
248            }
249        }
250
251        virtual void stop()
252        {
253            m_stopping = true;
254        }
255
256        Runnable(boost::asio::io_service& _ioService)
257            : m_ioService(_ioService), m_stopping(false) {}
258
259        boost::asio::io_service& m_ioService;
260        volatile bool m_stopping;
261    };
262
263    // Start some threads that will execute m_ioService.run()
264    for(int x = 0; x < m_threadCount; x++)
265    {
266        Zen::Threading::I_Thread* pThread = Zen::Threading::ThreadFactory::create(new Runnable(m_ioService));
267        m_threads.push_back(pThread);
268        pThread->start();
269    }
270
271}
272
273//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
274Threading::I_Condition*
275XMLProtocolService::prepareToStop()
276{
277    for(Threads_type::iterator iter = m_threads.begin(); iter != m_threads.end(); iter++)
278    {
279        (*iter)->stop();
280    }
281
282    m_ioService.stop();
283
284    return NULL;
285}
286
287//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
288void
289XMLProtocolService::stop()
290{
291    for(Threads_type::iterator iter = m_threads.begin(); iter != m_threads.end(); iter++)
292    {
293        (*iter)->join();
294        Threading::ThreadFactory::destroy(*iter);
295    }
296
297    m_threads.clear();
298}
299
300//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
301void
302XMLProtocolService::handleAccept(const boost::system::error_code& _error)
303{
304    if (!_error)
305    {
306        // The new connection is now connected, so start it.
307        pEndpoint_type pEndpoint(new Endpoint(getSelfReference(), m_endpoint), boost::bind(&XMLProtocolService::destroyEndpoint, this, _1));
308
309        m_pNewConnection->start(pEndpoint);
310
311        // Now, create another connection and do an async accept on it.
312        createConnection();
313
314        // And asynchronously accept the new connection.
315        asyncAccept();
316    }
317}
318
319//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
320void
321XMLProtocolService::createConnection()
322{
323    m_pNewConnection.reset(new Connection(m_ioService, *this));
324}
325
326//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
327void
328XMLProtocolService::asyncAccept()
329{
330    // TODO Add endpoint here?
331
332    // Start the async accept using handleAccept() as the callback
333    m_acceptor.async_accept(m_pNewConnection->getSocketReference(),
334        m_endpoint,
335        boost::bind(&XMLProtocolService::handleAccept, this,
336        boost::asio::placeholders::error)
337    );
338}
339
340//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
341XMLProtocolService::pResourceLocation_type
342XMLProtocolService::getLocation(const std::string& _url)
343{
344    Threading::CriticalSection lock(m_pLocationsGuard);
345    unsigned maximumMatched = 0;
346
347    pResourceLocation_type returnValue;
348
349    for(Locations_type::iterator iter = m_locations.begin(); iter != m_locations.end(); iter++)
350    {
351        const std::string& url = iter->first;
352        const int matchLen = std::min(url.length(), _url.length());
353        if(strncmp(url.c_str(), _url.c_str(), matchLen) == 0)
354        {
355            if (matchLen > maximumMatched)
356            {
357                returnValue = iter->second;
358                maximumMatched = matchLen;
359            }
360        }
361    }
362
363    return returnValue;
364}
365
366//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
367}   // namespace XML
368}   // namespace AppServer
369}   // namespace Enterprise
370}   // namespace Zen
371//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
Note: See TracBrowser for help on using the browser.