Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages | Examples

vos/corelibs/vos/remotesite.cc

Go to the documentation of this file.
00001 /*
00002     This file is part of the Virtual Object System of
00003     the Interreality project (http://interreality.org).
00004 
00005     Copyright (C) 2001-2003 Peter Amstutz
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Lesser General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Lesser General Public License for more details.
00016 
00017     You should have received a copy of the GNU Lesser General Public
00018     License along with this library; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00020 
00021     Peter Amstutz <tetron@interreality.org>
00022 */
00023 
00024 #include "remotesite.hh"
00025 #include "message.hh"
00026 
00027 #include <stdio.h>
00028 #include <sys/types.h>
00029 #include <fcntl.h>
00030 #include <errno.h>
00031 #include <cstdarg>
00032 #include <deque>
00033 #include <string>
00034 #include <map>
00035 
00036 using namespace VOS;
00037 
00038 multimap<string, metaobject_extender_t> RemoteSite::remoteObjectExtensionTable;
00039 
00040 RemoteSite::RemoteSite()
00041     : VobjectImplementation("", 0, false), RemoteMetaObject("", 0),
00042       RemoteVobject("", 0), MetaObject(0), localpeer(0), disconnected(false)
00043 {
00044     setGreeted(false);
00045 }
00046 
00047 RemoteSite::~RemoteSite()
00048 {
00049     LOG("remotesite", 4, "deleting " << getURL().getString());
00050     if(localpeer) localpeer->release(); // acquired by: doSitePeering()
00051 }
00052 
00053 LocalSite& RemoteSite::getLocalPeer() throw (NoLocalPeerError)
00054 {
00055     if(! localpeer) throw NoLocalPeerError("Remote site has no local peer (it has probably disconnected).");
00056     localpeer->acquire();
00057     return *localpeer;
00058 }
00059 
00060 void RemoteSite::flushIncomingBuffers()
00061 {
00062     localpeer->flushIncomingBuffers();
00063 }
00064 
00065 void RemoteSite::addNotification(NotifyEvent* ev)
00066 {
00067     localpeer->addNotification(ev);
00068 }
00069 
00070 void RemoteSite::flushNotifications()
00071 {
00072     localpeer->flushNotifications();
00073 }
00074 
00075 void RemoteSite::lockNotificationFlush()
00076 {
00077     localpeer->lockNotificationFlush();
00078 }
00079 
00080 void RemoteSite::unlockNotificationFlush()
00081 {
00082     localpeer->unlockNotificationFlush();
00083 }
00084 
00085 void RemoteSite::sendUpdateMessage(Message* m)
00086 {
00087     try {
00088         if(m->getMethod() == "core:insert-child-update"
00089             || m->getMethod() == "core:set-child-update") {
00090             try {
00091                 for(int i=0; i < m->getNumFields(); ++i) {
00092                     const Message::Field& pos = m->getField(i);
00093                     if(pos.key != "pos") break;
00094                     const Message::Field& name = m->getField(++i);
00095                     if(name.key != "name") break;
00096                     const Message::Field& path = m->getField(++i);
00097                     if(path.key != "path") break;
00098                     deque<string> objtypes;
00099                     if((i+1) < m->getNumFields()) {
00100                         const Message::Field* type = &(m->getField(i+1));
00101                         while(type->key == "type") {
00102                             objtypes.push_back(type->value);
00103                             i++;
00104                             if(i+1 < m->getNumFields()) {
00105                                 type = &(m->getField(i+1));
00106                             } else break;
00107                         }
00108                     }
00109                     bool newobject=false;
00110                     int position=atoi(pos.value.c_str());
00111                     try {
00112                         vRef<ParentChildRelation> c = VobjectImplementation::findChild(name.value);
00113                         URL u(path.value);
00114                         vRef<Site> st = c->child->getSite();
00115                         if(!(c->position == position
00116                              && st->hasHostAlias(u.getHostAndPort())
00117                              && c->child->getURL().getPath() == u.getPath()))
00118                         {
00119                             newobject = true;
00120                         }
00121                     } catch(NoSuchObjectError) {
00122                         newobject = true;
00123                     }
00124                     if(newobject) {
00125                         vRef<RemoteMetaObject> rmo = new RemoteMetaObject(name.value, this);
00126                         // setChild() cannot be done in the constructor or it will crash the constructor
00127                         setChild(position, name.value, &rmo);
00128                         if(objtypes.size()) {
00129                             for(deque<string>::iterator j = objtypes.begin(); j != objtypes.end(); j++) {
00130                                 if((*j).size() > 0) rmo->types.insert(*j);
00131                             }
00132                             for(deque<string>::iterator j = objtypes.begin(); j != objtypes.end(); j++) {
00133                                 if((*j).size() > 0) rmo->handleNewType(*j);
00134                             }
00135                         } else rmo->getTypes();
00136                     }
00137                 }
00138             } catch(Message::NoSuchFieldError) { }
00139         }
00140     } catch(NoSuchObjectError) {
00141     } catch(NoSuchSiteError) {
00142     } catch(URL::BadURLError) {
00143     }
00144 
00145     LOG("refcount", 5, "before sending to RemoteMetaObject::sendUpdateMessage count on message " << m->getCount());
00146     RemoteMetaObject::sendUpdateMessage(m);
00147     LOG("refcount", 5, "after sending to RemoteMetaObject::sendUpdateMessage count on message " << m->getCount());
00148 }
00149 
00150 /* leapfrogs the RemoteVobject setChild, because
00151    there is no way you can connect an object to a remote site directly
00152 */
00153 void RemoteSite::setChild(int position, const string& contextual_name, Vobject* child)
00154     throw (AccessControlError, TimeoutError)
00155 {
00156     if(! child) RemoteVobject::setChild(position, contextual_name, child);
00157     else {
00158         rREF(Site&, s, child->getSite(),
00159              if(&s == this) {
00160                  VobjectImplementation::setChild(this, position, contextual_name, child);
00161              } else throw AccessControlError("Cannot change the child of a remote site like this");
00162             );
00163     }
00164 }
00165 
00166 void RemoteSite::setURL(const URL& u)
00167 {
00168     url = u;
00169 }
00170 
00171 void RemoteSite::excise()
00172 {
00173     for(int i = (int)children.size() - 1; i >= 0; i--) {
00174         ParentChildRelation* c = children[i];
00175         if(c) {
00176             c->acquire();
00177             Vobject* ch = c->child;
00178             if(ch) {
00179                 ch->acquire();
00180                 ch->excise();
00181                 ch->release();
00182             }
00183             c->release();
00184         }
00185     }
00186 
00187     RemoteMetaObject::excise();
00188 
00189     LOG("refcount", 5, "remotesite: done trying to excise, count on this remote site is " << getCount());
00190 
00191     disconnected=true;
00192 
00193     if(localpeer && !localpeer->checkScheduleHoldsSite(this)) {
00194         Site::removeSite(*this);
00195     }
00196 
00197     if(localpeer) {
00198         localpeer->removeRemotePeer(this);
00199         localpeer = 0;
00200     }
00201 
00202 //  site = 0;
00203 //  VobjectImplementation::site = 0;
00204 }
00205 
00206 void RemoteSite::lockChildNotifyOutgoing(Vobject* v)
00207 {
00208     childlockSet.insert(v);
00209 }
00210 
00211 void RemoteSite::unlockChildNotifyOutgoing(Vobject* v, const string& nonce)
00212 {
00213     set<Vobject*>::iterator n = childlockSet.find(v);
00214     if(n != childlockSet.end()) {
00215         childlockSet.erase(n);
00216 
00217         vRef<Message> m = new Message();
00218         m->setType("update");
00219         m->setFrom(v->getURL().getString());
00220         m->setTo(getURL().getString());
00221         m->setMethod("core:set-child-update");
00222         m->setNonce(nonce);
00223 
00224         const ChildList& c = v->getChildren();
00225         for(ChildList::const_iterator i = c.begin(); i != c.end(); i++) {
00226             m->insertField(-1, "pos", (*i)->position);
00227             m->insertField(-1, "name", (*i)->contextual_name);
00228             m->insertField(-1, "path", (*i)->child->getURL().getString());
00229             /*if(meta_cast<Site*>(&(*fromobject))) {
00230                 const TypeSet& ts = getTypes();
00231                 if(ts.size()) {
00232                     for(TypeSet::const_iterator ti = ts.begin(); ti != ts.end(); ti++) {
00233                         m->insertField(-1, "type", *ti);
00234                     }
00235                 } else {
00236                     m->insertField(-1, "type", "");
00237                 }
00238                 }*/
00239         }
00240         sendMessage(&m);
00241     }
00242 }
00243 
00244 
00245 void RemoteSite::lockParentNotifyOutgoing(Vobject* v)
00246 {
00247     parentlockSet.insert(v);
00248 }
00249 
00250 void RemoteSite::unlockParentNotifyOutgoing(Vobject* v, const string& nonce)
00251 {
00252     set<Vobject*>::iterator n = parentlockSet.find(v);
00253     if(n != parentlockSet.end()) {
00254         parentlockSet.erase(n);
00255 
00256         vRef<Message> m = new Message();
00257         m->setType("update");
00258         m->setFrom(v->getURL().getString());
00259         m->setTo(getURL().getString());
00260         m->setMethod("core:insert-parent-update");
00261         m->setNonce(nonce);
00262 
00263         const ParentSet& c = v->getParents();
00264         for(ParentSet::const_iterator i = c.begin(); i != c.end(); i++) {
00265             m->insertField(-1, "pos", (*i)->position);
00266             m->insertField(-1, "name", (*i)->contextual_name);
00267             m->insertField(-1, "path", (*i)->parent->getURL().getString());
00268         }
00269         sendMessage(&m);
00270     }
00271 }
00272 
00273 void RemoteSite::lockTypeNotifyOutgoing(Vobject* v)
00274 {
00275     typelockSet.insert(v);
00276 }
00277 
00278 void RemoteSite::unlockTypeNotifyOutgoing(Vobject* v, const string& nonce)
00279 {
00280     set<Vobject*>::iterator n = typelockSet.find(v);
00281     if(n != typelockSet.end()) {
00282         typelockSet.erase(n);
00283 
00284         vRef<Message> m = new Message();
00285         m->setType("update");
00286         m->setFrom(v->getURL().getString());
00287         m->setTo(getURL().getString());
00288         m->setMethod("core:type-add-update");
00289         m->setNonce(nonce);
00290 
00291         const TypeSet& c = v->getTypes();
00292         for(TypeSet::const_iterator i = c.begin(); i != c.end(); i++) {
00293             m->insertField(-1, "type", *i);
00294         }
00295         sendMessage(&m);
00296     }
00297 }
00298 
00299 
00300 void RemoteSite::notifyChildInserted(VobjectEvent& e)
00301 {
00302     if(childlockSet.count(e.getParent())) return;
00303 
00304     vRef<Message> m = new Message();
00305     m->setType("update");
00306     m->setFrom(e.getParent()->getURL().getString());
00307     m->setTo(getURL().getString());
00308     m->setMethod("core:insert-child-update");
00309 
00310     LOG("notifyChildInserted", 5, "*** here we are! ***");
00311 
00312     char x[16];
00313     snprintf(x, sizeof(x), "%i", e.getPosition());
00314     m->insertField(-1, "pos", string(x));
00315     m->insertField(-1, "name", e.getContextualName());
00316     m->insertField(-1, "path", e.getChild()->getURL().getString());
00317     if(meta_cast<Site*>(e.getParent())) {
00318         const TypeSet& ts = getTypes();
00319         if(ts.size()) {
00320             for(TypeSet::const_iterator ti = ts.begin(); ti != ts.end(); ti++) {
00321                 m->insertField(-1, "type", *ti);
00322             }
00323         } else {
00324             m->insertField(-1, "type", "");
00325         }
00326     }
00327     sendMessage(&m);
00328 }
00329 
00330 void RemoteSite::notifyChildReplaced(VobjectEvent& e)
00331 {
00332     if(childlockSet.count(e.getParent())) return;
00333 
00334     vRef<Message> m = new Message();
00335     m->setType("update");
00336     m->setFrom(e.getParent()->getURL().getString());
00337     m->setTo(getURL().getString());
00338     m->setMethod("core:set-child-update");
00339 
00340     char x[16];
00341     snprintf(x, sizeof(x), "%i", e.getPosition());
00342     m->insertField(-1, "pos", string(x));
00343     m->insertField(-1, "name", e.getContextualName());
00344     m->insertField(-1, "path", e.getChild()->getURL().getString());
00345 
00346     sendMessage(&m);
00347 }
00348 
00349 void RemoteSite::notifyChildRemoved(VobjectEvent& e)
00350 {
00351     if(childlockSet.count(e.getParent())) return;
00352 
00353     vRef<Message> m = new Message();
00354     m->setType("update");
00355     m->setFrom(e.getParent()->getURL().getString());
00356     m->setTo(getURL().getString());
00357     m->setMethod("core:remove-child-update");
00358 
00359     char x[16];
00360     snprintf(x, sizeof(x), "%i", e.getPosition());
00361     m->insertField(-1, "pos", x);
00362     m->insertField(-1, "name", e.getContextualName());
00363     m->insertField(-1, "path", e.getChild()->getURL().getString());
00364 
00365     sendMessage(&m);
00366 }
00367 
00368 void RemoteSite::notifyParentInserted(VobjectEvent& e)
00369 {
00370     if(parentlockSet.count(e.getChild())) return;
00371 
00372     vRef<Message> m = new Message();
00373     m->setType("update");
00374     m->setFrom(e.getChild()->getURL().getString());
00375     m->setTo(getURL().getString());
00376     m->setMethod("core:insert-parent-update");
00377 
00378     char x[16];
00379     snprintf(x, sizeof(x), "%i", e.getPosition());
00380     m->insertField(-1, "pos", string(x));
00381     m->insertField(-1, "name", e.getContextualName());
00382     m->insertField(-1, "path", e.getParent()->getURL().getString());
00383 
00384     sendMessage(&m);
00385 }
00386 
00387 void RemoteSite::notifyParentRemoved(VobjectEvent& e)
00388 {
00389     if(parentlockSet.count(e.getChild())) return;
00390 
00391     vRef<Message> m = new Message();
00392     m->setType("update");
00393     m->setFrom(e.getChild()->getURL().getString());
00394     m->setTo(getURL().getString());
00395     m->setMethod("core:remove-parent-update");
00396 
00397     char x[16];
00398     snprintf(x, sizeof(x), "%i", e.getPosition());
00399     m->insertField(-1, "pos", string(x));
00400     m->insertField(-1, "name", e.getContextualName());
00401     m->insertField(-1, "path", e.getParent()->getURL().getString());
00402 
00403     sendMessage(&m);
00404 }
00405 
00406 void RemoteSite::notifyTypeInserted(VobjectEvent& e)
00407 {
00408     if(typelockSet.count(e.getAffectedObject())) return;
00409 
00410     vRef<Message> m = new Message();
00411     m->setType("update");
00412     m->setFrom(e.getAffectedObject()->getURL().getString());
00413     m->setTo(getURL().getString());
00414     m->setMethod("core:type-add-update");
00415 
00416     m->insertField(-1, "type", e.getNewType());
00417 
00418     sendMessage(&m);
00419 }
00420 
00421 void RemoteSite::notifyTypeRemoved(VobjectEvent& e)
00422 {
00423     vRef<Message> m = new Message();
00424     m->setType("update");
00425     m->setFrom(e.getAffectedObject()->getURL().getString());
00426     m->setTo(getURL().getString());
00427     m->setMethod("core:remove-type-update");
00428 
00429     m->insertField(-1, "type", e.getNewType());
00430 
00431     sendMessage(&m);
00432 }
00433 
00434 void RemoteSite::release()
00435 {
00436     /*if(disconnected
00437        && getHostAliases().size() > 0
00438        && (getCount()-1) == getHostAliases().size()) {
00439         LOG("remotesite", 3, "site is disconnected and not held by anything but site table.  releasing from site table...");
00440         disconnected=false;
00441         Site::removeSite(*this);
00442         }*/
00443     RemoteVobject::release();
00444 }
00445 
00446 void RemoteSite::extendMetaObject(RemoteMetaObject* root, const char* p)
00447 {
00448     pair<MI, MI> g = remoteObjectExtensionTable.equal_range(p);
00449     for(MI it = g.first; it != g.second; it++) {
00450         MetaObject* newext = (*it).second(root, p);
00451     }
00452 }
00453 
00454 #if 0
00455 void RemoteSite::extendMetaObject(RemoteMetaObject* root, ...)
00456 {
00457     va_list ap;
00458     va_start(ap, root);
00459     extendMetaObjectV(root, ap);
00460     va_end(ap);
00461 }
00462 #endif
00463 
00464 
00465 MetaObject* RemoteSite::createMetaObject(const char* desiredname, const deque<string>& typelist)
00466 {
00467     //string name = uniqueName(desiredname);  will be done by the local site anyway
00468     string name = desiredname;
00469     MetaObject* ret = 0;
00470     vRef<Message> m = new Message();
00471     vRef<LocalSite> ls = initFields(this, &m, "core:create-object", true);
00472     m->insertField(-1, "name", name);
00473     for(deque<string>::const_iterator i = typelist.begin(); i != typelist.end(); i++) {
00474         m->insertField(-1, "type", *i);
00475     }
00476     sendMessage(&m);
00477     try {
00478         vRef<Message> r = ls->waitFor(m->getNonce(), this);
00479         try {
00480             const Message::Field f = r->getField("error");
00481             throw AccessControlError(f.value);
00482         } catch(Message::NoSuchFieldError) {
00483             try {
00484                 const Message::Field f = r->getField("path");
00485                 ret = meta_cast<MetaObject*>(&findObjectFromRoot(f.value));
00486             } catch(Message::NoSuchFieldError) {
00487                 throw AccessControlError("reply did not contain path field");
00488             } catch(NoSuchSiteError) {
00489                 throw RemoteError("reply path field illegal");
00490             } catch(NoSuchObjectError x) {
00491                 throw RemoteError(string("could not access newly created object: ") + x.what());
00492             } catch(URL::BadURLError) {
00493                 throw RemoteError("reply path field illegal");
00494             } catch(AccessControlError x) {
00495                 throw x;
00496             } catch(RemoteError x) {
00497                 throw x;
00498             }
00499         }
00500     } catch(exception& e) {
00501         LOG("remotesite", 2, "RemoteVobject::removeChild: caught exception from waitFor: " << e.what());
00502     }
00503     return ret;
00504 }
00505 
00506 MetaObject* RemoteSite::createMetaObject(const char* name, const char* first, ...)
00507 {
00508     MetaObject* ret;
00509     va_list ap;
00510     va_start(ap, first);
00511     deque<string> args;
00512     if(first) {
00513         args.push_back(first);
00514         for(;;) {
00515             char* p=va_arg(ap, char*);
00516             if(p == 0) break;
00517             args.push_back(p);
00518         }
00519     }
00520     try {
00521         ret = createMetaObject(name, args);
00522     } catch(...) {
00523         va_end(ap);
00524         throw;
00525     }
00526     va_end(ap);
00527     return ret;
00528 }
00529 
00530 
00531 #if 0
00532 MetaObject* RemoteSite::createMetaObject(const deque<string>& typelist)
00533 {
00534     return createMetaObject(generateUniqueName(), typelist);
00535 }
00536 
00537 MetaObject* RemoteSite::createMetaObject()
00538 {
00539     return createMetaObjectT(0);
00540 }
00541 MetaObject* RemoteSite::createMetaObjectT(const char* first, ...)
00542 {
00543     MetaObject* ret;
00544     va_list ap;
00545     va_start(ap, first);
00546     deque<string> args;
00547     if(first) args.push_back(first);
00548     if(first) {
00549         for(;;) {
00550             char* p=va_arg(ap, char*);
00551             if(p == 0) break;
00552             args.push_back(p);
00553         }
00554     }
00555     try {
00556         ret = createMetaObject(args);
00557     } catch(...) {
00558         va_end(ap);
00559         throw;
00560     }
00561     va_end(ap);
00562     return ret;
00563 }
00564 
00565 MetaObject* RemoteSite::createMetaObjectV(va_list ap)
00566 {
00567     deque<string> args;
00568     for(;;) {
00569         char* p=va_arg(ap, char*);
00570         if(p == 0) break;
00571         args.push_back(p);
00572     }
00573     return createMetaObject(args);
00574 }
00575 
00576 
00577 MetaObject* RemoteSite::createMetaObjectV(const string& name, va_list ap)
00578 {
00579     deque<string> args;
00580     for(;;) {
00581         char* p=va_arg(ap, char*);
00582         if(p == 0) break;
00583         args.push_back(p);
00584     }
00585     return createMetaObject(name, args);
00586 }
00587 #endif
00588 
00589 void RemoteSite::addRemoteObjectExtension(const char* type, metaobject_extender_t newmethod)
00590 {
00591     remoteObjectExtensionTable.insert(multimap<string, metaobject_extender_t>::value_type(string(type), newmethod));
00592 }
00593 
00594 void RemoteSite::removeRemoteObjectExtension(const char* type, metaobject_extender_t oldmethod)
00595 {
00596     pair<MI, MI> g = remoteObjectExtensionTable.equal_range(type);
00597     for(MI it = g.first; it != g.second; it++) {
00598         if((*it).second == oldmethod) {
00599             remoteObjectExtensionTable.erase(it);
00600             break;
00601         }
00602     }
00603 }
00604 
00605 
00606 void RemoteSite::printExtensionTable(ostream& stream) {
00607     for(MI i = remoteObjectExtensionTable.begin(); i != remoteObjectExtensionTable.end(); i++) {
00608         stream << i->first << endl;
00609     }
00610 }
00611 
00612 void RemoteSite::catchIncomingMessage(const string& nonce)
00613 {
00614     waitingFor[nonce] = pair<bool, Message*>(false, 0);
00615 }
00616 
00617 void RemoteSite::clearCaughtMessage(const string& nonce)
00618 {
00619     if(waitingFor.count(nonce)) {
00620         if(waitingFor[nonce].second)
00621             waitingFor[nonce].second->release(); // acquired by: RemoteSocketSite::flushIncomingBuffers
00622         waitingFor.erase(nonce);
00623     }
00624 }
00625 
00626 bool RemoteSite::messageInProgress(const string& nonce)
00627 {
00628     if(waitingFor.count(nonce)) return waitingFor[nonce].first;
00629     else return false;
00630 }
00631 
00632 bool RemoteSite::messageReady(const string& nonce)
00633 {
00634     if(waitingFor.count(nonce)) return (waitingFor[nonce].second != 0);
00635     else return false;
00636 }
00637 
00638 Message* RemoteSite::retrieveCaughtMessage(const string& nonce)
00639 {
00640     if(waitingFor.count(nonce)) {
00641         Message* m = waitingFor[nonce].second;
00642         if(m) m->acquire(); // released by: the caller of this method
00643         return m;
00644     }
00645     else return 0;
00646 }

Generated on Tue Aug 12 03:55:41 2003 for Interreality Project - VOS by doxygen 1.3.2