X-Git-Url: http://developer.intra2net.com/git/?p=libt2n;a=blobdiff_plain;f=src%2Fcommand_server.cpp;h=21aeb798bfd420779292dcd498a1063e839b2a92;hp=e7d6d4da02a839074cd733766961f3474f7e8bdb;hb=44b4600fd51677e54dd167734ca9252b58237cda;hpb=28cb45a5725e9c6054d7048a9bf969b9f2c94d64 diff --git a/src/command_server.cpp b/src/command_server.cpp index e7d6d4d..21aeb79 100644 --- a/src/command_server.cpp +++ b/src/command_server.cpp @@ -1,21 +1,24 @@ -/*************************************************************************** - * Copyright (C) 2006 by Gerd v. Egidy * - * gve@intra2net.com * - * * - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library 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 Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser 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. * - ***************************************************************************/ +/* +Copyright (C) 2006 by Intra2net AG - Gerd v. Egidy + +The software in this package is distributed under the GNU General +Public License version 2 (with a special exception described below). + +A copy of GNU General Public License (GPL) is included in this distribution, +in the file COPYING.GPL. + +As a special exception, if other files instantiate templates or use macros +or inline functions from this file, or you compile this file and link it +with other works to produce a work based on this file, this file +does not by itself cause the resulting work to be covered +by the GNU General Public License. + +However the source code for this file must still be made available +in accordance with section (3) of the GNU General Public License. + +This exception does not invalidate any other reasons why a work based +on this file might be covered by the GNU General Public License. +*/ #include #include @@ -34,21 +37,45 @@ #include "container.hxx" #include "log.hxx" +#include + using namespace std; namespace libt2n { command_server::command_server(server& _s) - : s(_s) + : s(_s), guard_handle(0) { // register callback - s.add_callback(new_connection,bind(&command_server::new_connection_callback, boost::ref(*this), _1)); + s.add_callback(new_connection,bind(&command_server::send_hello, boost::ref(*this), _1)); } -void command_server::new_connection_callback(server_connection* conn) +/** + * Destructor + */ +command_server::~command_server() { - cerr << "new connection callback: " << conn->get_id() << endl; +} + +/// send a hello message to a new connection +void command_server::send_hello(unsigned int conn_id) +{ + server_connection* sc=s.get_connection(conn_id); + + if (!sc) + return; // connection not existing, so no hello + + std::ostringstream hello; + + hello << "T2Nv" << PROTOCOL_VERSION << ';'; + + int byteordercheck=1; + hello.write((char*)&byteordercheck,sizeof(byteordercheck)); + + hello << ';'; + + sc->write(hello.str()); } /// handle a command including deserialization and answering @@ -57,46 +84,72 @@ void command_server::handle_packet(const std::string& packet, server_connection* OBJLOGSTREAM(s,debug,"handling packet from connection " << conn->get_id()); // deserialize packet - istringstream ifs(packet); + std::istringstream ifs(packet); boost::archive::binary_iarchive ia(ifs); command_container ccont; + result_container res; - // TODO: catch - ia >> ccont; - - std::ostream* ostr; - if ((ostr=s.get_logstream(fulldebug))!=NULL) + try { - (*ostr) << "decoded packet data: " << std::endl; - boost::archive::xml_oarchive xo(*ostr); - xo << BOOST_SERIALIZATION_NVP(ccont); + ia >> ccont; + } + catch(boost::archive::archive_exception &e) + { + std::ostringstream msg; + msg << "archive_exception while deserializing on server-side, " + "code " << e.code << " (" << e.what() << ")"; + res.set_exception(new t2n_serialization_error(msg.str())); } - // TODO: cast to command subclass (template) - command *cmd=ccont.get_command(); + if (!res.has_exception()) + { + std::ostream* ostr; + if ((ostr=s.get_logstream(fulldebug))!=NULL) + { + (*ostr) << "decoded packet data: " << std::endl; + boost::archive::xml_oarchive xo(*ostr); + xo << BOOST_SERIALIZATION_NVP(ccont); + } - result_container res; + command* cmd=cast_command(ccont.get_command()); - if (cmd) - { - try + if (cmd) + { + try + { + res.set_result((*cmd)()); + } + catch (t2n_exception &e) + { res.set_exception(e.clone()); } + } + else { - res.set_result((*cmd)()); + std::ostringstream msg; + if (ccont.get_command()!=NULL) + msg << "illegal command of type " << typeid(ccont.get_command()).name() << " called"; + else + msg << "NULL command called"; + res.set_exception(new t2n_command_error(msg.str())); } - catch (t2n_exception &e) - { res.set_exception(e.clone()); } - catch (...) - { throw; } } - else - throw logic_error("uninitialized command called"); - ostringstream ofs; + std::ostringstream ofs; boost::archive::binary_oarchive oa(ofs); - // TODO: catch - oa << res; + try + { + oa << res; + } + catch(boost::archive::archive_exception &e) + { + std::ostringstream msg; + msg << "archive_exception while serializing on server-side, " + "code " << e.code << " (" << e.what() << ")"; + res.set_exception(new t2n_serialization_error(msg.str())); + oa << res; + } + std::ostream* ostr; if ((ostr=s.get_logstream(fulldebug))!=NULL) { (*ostr) << "returning result, decoded data: " << std::endl; @@ -108,20 +161,46 @@ void command_server::handle_packet(const std::string& packet, server_connection* } /** @brief handle incoming commands - @param usec_timeout wait until new data is found, max timeout usecs. - -1: wait endless, 0: no timeout + @param[in,out] usec_timeout wait until new data is found, max timeout usecs. + -1: wait endless, 0: instant return + @param[out] usec_timeout_remaining microseconds from the timeout that were not used */ -void command_server::handle(long long usec_timeout) +void command_server::handle(long long usec_timeout, long long* usec_timeout_remaining) { - if (s.fill_buffer(usec_timeout)) - { - string packet; - unsigned int conn_id; + guard_handle++; - while (s.get_packet(packet,conn_id)) - handle_packet(packet,s.get_connection(conn_id)); + try + { + if (s.fill_buffer(usec_timeout,usec_timeout_remaining)) + { + std::string packet; + unsigned int conn_id = 0; + + while (s.get_packet(packet,conn_id)) + { + server_connection* conn=s.get_connection(conn_id); + if (!conn) + EXCEPTIONSTREAM(error,logic_error,"illegal connection id " << conn_id << " received"); + try + { handle_packet(packet,conn); } + catch (t2n_transfer_error &e) + { + // shut down a connection with transfer errors (usually write errors) + conn->close(); + } + } + } } - s.cleanup(); + catch(...) + { + guard_handle--; + throw; + } + guard_handle--; + + // don't call cleanup on re-entered handle-calls + if (guard_handle == 0) + s.cleanup(); } }