summaryrefslogtreecommitdiffstats
path: root/mcop/connection.cc
diff options
context:
space:
mode:
Diffstat (limited to 'mcop/connection.cc')
-rw-r--r--mcop/connection.cc196
1 files changed, 196 insertions, 0 deletions
diff --git a/mcop/connection.cc b/mcop/connection.cc
new file mode 100644
index 0000000..49221f9
--- /dev/null
+++ b/mcop/connection.cc
@@ -0,0 +1,196 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ */
+
+#include "connection.h"
+#include "dispatcher.h"
+#include "debug.h"
+#include <stdio.h>
+#include <string.h> // for Solaris
+#include <queue>
+#include <algorithm>
+
+using namespace Arts;
+using namespace std;
+
+namespace Arts {
+class ConnectionPrivate {
+public:
+ struct Data {
+ Data() : data(0), len(0) { }
+ Data(unsigned char *data, long len) : data(data), len(len) { }
+ Data(const Data& d) : data(d.data), len(d.len) { }
+ unsigned char *data;
+ long len;
+ };
+
+ queue<Data> incoming;
+ map<string,string> hints;
+};
+}
+
+Connection::Connection() :d(new ConnectionPrivate), _refCnt(1)
+{
+ _connState = unknown;
+}
+
+Connection::~Connection()
+{
+ assert(d->incoming.empty());
+ assert(_refCnt == 0);
+
+ delete d;
+}
+
+void Connection::_copy()
+{
+ assert(_refCnt > 0);
+ _refCnt++;
+}
+
+void Connection::_release()
+{
+ assert(_refCnt > 0);
+ _refCnt--;
+ if(_refCnt == 0)
+ delete this;
+}
+
+void Connection::initReceive()
+{
+ rcbuf = 0;
+ receiveHeader = true;
+ remaining = 12;
+}
+
+void Connection::receive(unsigned char *newdata, long newlen)
+{
+ /*
+ * protect against being freed while receive is running, as there are a
+ * few points where reentrant event loops may happen (Dispatcher::handle)
+ */
+ _copy();
+
+ d->incoming.push(ConnectionPrivate::Data(newdata,newlen));
+
+ do
+ {
+ ConnectionPrivate::Data &data = d->incoming.front();
+
+ // get a buffer for the incoming message
+ if(!rcbuf) rcbuf = new Buffer;
+
+ // put a suitable amount of input data into the receive buffer
+ long len = min(remaining, data.len);
+
+ remaining -= len;
+ rcbuf->write(data.data,len);
+
+ data.len -= len;
+ data.data += len;
+
+ if(data.len == 0)
+ d->incoming.pop();
+
+ // look if it was enough to do something useful with it
+ if(remaining == 0)
+ {
+ if(receiveHeader)
+ {
+ long mcopMagic;
+
+ mcopMagic = rcbuf->readLong();
+ remaining = rcbuf->readLong() - 12;
+ messageType = rcbuf->readLong();
+
+ if(_connState != Connection::established
+ && (remaining >= 4096 || remaining < 0))
+ {
+ /*
+ * don't accept large amounts of data on unauthenticated
+ * connections
+ */
+ remaining = 0;
+ }
+
+ if(mcopMagic == MCOP_MAGIC)
+ {
+ // do we need to receive more data (message body?)
+ if(remaining)
+ {
+ receiveHeader = false;
+ }
+ else
+ {
+ Buffer *received = rcbuf;
+ initReceive();
+ Dispatcher::the()->handle(this,received,messageType);
+ }
+ }
+ else
+ {
+ initReceive();
+ Dispatcher::the()->handleCorrupt(this);
+ }
+ }
+ else
+ {
+ Buffer *received = rcbuf;
+
+ /*
+ * it's important to prepare to receive new messages *before*
+ * calling Dispatcher::the()->handle(...), as handle may
+ * get into an I/O situation (e.g. when doing an invocation
+ * itself), and we may receive more messages while handle is
+ * running
+ */
+ initReceive();
+
+ // rcbuf is consumed by the dispatcher
+ Dispatcher::the()->handle(this,received,messageType);
+ }
+ }
+ } while(!d->incoming.empty());
+
+ _release();
+}
+
+void Connection::setHints(const vector<string>& hints)
+{
+ vector<string>::const_iterator i;
+
+ for(i = hints.begin(); i != hints.end(); i++)
+ {
+ string key;
+ vector<string> values;
+
+ if(MCOPUtils::tokenize(*i, key, values))
+ {
+ if(values.size() == 1)
+ d->hints[key] = values[0];
+ }
+ }
+}
+
+string Connection::findHint(const string& hint)
+{
+ return d->hints[hint];
+}