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
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
|