reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
QValueTargetHandler.cxx
Go to the documentation of this file.
2
3
6#include "repro/Proxy.hxx"
9
10#include "rutil/Data.hxx"
11#include "rutil/Logger.hxx"
12#include "repro/ProxyConfig.hxx"
14
15#define RESIPROCATE_SUBSYSTEM resip::Subsystem::REPRO
16
17namespace repro
18{
19
21 Processor("QValueTargetHandler")
22{
24
25 if(config.getConfigData("QValueBehavior", "") =="FULL_SEQUENTIAL")
26 {
28 }
29 else if(config.getConfigData("QValueBehavior", "") == "FULL_PARALLEL")
30 {
32 }
33
34 mCancelBetweenForkGroups=config.getConfigBool("QValueCancelBetweenForkGroups", true);
35 mWaitForTerminate=config.getConfigBool("QValueWaitForTerminateBetweenForkGroups", true);
36 mDelayBetweenForkGroups=config.getConfigInt("QValueMsBetweenForkGroups", 3000);
37 mCancellationDelay=config.getConfigInt("QValueMsBeforeCancel", 30000);
38}
39
43
46{
47 std::vector<resip::Data> nextCancelTids;
48 std::vector<resip::Data> nextBeginTids;
49
50 Proxy* proxy=&(rc.getProxy());
51
52 resip::Data tid = rc.getTransactionId();
53 ResponseContext& rsp=rc.getResponseContext();
54 bool shouldContinue=true;
55
56 //Use this as a loop invariant.
57 bool bail=false;
58
59 resip::Message* msg = rc.getCurrentEvent();
60 resip_assert(msg);
61
62 if(msg)
63 {
65
66 if(fc)
67 {
68 shouldContinue=false;
69 std::vector<resip::Data>::iterator i;
70
71 //Might we have scheduled cancellations? If so, is there anything else
72 //worth trying? (We won't cancel stuff if there is nothing else left
73 //to try)
74 if(mCancelBetweenForkGroups && rsp.hasCandidateTransactions())
75 {
76 std::vector<resip::Data>& cancelTids = fc->mTransactionsToCancel;
77 for(i = cancelTids.begin(); i != cancelTids.end(); i++)
78 {
79 //Calling cancelClientTransaction on an already cancelled
80 //target is safe, and usually more efficient than checking
81 //beforehand.
82 rsp.cancelClientTransaction(*i);
83 }
84 }
85
86 //Might we have scheduled some transactions to start?
87 //(and if we did, should we now schedule them for cancellation later?)
89 {
90 std::vector<resip::Data>& beginTids=fc->mTransactionsToProcess;
91 for(i=beginTids.begin();i!=beginTids.end();i++)
92 {
93 //Calling beginClientTransaction on an already active
94 // (or Terminated) transaction is safe, and more
95 // efficient than checking beforehand.
96 rsp.beginClientTransaction(*i);
98 {
99 nextCancelTids.push_back(*i);
100 }
101 }
102 }
103 }
104 else
105 {
106 DebugLog(<<"No ForkControlMessage for me.");
107 }
108 }
109
110 std::list<std::list<resip::Data> >& targetCollection =
111 rsp.mTransactionQueueCollection;
112 std::list<std::list<resip::Data> >::iterator outer;
113 std::list<std::list<resip::Data> >::iterator temp;
114 std::list<resip::Data>::iterator inner;
115 bool activeTargets=false;
116 bool startedTargets=false;
117
118 for(outer=targetCollection.begin();
120 {
121 inner=outer->begin();
122
123 if(inner!=outer->end() && isMyType(rsp.getTarget(*inner)))
124 {
125 DebugLog(<<"QValueTargetHandler: "
126 <<"Found a queue of QValueTargets. Are any of them active?");
127 //Are there active targets in this queue already?
128 bail=false;
129 for(;inner!=outer->end() && !bail;inner++)
130 {
131 if(rsp.isActive(*inner))
132 {
133 activeTargets=true;
134 DebugLog(<<"There are active targets. "
135 <<"I don't need to do anything else yet.");
136 bail=true;
137 }
138 }
139
140 //If no active targets, we need to start some new ones.
141 //(and schedule their cancellation if configured to)
142 //However, calling beginClientTransaction does not guarantee that a
143 //target will start, since that target may be a duplicate.
144 //So, we keep firing up target groups until something sticks, or we hit
145 //the end of this queue.
146 bail=false;
147 while(!activeTargets && !bail)
148 {
149 DebugLog(<<"There are no active targets here. "
150 <<"Looking for a group to start.");
151 std::vector<resip::Data> beginTargets;
152
154
155 if(beginTargets.empty())
156 {
157 DebugLog(<<"There are no more targets to start in this queue."
158 <<" Trying to find another queue to work on.");
159 bail=true;
160 }
161 else
162 {
163 DebugLog(<<"This queue has a group of targets in it. "
164 <<"Trying to start this group.");
165 std::vector<resip::Data>::iterator i;
166 for(i=beginTargets.begin();i!=beginTargets.end();i++)
167 {
168 bool success = rsp.beginClientTransaction(*i);
169 if(success && mCancelBetweenForkGroups)
170 {
171 nextCancelTids.push_back(*i);
172 }
173
174 activeTargets |= success;
175 startedTargets |= success;
176 }
178 {
179 DebugLog(<<"Successfully started some targets.");
180 }
181 else
182 {
183 DebugLog(<<"None of these Targets were valid!"
184 << " Moving on to another group.");
185 }
186 }
187 }
188
189 if(!startedTargets)
190 {
191 DebugLog(<< "There weren't any valid Targets in this queue!");
192 }
193 //If we just started some targets, and we are not supposed to wait
194 //for these targets to terminate before beginning the next group
195 //in this queue, we should schedule the next group now.
196 //If there is no next group, nextBeginTids will be empty.
198 {
199 DebugLog(<<"Now I need to schedule the next group of Targets.");
201 }
202
203 //Clean up the queue we just tried
205 }
206
207 if(outer->empty())
208 {
209 temp=outer;
210 outer++;
211 targetCollection.erase(temp);
212 }
213 else
214 {
215 outer++;
216 }
217
219 }
220
221 //Do we have anything to schedule for later?
222 if(!nextCancelTids.empty() || !nextBeginTids.empty())
223 {
224 // If the delays are equal, then put both cancel and nextBeginTids in one ForkControlMessage
226 {
228 fork->mTransactionsToProcess=nextBeginTids;
229 fork->mTransactionsToCancel=nextCancelTids;
230
232 dynamic_cast<resip::ApplicationMessage*>(fork);
233
234 proxy->postMS(std::unique_ptr<resip::ApplicationMessage>(app),
236 }
237 else // Issue two seperate ForkControlMessages
238 {
239 if(!nextCancelTids.empty())
240 {
241 ForkControlMessage* cancel = new ForkControlMessage(*this,tid,proxy);
243
245 dynamic_cast<resip::ApplicationMessage*>(cancel);
246
247 rc.getProxy().postMS(std::unique_ptr<resip::ApplicationMessage>(app),
249 }
250 if(!nextBeginTids.empty())
251 {
252 ForkControlMessage* begin = new ForkControlMessage(*this,tid,proxy);
254
256 =dynamic_cast<resip::ApplicationMessage*>(begin);
257
258 proxy->postMS(std::unique_ptr<resip::ApplicationMessage>(app),
260 }
261 }
262 }
263
264 //We should not pass control on to the rest of the chain until all
265 //of the QValueTargets have been taken care of. Also, we should not
266 //pass control to the rest of the chain if we received a
267 //ForkControlMessage explicitly intended for us.
268 //(this could confuse the other Target Processors)
270 {
271 return Processor::Continue;
272 }
273 else
274 {
276 }
277}
278
279void
281 const std::list<resip::Data> & queue,
282 const ResponseContext& rsp) const
283{
284 if(queue.empty())
285 {
286 return;
287 }
288
289 std::list<resip::Data>::const_iterator i = queue.begin();
290 int currentQ=0;
291
292 //Find the first Candidate target in the queue.
293 for(i=queue.begin();i!=queue.end();i++)
294 {
295 if(rsp.isCandidate(*i))
296 {
297 currentQ=rsp.getTarget(*i)->getPriority();
298 break;
299 }
300 }
301
302 switch(mForkBehavior)
303 {
304 case FULL_SEQUENTIAL:
305 if(i!=queue.end())
306 {
307 fillHere.push_back(*i);
308 }
309 break;
310
311 case EQUAL_Q_PARALLEL:
312 while(i!=queue.end() && rsp.getTarget(*i)->getPriority()==currentQ)
313 {
314 fillHere.push_back(*i);
315 i++;
316 }
317 break;
318
319 case FULL_PARALLEL:
320 while(i!=queue.end())
321 {
322 fillHere.push_back(*i);
323 i++;
324 }
325 break;
326
327 default:
328 ErrLog(<<"mForkBehavior is not defined! How did this happen?");
329 }
330}
331
332bool
334{
335 QValueTarget* qt = dynamic_cast<QValueTarget*>(target);
336 if(qt)
337 {
338 return true;
339 }
340 else
341 {
342 return false;
343 }
344}
345
346void
347QValueTargetHandler::removeTerminated(std::list<resip::Data> & queue,
348 const ResponseContext& rsp) const
349{
350 std::list<resip::Data>::iterator i = queue.begin();
351
352 while(i!=queue.end())
353 {
354 if(rsp.isTerminated(*i))
355 {
356 std::list<resip::Data>::iterator temp=i;
357 i++;
358 queue.erase(temp);
359 }
360 else
361 {
362 i++;
363 }
364 }
365}
366
367void
372}
373
374/* ====================================================================
375 * The Vovida Software License, Version 1.0
376 *
377 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
378 *
379 * Redistribution and use in source and binary forms, with or without
380 * modification, are permitted provided that the following conditions
381 * are met:
382 *
383 * 1. Redistributions of source code must retain the above copyright
384 * notice, this list of conditions and the following disclaimer.
385 *
386 * 2. Redistributions in binary form must reproduce the above copyright
387 * notice, this list of conditions and the following disclaimer in
388 * the documentation and/or other materials provided with the
389 * distribution.
390 *
391 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
392 * and "Vovida Open Communication Application Library (VOCAL)" must
393 * not be used to endorse or promote products derived from this
394 * software without prior written permission. For written
395 * permission, please contact vocal@vovida.org.
396 *
397 * 4. Products derived from this software may not be called "VOCAL", nor
398 * may "VOCAL" appear in their name, without prior written
399 * permission of Vovida Networks, Inc.
400 *
401 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
402 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
403 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
404 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
405 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
406 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
407 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
408 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
409 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
410 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
411 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
412 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
413 * DAMAGE.
414 *
415 * ====================================================================
416 */
#define DebugLog(args_)
Definition Logger.hxx:128
#define ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
std::vector< resip::Data > mTransactionsToProcess
std::vector< resip::Data > mTransactionsToCancel
virtual bool isMyType(Target *target) const
void fillNextTargetGroup(std::vector< resip::Data > &fillHere, const std::list< resip::Data > &queue, const ResponseContext &rsp) const
virtual void removeTerminated(std::list< resip::Data > &queue, const ResponseContext &rsp) const
QValueTargetHandler(ProxyConfig &config)
void setCancelBetweenForkGroups(bool enabled)
virtual processor_action_t process(RequestContext &)
A base-class for messages used by applications.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
The base-class used for message-passing.
Definition Message.hxx:21
This Class is used to implement a primitive form of RPC using loose XML formatting.
void list()
Definition userAdmin.cxx:66