Web Wispers 1.2.2 C++ Unit Test Coverage
Current view: top level - ssrc/wispers/session - service.cc (source / functions) Hit Total Coverage
Test: Web Wispers 1.2.2 C++ Unit Tests Lines: 91 117 77.8 %
Date: 2012-04-09 Functions: 18 21 85.7 %
Branches: 83 186 44.6 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright 2006-2009 Savarese Software Research Corporation
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at
       7                 :            :  *
       8                 :            :  *     https://www.savarese.com/software/ApacheLicense-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <ssrc/wispers/session/service.h>
      18                 :            : #include <ssrc/wispers/utility/checkpoint.h>
      19                 :            : 
      20                 :            : 
      21                 :            : __BEGIN_NS_SSRC_WSPR_SESSION
      22                 :            : 
      23                 :            : /**
      24                 :            :  * Only session ids that have already been created can be updated.
      25                 :            :  * Otherwise, insertion attempt is ignored.  This really turns insert
      26                 :            :  * into update.
      27                 :            :  */
      28                 :          2 : void Session::process_request(const MessageInsert & msg, const MessageInfo &) {
      29                 :          2 :   unsigned int i = msg.values.size();
      30                 :            : 
      31         [ +  + ]:          6 :   while(i-- > 0) {
      32                 :          2 :     session_map::iterator && it = find<BySID>(msg.values[i].sid);
      33                 :            : 
      34         [ +  + ]:          2 :     if(it != end<BySID>()) {
      35                 :          1 :       const_cast<SessionData &>(*it).attributes = msg.values[i].attributes;
      36                 :          1 :       touch_session(it);
      37                 :            :     }
      38                 :            :   }
      39                 :          2 : }
      40                 :            : 
      41                 :            : /**
      42                 :            :  *
      43                 :            :  */
      44                 :          4 : void Session::process_request(const MessageCreateSession & msg,
      45                 :            :                               const MessageInfo & msginfo)
      46                 :            : {
      47                 :          4 :   session_map::iterator it(end<BySID>());
      48                 :            : 
      49         [ -  + ]:          4 :   if(!msg.sid.empty())
      50                 :          0 :     it = find<BySID>(msg.sid);
      51                 :            : 
      52         [ +  - ]:          4 :   if(it == end<BySID>())
      53                 :          4 :     it = create_session().first;
      54                 :            : 
      55                 :            :   _caller.reply<CallSingleQueryResult>(Message::FIFOSelfDiscard,
      56                 :          4 :                                        msginfo.sender(), msginfo.token(), *it);
      57                 :          4 : }
      58                 :            : 
      59                 :            : /**
      60                 :            :  *
      61                 :            :  */
      62                 :          3 : void Session::process_request(const MessageGetSession & msg,
      63                 :            :                               const MessageInfo & msginfo)
      64                 :            : {
      65                 :          6 :   MessageSingleQueryResult result;
      66         [ +  - ]:          3 :   session_map::iterator && it = find<BySID>(msg.sid);
      67                 :            : 
      68   [ +  -  +  -  :          3 :   if(it != end<BySID>()) {
                   +  + ]
      69                 :          1 :     result.found  = true;
      70   [ +  -  +  - ]:          1 :     result.result = *it;
      71         [ +  - ]:          1 :     if(msg.update_access_time)
      72         [ +  - ]:          1 :       touch_session(it);
      73                 :            :   }
      74                 :            : 
      75                 :          3 :   _caller.reply<CallSingleQueryResult>(msginfo.sender(), msginfo.token(),
      76         [ +  - ]:          6 :                                        result, Message::FIFOSelfDiscard);
      77                 :          3 : }
      78                 :            : 
      79                 :            : /**
      80                 :            :  *
      81                 :            :  */
      82                 :          1 : void Session::process_request(MessageSetAttributes & msg,
      83                 :            :                               const MessageInfo &)
      84                 :            : {
      85                 :          1 :   session_map::iterator && it = find<BySID>(msg.sid);
      86                 :            : 
      87         [ +  - ]:          1 :   if(it != end<BySID>()) {
      88                 :          1 :     const_cast<SessionData &>(*it).attributes->merge(std::move(msg.attributes));
      89                 :          1 :     touch_session(it);
      90                 :            :   }
      91                 :          1 : }
      92                 :            : 
      93                 :            : /**
      94                 :            :  *
      95                 :            :  */
      96                 :          0 : void Session::update_session(const SessionData & update) {
      97                 :          0 :   session_map::iterator && it = find<BySID>(update.sid);
      98                 :            : 
      99         [ #  # ]:          0 :   if(it != end<BySID>()) {
     100                 :          0 :     SessionData session = *it;
     101   [ #  #  #  # ]:          0 :     get_index<BySID>().erase(it);
     102                 :          0 :     session.uid = update.uid;
     103         [ #  # ]:          0 :     session.attributes = update.attributes;
     104                 :          0 :     _touch_session(session);
     105                 :            : 
     106         [ #  # ]:          0 :     index_by_uid & index = get_index<ByUID>();
     107         [ #  # ]:          0 :     index_by_uid::iterator && uit = find<ByUID>(session.uid);
     108                 :            : 
     109   [ #  #  #  #  :          0 :     if(uit != end<ByUID>()) {
                   #  # ]
     110                 :            :       // We don't need to send an expiration message because the next
     111                 :            :       // client action requiring a session will clear the session.
     112                 :            :       // Everything else (e.g., EventQueue) indexes on uid.
     113         [ #  # ]:          0 :       index.erase(uit);
     114                 :            :     }
     115                 :            : 
     116         [ #  # ]:          0 :     insert<BySID>(session);
     117                 :            :   }
     118                 :          0 : }
     119                 :            : 
     120                 :          0 : void Session::process_request(const MessageLogoutSession & msg,
     121                 :            :                               const MessageInfo &)
     122                 :            : {
     123                 :          0 :   index_by_uid & index = get_index<ByUID>();
     124                 :          0 :   index_by_uid::iterator && it = find<ByUID>(msg.session.uid);
     125                 :            : 
     126         [ #  # ]:          0 :   if(it != end<ByUID>()) {
     127                 :          0 :     index.erase(it);
     128                 :          0 :     MessageExpireSession expire;
     129         [ #  # ]:          0 :     expire.sessions.push_back(msg.session.uid);
     130         [ #  # ]:          0 :     _caller.send<CallExpireSession>(protocol_traits::event_group_expire(),
     131   [ #  #  #  # ]:          0 :                                     expire);
     132                 :            :   }
     133                 :          0 : }
     134                 :            : 
     135                 :            : /**
     136                 :            :  *
     137                 :            :  */
     138                 :          5 : void Session::load_checkpoint(const std::string & filename)
     139                 :            :   SSRC_DECL_THROW(std::runtime_error, boost::archive::archive_exception)
     140                 :            : {
     141                 :          5 :   NS_SSRC_WSPR_UTILITY::load_checkpoint(_checkpoint_path, super::_index);
     142                 :            : 
     143         [ +  + ]:          8 :   for(index_by_sid::iterator it = begin<BySID>(); it != end<BySID>(); ++it)
     144                 :          3 :     touch_session(it);
     145                 :          5 : }
     146                 :            : 
     147                 :            : /**
     148                 :            :  *
     149                 :            :  */
     150                 :         10 : void Session::transition(State state) {
     151   [ +  +  -  - ]:         10 :   switch(state) {
     152                 :            :   case Starting:
     153         [ +  - ]:          5 :     _caller.join(protocol_traits::service_group());
     154         [ +  - ]:          5 :     _caller.join(protocol_traits::event_group_login());
     155         [ +  - ]:          5 :     _caller.join(protocol_traits::event_group_logout());
     156                 :            :     _poll_timeout = 
     157                 :          5 :       schedule_timeout(boost::bind(&Session::check_for_expirations, this),
     158   [ +  -  +  -  :         10 :                        TimeValue(_poll_interval, 0));
                   +  - ]
     159                 :          5 :     state = Started;
     160                 :          5 :     break;
     161                 :            :   case Stopping:
     162         [ +  - ]:          5 :     if(_poll_timeout)
     163                 :          5 :       cancel_timeout(_poll_timeout);
     164         [ +  - ]:          5 :     _caller.leave(protocol_traits::event_group_logout());
     165         [ +  - ]:          5 :     _caller.leave(protocol_traits::event_group_login());
     166         [ +  - ]:          5 :     _caller.leave(protocol_traits::service_group());
     167                 :          5 :     state = Stopped;
     168                 :            :     //break;
     169                 :            :   case Stopped:
     170                 :            :     // TODO: remove this after we implement graceful restarts/upgrades.
     171                 :            :     //expire_sessions(boost::integer_traits<idle_count_type>::const_max);
     172                 :          5 :     NS_SSRC_WSPR_UTILITY::save_checkpoint(_checkpoint_path, super::_index);
     173                 :          5 :     break;
     174                 :            :   default:
     175                 :          0 :     break;
     176                 :            :   }
     177                 :            : 
     178                 :         10 :   super::transition(state);
     179                 :         10 : }
     180                 :            : 
     181                 :            : /**
     182                 :            :  *
     183                 :            :  */
     184                 :          5 : Session::Session(super::caller_type & caller,
     185                 :            :                  const SessionInitializer & initializer)
     186                 :            :   SSRC_DECL_THROW(std::runtime_error, boost::archive::archive_exception) :
     187                 :            :   super(caller), _random_id(),
     188                 :            :   _expirations_per_message(initializer.expirations_per_message),
     189                 :            :   _poll_interval(initializer.poll_interval),
     190                 :            :   _max_idle_time(initializer.max_idle_time),
     191                 :            :   _low_count(0), _touch_session(_max_idle_time / _poll_interval),
     192   [ +  -  +  -  :          5 :   _poll_timeout(), _checkpoint_path(initializer.checkpoint_path)
                   +  - ]
     193                 :            : {
     194   [ +  -  +  -  :          5 :   add_service_type(protocol_traits::service_type());
                   +  - ]
     195                 :            : 
     196         [ +  - ]:          5 :   WISP_SERVICE_REQUEST(MessageCreateSession);
     197         [ +  - ]:          5 :   WISP_SERVICE_REQUEST(MessageSetAttributes);
     198         [ +  - ]:          5 :   WISP_SERVICE_REQUEST(MessageGetSession);
     199         [ +  - ]:          5 :   WISP_SERVICE_REQUEST(MessageUpdateSession);
     200         [ +  - ]:          5 :   WISP_SERVICE_REQUEST(MessageLoginSession);
     201         [ +  - ]:          5 :   WISP_SERVICE_REQUEST(MessageLogoutSession);
     202                 :            : 
     203         [ +  - ]:          5 :   load_checkpoint(_checkpoint_path);
     204                 :          5 : }
     205                 :            : 
     206                 :          1 : void Session::expire_sessions(const idle_count_type low_count) {
     207                 :          1 :   index_by_access & index = get_index<ByLastAccess>();
     208                 :          1 :   index_by_access::iterator upper = index.upper_bound(low_count);
     209                 :          1 :   index_by_access::iterator it = index.begin();
     210                 :          2 :   MessageExpireSession msg;
     211                 :          1 :   unsigned int count = 0;
     212                 :            : 
     213   [ +  -  -  + ]:          1 :   do {
     214   [ +  -  +  +  :          3 :     while(it != upper && count < _expirations_per_message) {
             +  -  +  + ]
     215   [ +  -  +  - ]:          1 :       msg.sessions.push_back(it->uid);
     216         [ +  - ]:          1 :       it = index.erase(it);
     217                 :          1 :       ++count;
     218                 :            :     }
     219                 :            : 
     220   [ +  -  +  - ]:          1 :     if(msg.sessions.size() > 0) {
     221         [ +  - ]:          1 :       _caller.send<CallExpireSession>(protocol_traits::event_group_expire(),
     222   [ +  -  +  - ]:          1 :                                       msg);
     223         [ +  - ]:          1 :       msg.sessions.clear();
     224                 :            :     }
     225                 :            :   } while(it != upper);
     226                 :          1 : }
     227                 :            : 
     228                 :            : /**
     229                 :            :  *
     230                 :            :  */
     231                 :          6 : string Session::create_sid() {
     232         [ +  - ]:          6 :   sid_type sid(SessionIdNumChars, ' ');
     233         [ +  - ]:          6 :   session_map::iterator && end_ = end<BySID>();
     234                 :            : 
     235   [ +  -  -  + ]:          6 :   do {
     236         [ +  - ]:          6 :     _random_id(sid);
     237                 :            :     // TODO: Protect against accidental infinite loop (e.g., if we fill up)!
     238         [ +  - ]:          6 :   } while(find<BySID>(sid) != end_);
     239                 :            : 
     240                 :          6 :   return sid;
     241                 :            : }
     242                 :            : 
     243                 :            : 
     244                 :            : 
     245   [ +  -  +  -  :         17 : __END_NS_SSRC_WSPR_SESSION
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]