srv-hosts.cpp

Go to the documentation of this file.
00001 /*
00002  * srv-hosts.cpp
00003  *
00004  * Copyright (C) 2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  * Host management.  See srv-hosts.h
00031  */
00032 
00033 // includes -------------------------------------------------------------------
00034 #include "srv-hosts.h"          // always include our own header first!
00035 
00036 #include "common/wave_ex.h"
00037 
00038 #include "threadsafe/threadsafe_map.h"
00039 
00040 
00041 namespace aesop {
00042 
00043 
00044 HostManager::~HostManager(void) throw() { }
00045 
00046 
00047 
00049 //
00050 //      HostMgr -- object that implements the HostManager interface
00051 //
00053 
00054 class HostMgr : public HostManager {
00055 public:
00056         HostMgr(void) throw();
00057         ~HostMgr(void) throw() { }
00058 
00059         // public class methods ------------------------------------------------
00060         void initialize(IN int udpSize);
00061 
00062         // aesop::HostManager class interface methods --------------------------
00063         void addHost(IN conn_id_t hostId,
00064                                 IN long udpToken,
00065                                 IN const char * publicKey);
00066         bool getHostByUdpConnectionID(IN conn_id_t udpConnID,
00067                                 OUT host_rec_t& hr);
00068         bool getHostByTcpConnectionID(IN conn_id_t tcpConnID,
00069                                 OUT host_rec_t& hr);
00070         void updateHost(IN host_rec_t& hr);
00071         bool removeHost(IN conn_id_t hostId);
00072         void getIterator(OUT iterator_t& iterator);
00073         bool getNextHost(IO iterator_t& iterator,
00074                                 OUT host_rec_t& pr);
00075 
00076 private:
00077         // private typedefs ----------------------------------------------------
00078         struct host_data_t {
00079                 host_rec_t      hr;
00080         };
00081 
00082         typedef threadsafe_map<conn_id_t, smart_ptr<host_data_t> > host_map_t;
00083 
00084         // private helper methods ----------------------------------------------
00085         static host_map_t::iterator_t * castIterator(IN iterator_t& i) throw() {
00086                         return (host_map_t::iterator_t *) &i;
00087                 }
00088 
00089         // private member data -------------------------------------------------
00090         host_map_t                      m_hosts;
00091         int                             m_udpSize;
00092 };
00093 
00094 
00095 
00096 HostMgr::HostMgr(void)
00097 throw()
00098 {
00099         m_udpSize = 0;
00100 }
00101 
00102 
00103 
00104 void
00105 HostMgr::initialize
00106 (
00107 IN int udpSize
00108 )
00109 {
00110         ASSERT(udpSize > 63 && udpSize <= 1024, "Bad udp size: %d", udpSize);
00111 
00112         m_udpSize = udpSize;
00113 
00114         // verify public iterator size
00115         ASSERT2(sizeof(iterator_t) >= sizeof(host_map_t::iterator_t),
00116             "Public iterator is too small!  " << sizeof(iterator_t) 
00117             << " bytes vs. " << sizeof(host_map_t::iterator_t) << " bytes.");
00118 }
00119 
00120 
00121 
00123 //
00124 //      HostMgr -- aesop::HostManager class interface methods
00125 //
00127 
00128 void
00129 HostMgr::addHost
00130 (
00131 IN conn_id_t hostId,
00132 IN long udpToken,
00133 IN const char * publicKey
00134 )
00135 {
00136         ASSERT(hostId, "null");
00137         ASSERT(udpToken, "null");
00138         ASSERT(publicKey, "null");
00139 
00140         // quick check--already have a host here?
00141         // This can fail due to race conditions!  But this should catch
00142         //      obvious errors.
00143         smart_ptr<host_data_t> hd;
00144         if (m_hosts.lookup(hostId, hd)) {
00145                 DPRINTF("Already have a host record for conn_id=%lu",
00146                     (long) hostId);
00147                 return;
00148         }
00149 
00150         // set up new host data
00151         hd = new host_data_t;
00152         ASSERT(hd, "out of memory");
00153         host_rec_t& hr = hd->hr;        // convenient reference
00154 
00155         hr.mode = eHostMode_Connected;
00156         hr.udpConn = hostId;
00157         hr.udpToken = udpToken;
00158         hr.netQueue = netrq::Queue::create();
00159         hr.desKey = crypto::DESKey::create();
00160         hr.outbuf = xdrbuf::Output::create(m_udpSize);
00161         hr.publicKey = crypto::RSAPublicKey::create(publicKey);
00162 
00163         // all good!
00164         m_hosts.insert(hostId, hd);
00165 }
00166 
00167 
00168 
00169 bool
00170 HostMgr::getHostByUdpConnectionID
00171 (
00172 IN conn_id_t hostId,
00173 OUT host_rec_t& hr
00174 )
00175 {
00176         ASSERT(hostId, "null");
00177 
00178         hr.clear();
00179 
00180         smart_ptr<host_data_t> hd;
00181         if (!m_hosts.lookup(hostId, hd))
00182                 return false;           // not found!
00183 
00184         // copy over fields
00185         hr = hd->hr;
00186 
00187         // done
00188         return true;
00189 }
00190 
00191 
00192 
00193 bool
00194 HostMgr::getHostByTcpConnectionID
00195 (
00196 IN conn_id_t tcpConnID,
00197 OUT host_rec_t& hr
00198 )
00199 {
00200         hr.clear();
00201         // For efficiency, we could keep a 2nd map.
00202         // However, these lookups are infrequent (occasional TCP message).
00203         // So we just iterate every time we are asked.
00204 
00205         host_map_t::iterator_t i;
00206         m_hosts.getIterator(i);
00207 
00208         conn_id_t hostId;
00209         smart_ptr<host_data_t> hd;
00210         while (m_hosts.getNextElement(i, hostId, hd)) {
00211                 if (tcpConnID == hd->hr.tcpConn) {
00212                         // matched!
00213                         hr = hd->hr;
00214                         return true;
00215                 }
00216         }
00217 
00218         // failed to find tcp connection id!
00219         return false;
00220 }
00221 
00222 
00223 
00224 void
00225 HostMgr::updateHost
00226 (
00227 IN host_rec_t& hr
00228 )
00229 {
00230         ASSERT(hr.udpConn, "null");
00231 
00232         smart_ptr<host_data_t> hd;
00233         if (!m_hosts.lookup(hr.udpConn, hd)) {
00234                 DPRINTF("Attempting to update a non-existent host?");
00235                 return;
00236         }
00237         ASSERT(hd, "null host data in map");
00238 
00239         // copy over for now
00240         // TODO: is this safe?  Could have multiple threads reading as this is
00241         //      updating.
00242         //  This is believed to be safe, since all components (primitive types
00243         //      or smart_ptrs) are threadsafe. 
00244         hd->hr = hr;
00245 }
00246 
00247 
00248 
00249 bool
00250 HostMgr::removeHost
00251 (
00252 IN conn_id_t hostId
00253 )
00254 {
00255         ASSERT(hostId, "null");
00256 
00257         return m_hosts.remove(hostId);
00258 }
00259 
00260 
00261 
00262 void
00263 HostMgr::getIterator
00264 (
00265 OUT iterator_t& iterator
00266 )
00267 {
00268         host_map_t::iterator_t * ri = castIterator(iterator);
00269         ASSERT(ri, "null");
00270 
00271         m_hosts.getIterator(*ri);
00272 }
00273 
00274 
00275 
00276 bool
00277 HostMgr::getNextHost
00278 (
00279 IO iterator_t& iterator,
00280 OUT host_rec_t& hr
00281 )
00282 {
00283         hr.clear();
00284 
00285         host_map_t::iterator_t * ri = castIterator(iterator);
00286         ASSERT(ri, "null");
00287 
00288         conn_id_t hostId;
00289         smart_ptr<host_data_t> hd;
00290         if (!m_hosts.getNextElement(*ri, hostId, hd))
00291                 return false;
00292 
00293         hr = hd->hr;
00294         return true;
00295 }
00296 
00297 
00298 
00300 //
00301 //      HostMgr -- private helper methods
00302 //
00304 
00305 
00306 
00308 //
00309 //      public API
00310 //
00312 
00313 smart_ptr<HostManager>
00314 HostManager::create
00315 (
00316 IN int udpSize
00317 )
00318 {
00319         ASSERT(udpSize > 0, "bad udp size: %d", udpSize);
00320 
00321         smart_ptr<HostMgr> local = new HostMgr;
00322         ASSERT(local, "out of memory");
00323 
00324         local->initialize(udpSize);
00325 
00326         return local;
00327 }
00328 
00329 
00330 
00331 };      // aesop namespace
00332