Client.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006-2010 Jacek Sieka, arnetheduck on gmail point com
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #include "adchpp.h"
00020 
00021 #include "Client.h"
00022 
00023 #include "ClientManager.h"
00024 #include "TimerManager.h"
00025 #include "SocketManager.h"
00026 
00027 namespace adchpp {
00028 
00029 using namespace std;
00030 using namespace std::placeholders;
00031 
00032 size_t Client::defaultMaxCommandSize = 16 * 1024;
00033 
00034 Client* Client::create(const ManagedSocketPtr& ms, uint32_t sid) throw() {
00035     Client* c = new Client(sid);
00036     c->setSocket(ms);
00037     return c;
00038 }
00039 
00040 Client::Client(uint32_t sid_) throw() : Entity(sid_), disconnecting(false),
00041     dataBytes(0), maxCommandSize(getDefaultMaxCommandSize()) {
00042 }
00043 
00044 Client::~Client() {
00045 
00046 }
00047 
00048 namespace {
00049     // Lightweight call forwarders, instead of std::bind
00050     template<void (Client::*F)()>
00051     struct Handler0 {
00052         Handler0(Client* c_) : c(c_) { }
00053         void operator()() { (c->*F)(); }
00054         Client* c;
00055     };
00056 
00057     template<void (Client::*F)(const boost::system::error_code&)>
00058     struct Handler0x {
00059         Handler0x(Client* c_) : c(c_) { }
00060         void operator()() { (c->*F)(boost::system::error_code(boost::system::errc::timed_out, boost::system::get_generic_category())); }
00061         Client* c;
00062     };
00063 
00064     template<typename T, void (Client::*F)(const T&)>
00065     struct Handler1 {
00066         Handler1(Client* c_) : c(c_) { }
00067         void operator()(const T& bv) { (c->*F)(bv); }
00068         Client* c;
00069     };
00070 }
00071 
00072 void Client::setSocket(const ManagedSocketPtr& aSocket) throw() {
00073     dcassert(!socket);
00074     socket = aSocket;
00075     socket->setConnectedHandler(Handler0<&Client::onConnected>(this));
00076     socket->setDataHandler(Handler1<BufferPtr, &Client::onData>(this));
00077     socket->setFailedHandler(Handler1<boost::system::error_code, &Client::onFailed>(this));
00078 }
00079 
00080 void Client::onConnected() throw() {
00081     ClientManager::getInstance()->onConnected(*this);
00082 }
00083 
00084 void Client::onData(const BufferPtr& buf) throw() {
00085     uint8_t* data = buf->data();
00086     size_t done = 0;
00087     size_t len = buf->size();
00088     while(!disconnecting && done < len) {
00089         if(dataBytes > 0) {
00090             size_t n = (size_t)min(dataBytes, (int64_t)(len - done));
00091             dataHandler(*this, data + done, n);
00092             dataBytes -= n;
00093             done += n;
00094         } else {
00095             size_t j = done;
00096             while(j < len && data[j] != '\n')
00097                 ++j;
00098 
00099             if(j == len) {
00100                 if(!buffer) {
00101                     if(done == 0) {
00102                         buffer = buf;
00103                     } else {
00104                         buffer = make_shared<Buffer>(data + done, len - done);
00105                     }
00106                 } else {
00107                     buffer->append(data + done, data + len);
00108                 }
00109                 return;
00110             } else if(!buffer) {
00111                 if(done == 0 && j == len-1) {
00112                     buffer = buf;
00113                 } else {
00114                     buffer = make_shared<Buffer>(data + done, j - done + 1);
00115                 }
00116             } else {
00117                 buffer->append(data + done, data + j + 1);
00118             }
00119 
00120             done = j + 1;
00121 
00122             if(getMaxCommandSize() > 0 && buffer->size() > getMaxCommandSize()) {
00123                 send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC, "Command too long"));
00124                 disconnect(Util::REASON_MAX_COMMAND_SIZE);
00125                 return;
00126             }
00127 
00128             if(buffer->size() == 1) {
00129                 buffer.reset();
00130                 continue;
00131             }
00132 
00133             try {
00134                 AdcCommand cmd(buffer);
00135 
00136                 if(cmd.getType() == 'H') {
00137                     cmd.setFrom(getSID());
00138                 } else if(cmd.getFrom() != getSID()) {
00139                     disconnect(Util::REASON_INVALID_SID);
00140                     return;
00141                 }
00142                 ClientManager::getInstance()->onReceive(*this, cmd);
00143             } catch(const ParseException&) {
00144                 ClientManager::getInstance()->onBadLine(*this, string((char*)buffer->data(), buffer->size()));
00145             }
00146             buffer.reset();
00147         }
00148     }
00149 }
00150 
00151 void Client::disconnect(Util::Reason reason) throw() {
00152     dcassert(socket);
00153     if(!disconnecting) {
00154         dcdebug("%s disconnecting because %d\n", AdcCommand::fromSID(getSID()).c_str(), reason);
00155         disconnecting = true;
00156 
00157         socket->setConnectedHandler(ManagedSocket::ConnectedHandler());
00158         socket->setDataHandler(ManagedSocket::DataHandler());
00159         socket->setFailedHandler(ManagedSocket::FailedHandler());
00160 
00162         socket->disconnect(5000, reason);
00163 
00164         // We fail the client ASAP to release nicks etc used...
00165         SocketManager::getInstance()->addJob(Handler0x<&Client::onFailed>(this));
00166     }
00167 }
00168 
00169 void Client::onFailed(const boost::system::error_code& ec) throw() {
00170     ClientManager::getInstance()->onFailed(*this, ec);
00171     delete this;
00172 }
00173 
00174 }
Generated on Sat Nov 27 23:37:53 2010 for adchpp by  doxygen 1.6.3