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/site.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, 2002 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 "site.hh"
00025 #include "remotesocketsite.hh"
00026 #include "message.hh"
00027 #include "messageblock.hh"
00028 
00029 using namespace VOS;
00030 
00031 #include <stdio.h>
00032 #include <string>
00033 #include <map>
00034 #include <iterator>
00035 #include <queue>
00036 #include <algorithm>
00037 
00038 
00039 #if !defined(HAVE_SOCKLEN_T) && !defined(__socklen_t_defined)
00040 //#warning socklen_t not defined. Defining it as int.
00041 typedef int socklen_t;
00042 #define __socklen_t_defined 1
00043 #endif
00044 
00045 
00046 /** @file
00047     Implements Site.
00048 */
00049 
00050 map<string, Site*> Site::siteTable;
00051 boost::mutex Site::siteTable_mutex;
00052 LocalSite* Site::defaultPeer = 0;
00053 set<int> Site::allOpenSockets;
00054 
00055 Site::Site()
00056     : MetaObject(0)
00057 {
00058 }
00059 
00060 Site::~Site()
00061 {
00062      for(map<string, MessageBlock*>::iterator i = messageBlockTable.begin();
00063         i != messageBlockTable.end();
00064         i++) {
00065         (*i).second->release(); // acquired by: addMessageBlock()
00066     }
00067     for(map<string, Message*>::iterator i = outgoingTraps.begin();
00068         i != outgoingTraps.end();
00069         i++) {
00070         (*i).second->release(); // acquired by: trapOutgoingReply()
00071     }
00072 }
00073 
00074 void Site::addHostAlias(const string& h)
00075 {
00076     if(! hasHostAlias(h)) {
00077         boost::mutex::scoped_lock lock(hostnames_mutex);
00078         boost::mutex::scoped_lock lock2(siteTable_mutex);
00079 
00080         hostnames.insert(h);
00081         acquire(); // released by: removeHostAlias() or removeSite()
00082         siteTable[h]=this;
00083     }
00084     LOG("refcount", 5, "addHostAlias: count is " << getCount());
00085 }
00086 
00087 void Site::removeHostAlias(const string& h)
00088 {
00089     if(hasHostAlias(h)) {
00090         boost::mutex::scoped_lock lock(hostnames_mutex);
00091 
00092         hostnames.erase(h);
00093         release(); // acquired by: addHostAlias() or addSite()
00094     }
00095     LOG("refcount", 5, "removeHostAlias: count is " << getCount());
00096 }
00097 
00098 bool Site::hasHostAlias(const string& h)
00099 {
00100     boost::mutex::scoped_lock lock(hostnames_mutex);
00101     return (hostnames.count(h) > 0);
00102 }
00103 
00104 set<string>& Site::getHostAliases()
00105 {
00106     boost::mutex::scoped_lock lock(hostnames_mutex);
00107     return hostnames;
00108 }
00109 
00110 void Site::addSite(Site* s)
00111 {
00112     removeSite(*s);
00113 
00114     set<string>& v=s->getHostAliases();
00115 
00116     boost::mutex::scoped_lock lock(siteTable_mutex);
00117 
00118     for(set<string>::iterator i=v.begin(); i != v.end(); i++) {
00119         LOG("addSite", 3, "adding " << *i << " to site table");
00120         s->acquire(); // released by: Site::removeSite() or removeHostAlias()
00121         siteTable[*i]=s;
00122     }
00123     LOG("refcount", 5, "addSite: count is " << s->getCount());
00124 }
00125 
00126 void Site::removeSite(Site& s)
00127 {
00128     set<string>& v=s.getHostAliases();
00129 
00130     boost::mutex::scoped_lock lock(siteTable_mutex);
00131 
00132     for(set<string>::iterator i=v.begin(); i != v.end(); i++) {
00133         if(siteTable.count(*i)) {
00134             siteTable.erase(*i);
00135             s.release(); // acquired by: Site::addSite or addHostAlias()
00136         }
00137     }
00138     LOG("refcount", 5, "removeSite: count is " << s.getCount());
00139 }
00140 
00141 struct hostent* Site::hostent_deepcopy(struct hostent* hp)
00142 {
00143     struct hostent* ret = (struct hostent*)malloc(sizeof(struct hostent));
00144 
00145     ret->h_name = strdup(hp->h_name);
00146     int i = 0;
00147     while(hp->h_aliases[i]) i++;
00148     ret->h_aliases = (char**)malloc((i+1) * sizeof(char*));
00149     int n;
00150     for(n = 0; n < i; n++) {
00151         ret->h_aliases[n] = strdup(hp->h_aliases[n]);
00152     }
00153     ret->h_aliases[n] = 0;
00154 
00155     ret->h_addrtype = hp->h_addrtype;
00156     ret->h_length = hp->h_length;
00157 
00158     i=0;
00159     while(hp->h_addr_list[i]) i++;
00160     ret->h_addr_list = (char**)malloc((i+1) * sizeof(char*));
00161     for(n = 0; n < i; n++) {
00162         ret->h_addr_list[n] = (char*)malloc(hp->h_length);
00163         memcpy(ret->h_addr_list[n], hp->h_addr_list[n], hp->h_length);
00164     }
00165     ret->h_addr_list[n] = 0;
00166 
00167     return ret;
00168 }
00169 
00170 struct hostent* Site::gethostbyaddr_locked(const char *addr, int len, int type)
00171 {
00172     static boost::mutex ghba_mutex;
00173 
00174     boost::mutex::scoped_lock lock(ghba_mutex);
00175 
00176     struct hostent* hp = gethostbyaddr(addr, len, type);
00177 
00178     if(! hp) return 0;
00179 
00180     return hostent_deepcopy(hp);
00181 }
00182 
00183 struct hostent* Site::gethostbyname_locked(const char *addr)
00184 {
00185     static boost::mutex ghbn_mutex;
00186 
00187     boost::mutex::scoped_lock lock(ghbn_mutex);
00188 
00189     struct hostent* hp = gethostbyname(addr);
00190 
00191     if(! hp) return 0;
00192 
00193     return hostent_deepcopy(hp);
00194 }
00195 
00196 
00197 void Site::freeHostEnt(struct hostent* hp)
00198 {
00199     free(hp->h_name);
00200     for(int i = 0; hp->h_aliases[i]; i++) free(hp->h_aliases[i]);
00201     free(hp->h_aliases);
00202     for(int i = 0; hp->h_addr_list[i]; i++) free(hp->h_addr_list[i]);
00203     free(hp->h_addr_list);
00204     free(hp);
00205 }
00206 
00207 string Site::detectHostname(int fd, unsigned char ipaddr[4])
00208 {
00209     struct sockaddr_in sa;
00210     socklen_t socklen = sizeof(struct sockaddr_in);
00211     getsockname(fd, (struct sockaddr *)&sa, &socklen);
00212 
00213     long addr = ntohl(sa.sin_addr.s_addr);
00214     char dottedquad[64];
00215     ipaddr[0] = (unsigned int)(addr >> 24) & 0xFF;
00216     ipaddr[1] = (unsigned int)(addr >> 16) & 0xFF;
00217     ipaddr[2] = (unsigned int)(addr >> 8) & 0xFF;
00218     ipaddr[3] = (unsigned int)(addr & 0xFF);
00219     sprintf(dottedquad, "%u.%u.%u.%u", (unsigned int)ipaddr[0], (unsigned int)ipaddr[1],
00220            (unsigned int)ipaddr[2], (unsigned int)ipaddr[3]);
00221 
00222     struct hostent* hp;
00223     int err = 0;
00224 #ifdef HAVE_GETIPNODEBYNAME
00225     hp = getipnodebyaddr((const char*)&sa.sin_addr.s_addr, sizeof(addr), AF_INET, &err);
00226 #else
00227     hp = gethostbyaddr_locked((const char*)&sa.sin_addr.s_addr, sizeof(addr), AF_INET);
00228         err = h_errno;
00229 #endif
00230     if(hp) {
00231         struct hostent* hp2;
00232 #ifdef HAVE_GETIPNODEBYNAME
00233         hp2 = getipnodebyname(hp->h_name, AF_INET, 0, &err);
00234 #else
00235         hp2 = gethostbyname_locked(hp->h_name);
00236         err = h_errno;
00237 #endif
00238 
00239 #ifdef HAVE_GETIPNODEBYNAME
00240         freehostent(hp);
00241 #else
00242         freeHostEnt(hp);
00243 #endif
00244         string ret;
00245         if(hp2) {
00246             return ret = string(hp2->h_name);
00247         } else {
00248             LOG("site", 1, "Warning: gethostbyaddr failed for " << hp->h_name << ".  Using address " << dottedquad << " instead.");
00249             ret = dottedquad;
00250         }
00251 #ifdef HAVE_GETIPNODEBYNAME
00252         freehostent(hp2);
00253 #else
00254         freeHostEnt(hp2);
00255 #endif
00256         return ret;
00257     } else {
00258         LOG("Site", 1, "Warning: gethostbyaddr failed for " << dottedquad << ".  Using that address as it is.");
00259         return dottedquad;
00260     }
00261 }
00262 
00263 Site& Site::findSite(const string& s) throw (NoSuchSiteError)
00264 {
00265     map<string,Site*>::iterator i = siteTable.find(s);
00266     if(i == siteTable.end()) {
00267         char t[256];
00268         snprintf(t, sizeof(t), "%s:%i", s.c_str(), VOS_DEFAULT_PORT);
00269         i=siteTable.find(string(t));
00270         if(i == siteTable.end()) {
00271             try {
00272                 unsigned int c = (unsigned int)s.find(":");
00273                 if(c==string::npos) throw NoSuchSiteError("Bad site name: must be in the form \"host:port\"");
00274                 string h=s.substr(0, c);
00275                 int p=atoi(s.substr(c+1).c_str());
00276 
00277                 RemoteSocketSite* rs = AsyncConnect::connect(h, p, defaultPeer, false);
00278                 rs->getTypes();
00279                 // pass reference through
00280                 return *rs;
00281             } catch(RemoteSite::SiteConnectionError x) {
00282                 LOG("site", 3, "cannot connect to site " << x.what());
00283                 throw NoSuchSiteError(string("Cannot connect to site: ")+x.what());
00284             } catch(TimeoutError) {
00285                 throw NoSuchSiteError(string("Site doesn't want to talk to us (timeout)"));
00286             } catch(runtime_error e) {
00287                 LOG("site", 3, "cannot connect to site " << e.what());
00288                 throw NoSuchSiteError(string("Unknown error: ") + e.what());
00289             }
00290         } else {
00291             ((*i).second)->acquire(); // released by: the caller of this method
00292             return *((*i).second);
00293         }
00294     } else {
00295         ((*i).second)->acquire(); // released by: the caller of this method
00296         return *((*i).second);
00297     }
00298 }
00299 
00300 LocalSite* Site::getDefaultPeer()
00301 {
00302     if(defaultPeer) defaultPeer->acquire(); // released by: the caller of this method
00303     return defaultPeer;
00304 }
00305 
00306 void Site::setDefaultPeer(LocalSite* localsite)
00307 {
00308     if(defaultPeer) defaultPeer->release(); // acquired by: setDefaultPeer()
00309     localsite->acquire(); // released by: setDefaultPeer()
00310     defaultPeer = localsite;
00311 }
00312 
00313 void Site::doSitePeering(LocalSite* ls, RemoteSite* rs, bool isspooftest, bool waitforhello)
00314 {
00315     // This method assumes that the remote site is only owned by this thread,
00316     // so we only have to deal with locking the local site
00317 
00318     ls->acquire(); // released by: RemoteSite destructor
00319     rs->localpeer = ls;
00320 
00321     struct LocalSite::SiteTableEntry* st=new LocalSite::SiteTableEntry();
00322     st->partialMessage=0;
00323     rs->acquire(); // released by: LocalSite::removeRemotePeer()
00324     if(ls->iteratorsUsingPeerSites == 0 && waitforhello) {
00325         ls->peerSites[rs]=st;
00326     } else {
00327         boost::mutex::scoped_lock lock(ls->peerSitesBuffer_mutex);
00328 
00329         /* this is slightly inelegant, but putting it in a pair<> causes gcc to fail (bleh!) */
00330         ls->peerSitesBuffer_rs.push_back(rs);
00331         ls->peerSitesBuffer_st.push_back(st);
00332     }
00333 
00334     rs->defaultContext.setParameter("from", rs->getURL().getString());
00335     rs->defaultContext.setParameter("to", ls->getURL().getString());
00336     rs->defaultContext.setParameter("method", "");
00337 
00338     vRef<Message> m = new Message();
00339     m->setType("message");
00340     m->setMethod("core:hello");
00341 
00342     if(! isspooftest) {
00343         int r = rand();
00344         char s[16];
00345         snprintf(s, sizeof(s), "%i", r);
00346         m->insertField(-1, "antispoof", s);
00347 
00348         m->insertField(-1, "alias", ls->getURL().getHostAndPort());
00349 
00350         set<string>& v = ls->getHostAliases();
00351         for(set<string>::iterator i=v.begin(); i != v.end(); i++) {
00352             if((*i).substr(0, 9) != "localhost"
00353                && (*i) != ls->getURL().getHostAndPort())
00354             {
00355                 m->insertField(-1, "alias", *i);
00356             }
00357         }
00358         rs->setAntiSpoofID(s);
00359     }
00360 
00361     rs->sendMessage(&m);
00362 
00363     if(waitforhello) {
00364         while(rs->isConnected() && !rs->getGreeted()) {
00365             defaultPeer->flushIncomingBuffers();
00366         }
00367     }
00368 }
00369 
00370 const map<string,Site*>& Site::getAllSites()
00371 {
00372     return siteTable;
00373 }
00374 
00375 const string Site::getType()
00376 {
00377     return string("site");
00378 }
00379 
00380 void Site::addMessageBlock(MessageBlock* m)
00381 {
00382     m->acquire(); // released by: addMessageBlock(), removeMessageBlock() or this destructor
00383     map<string, MessageBlock*>::iterator i = messageBlockTable.find(m->getName());
00384     if(i != messageBlockTable.end()) (*i).second->release(); // acquired by: addMessageBlock()
00385     messageBlockTable[m->getName()] = m;
00386 }
00387 
00388 void Site::removeMessageBlock(MessageBlock* m)
00389 {
00390     map<string, MessageBlock*>::iterator i = messageBlockTable.find(m->getName());
00391     if(i != messageBlockTable.end()) {
00392         (*i).second->release(); // acquired by: addMessageBlock()
00393         messageBlockTable.erase(i);
00394     }
00395 }
00396 
00397 MessageBlock* Site::getMessageBlock(const string& s) throw (NoSuchMessageBlockError)
00398 {
00399     map<string, MessageBlock*>::iterator i = messageBlockTable.find(s);
00400     if(i != messageBlockTable.end()) {
00401         (*i).second->acquire(); // released by: the caller of this method
00402         return (*i).second;
00403     } else throw NoSuchMessageBlockError("message block not found");
00404 }
00405 
00406 void Site::sendMessage(Message* m)
00407 {
00408     if(m->getNonce() != "") {
00409         map<string, Message*>::iterator i = outgoingTraps.find(m->getNonce());
00410         if(i != outgoingTraps.end()) {
00411             pREF(MessageContext*, mc, (*i).second->getMessageContext(),
00412                  if(mc) mc->addToReplyRecord(m));
00413             (*i).second->release(); // acquired by: trapOutgoingReply()
00414             outgoingTraps.erase(i);
00415         }
00416     }
00417 }
00418 
00419 void Site::sendMessage(MessageBlock* mb)
00420 {
00421     for(int i = 0; i < mb->numMessages(); i++) {
00422         vRef<Message> m = mb->getMessage(i);
00423         if(m->getNonce() != "") {
00424             map<string, Message*>::iterator i = outgoingTraps.find(m->getNonce());
00425             if(i != outgoingTraps.end()) {
00426                 vRef<MessageContext> mc = (*i).second->getMessageContext();
00427                 if(&mc) mc->addToReplyRecord(&m);
00428                 (*i).second->release(); // acquired by: trapOutgoingReply()
00429                 outgoingTraps.erase(i);
00430             }
00431         }
00432     }
00433 }
00434 
00435 void Site::trapOutgoingReply(Message* m)
00436 {
00437     pREF(MessageContext*, mc, m->getMessageContext(), if(!mc) return; );
00438     string dep = m->getDependency();
00439     unsigned int i=0;
00440     unsigned int n=0;
00441     LOG("site", 3, "Will trap outgoing nonce " << dep);
00442     while(i < dep.size()) {
00443         while(i < dep.size() && dep[i] != ',') i++;
00444         if(outgoingTraps[dep.substr(n, i-n)] == 0) {
00445             m->acquire(); // released by: sendMessage() or destructor
00446             outgoingTraps[dep.substr(n, i-n)] = m;
00447         }
00448         n=++i;
00449     }
00450 }
00451 
00452 Site& Site::getSite()
00453 {
00454     acquire(); // released by: the caller of this method
00455     return *this;
00456 }
00457 
00458 bool Site::getGreeted()
00459 {
00460     return greeted;
00461 }
00462 
00463 void Site::setGreeted(bool g)
00464 {
00465     greeted = g;
00466 }
00467 
00468 
00469 string Site::generateUniqueName()
00470 {
00471     char name[256];
00472     bool inuse;
00473 
00474     do {
00475         try {
00476             snprintf(name, sizeof(name), "%i", rand());
00477             rREF(Vobject&, foo, findObject(name), );
00478             inuse = true;
00479         } catch(Vobject::NoSuchObjectError) {
00480             inuse = false;
00481         }
00482     } while(inuse);
00483     return string(name);
00484 }
00485 
00486 string Site::uniqueName(const char* desiredName) {
00487     string name;
00488     // need to generate unique name?
00489     if(desiredName == 0 || strlen(desiredName) == 0) {
00490         return generateUniqueName();
00491     } else {
00492         name = desiredName;
00493         try {
00494             while(true) {
00495                 vRef<Vobject> o = findObject(name);
00496                 char tmp[256];
00497                 snprintf(tmp, sizeof(tmp), "%s_%i", desiredName, rand());
00498                 name = tmp;
00499             }
00500         } catch(NoSuchObjectError) {
00501             // yay, name is unique
00502         }
00503     }
00504     return name;
00505 }
00506 
00507 void Site::insertMessageFilter(int pos, MessageFilter* mf)
00508 {
00509     if(pos < 0) pos += (int)messagefilters.size() + 1;
00510     messagefilters.insert(messagefilters.begin() + pos, mf);
00511 }
00512 
00513 void Site::removeMessageFilter(int pos)
00514 {
00515     if(pos < 0) pos += (int)messagefilters.size() + 1;
00516     messagefilters.erase(messagefilters.begin() + pos);
00517 }
00518 
00519 void Site::removeMessageFilter(MessageFilter* m)
00520 {
00521     for(unsigned int i = 0; i < messagefilters.size(); i++) {
00522         if(messagefilters[i] == m) {
00523             messagefilters.erase(messagefilters.begin() + i);
00524             i--;
00525         }
00526     }
00527 }
00528 
00529 const deque<MessageFilter*>& Site::getMessageFilters()
00530 {
00531     return messagefilters;
00532 }
00533 
00534 /* Message filter stuff */
00535 
00536 MessageFilter::~MessageFilter() { }
00537 
00538 bool MessageFilter::checkMessage(MessageBlock* m)
00539 {
00540     for(int n = 0; n < m->numMessages(); n++) {
00541         vRef<Message> msg = m->getMessage(n);
00542         if(! checkMessage(&msg)) {
00543             return false;
00544         }
00545     }
00546     return true;
00547 }
00548 
00549 /** Notify Event stuff */
00550 
00551 VobjectNotifyEvent::VobjectNotifyEvent(ChildChangeListener* cl, VobjectEvent& e)
00552     : childlistener(cl), parentlistener(0), typelistener(0), event(e)
00553 {
00554     // the following are released by the destructor
00555     if(RefCounted* rc = dynamic_cast<RefCounted*>(cl)) rc->acquire();
00556     e.acquire();
00557 }
00558 
00559 VobjectNotifyEvent::VobjectNotifyEvent(ParentChangeListener* pl, VobjectEvent& e)
00560     : childlistener(0), parentlistener(pl), typelistener(0), event(e)
00561 {
00562     // the following are released by the destructor
00563     if(RefCounted* rc = dynamic_cast<RefCounted*>(pl)) rc->acquire();
00564     e.acquire();
00565 }
00566 
00567 VobjectNotifyEvent::VobjectNotifyEvent(TypeChangeListener* tl, VobjectEvent& e)
00568     : childlistener(0), parentlistener(0), typelistener(tl), event(e)
00569 {
00570     // the following are released by the destructor
00571     if(RefCounted* rc = dynamic_cast<RefCounted*>(tl)) rc->acquire();
00572     e.acquire();
00573 }
00574 
00575 VobjectNotifyEvent::~VobjectNotifyEvent()
00576 {
00577     if(childlistener) if(RefCounted* rc = dynamic_cast<RefCounted*>(childlistener)) rc->release();
00578     if(parentlistener) if(RefCounted* rc = dynamic_cast<RefCounted*>(parentlistener)) rc->release();
00579     if(typelistener) if(RefCounted* rc = dynamic_cast<RefCounted*>(typelistener)) rc->release();
00580     event.release();
00581 }
00582 
00583 void VobjectNotifyEvent::notify()
00584 {
00585     switch(event.getEvent()) {
00586     case VobjectEvent::TypeInsert:
00587         typelistener->notifyTypeInserted(event);
00588         break;
00589     case VobjectEvent::TypeRemove:
00590         typelistener->notifyTypeRemoved(event);
00591         break;
00592     case VobjectEvent::ParentInsert:
00593         parentlistener->notifyParentInserted(event);
00594         break;
00595     case VobjectEvent::ParentRemove:
00596         parentlistener->notifyParentRemoved(event);
00597         break;
00598     case VobjectEvent::ChildInsert:
00599         childlistener->notifyChildInserted(event);
00600         break;
00601     case VobjectEvent::ChildReplace:
00602         childlistener->notifyChildReplaced(event);
00603         break;
00604     case VobjectEvent::ChildRemove:
00605         childlistener->notifyChildRemoved(event);
00606         break;
00607     default:
00608         LOG("vobject", 0, "Supplied VobjectNotifyEvent::notify with an unsupported event type!");
00609     }
00610 }

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