An Overlay-based
Virtual Network Substrate
SpoVNet

source: source/ariba/utility/transport/tcpip/protlib/timer_module.cpp @ 5284

Last change on this file since 5284 was 5284, checked in by mies, 10 years ago

+ added new transport modules and adapted ariba to them
+ exchange endpoint descriptors an link establishment
+ clean up of base communication
+ link establishment with in the presence of multiple endpoints
+ local discovery for ipv6, ipv4 and bluetooth mac addresses

File size: 18.9 KB
Line 
1/// ----------------------------------------*- mode: C++; -*--
2/// @file timer_module.cpp
3/// timer module that maintains timers and triggers messages
4/// ----------------------------------------------------------
5/// $Id: timer_module.cpp 2756 2007-08-06 12:51:39Z bless $
6/// $HeadURL: https://svn.ipv6.tm.uka.de/nsis/protlib/trunk/src/timer_module.cpp $
7// ===========================================================
8//                     
9// Copyright (C) 2005-2007, all rights reserved by
10// - Institute of Telematics, Universitaet Karlsruhe (TH)
11//
12// More information and contact:
13// https://projekte.tm.uka.de/trac/NSIS
14//                     
15// This program is free software; you can redistribute it and/or modify
16// it under the terms of the GNU General Public License as published by
17// the Free Software Foundation; version 2 of the License
18//
19// This program is distributed in the hope that it will be useful,
20// but WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22// GNU General Public License for more details.
23//
24// You should have received a copy of the GNU General Public License along
25// with this program; if not, write to the Free Software Foundation, Inc.,
26// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27//
28// ===========================================================
29/** @ingroup timermodule
30 * The timer module provides a way for other modules to set timers via a
31 * message and receive a message back on their queue when the timer goes
32 * off.
33 */
34
35#include <sstream>
36
37#include "timer_module.h"
38#include "queuemanager.h"
39#include "logfile.h"
40#include "cleanuphandler.h"
41
42namespace protlib {
43
44/** @addtogroup timermodule Timer Module
45 * @{
46 */
47
48  using namespace log;
49
50/***** class TimerMsg *****/
51
52TimerMsg::TimerMsg(qaddr_t s, bool s_err)
53  : message(type_timer,s),
54    time_sec(0),
55    time_msec(0),
56    action(ac_ignore),
57    param1(NULL),
58    param2(NULL),
59    ok(true),
60    send_error(s_err),
61    relative(true)
62{
63  // Log(DEBUG_LOG,LOG_NORMAL,"TimerMsg","TimerMsg constructor. msgid:" << get_id());
64} // end TimerMsg
65
66/** Destructor, does nothing. */
67TimerMsg::~TimerMsg() {}
68
69
70/** Set result flag and get old value.
71 * You should not set this, this is done by the timer module.
72 */
73bool TimerMsg::set_ok(bool r) {
74        register bool old = ok;
75        ok = r;
76        return old;
77} // end set_ok
78
79/** Prepare message to start an absolute timer. */
80bool TimerMsg::start_absolute(int32 sec, int32 msec, param_t p1, param_t p2) {
81        return start(false,sec,msec,p1,p2);
82} // end start_absolute
83
84/** Prepare message to start a relative timer. */
85bool TimerMsg::start_relative(int32 sec, int32 msec, param_t p1, param_t p2) {
86        return start(true,sec,msec,p1,p2);
87} // end start_relative
88
89bool TimerMsg::start(bool rel, int32 sec, int32 msec, param_t p1, param_t p2) {
90        time_sec = (sec<=0)?0:sec;
91        time_msec = (msec<=0)?0:msec;
92        param1 = p1;
93        param2 = p2;
94        action = ac_start;
95        relative = rel;
96        ok = true;
97        return true;
98} // end start
99
100/** Restart an absolute timer. */
101bool TimerMsg::restart_absolute(id_t id, int32 sec, int32 msec) {
102        return restart(false,id,sec,msec);
103} // end restart_absolute
104
105/** Restart a relative timer. */
106bool TimerMsg::restart_relative(id_t id, int32 sec, int32 msec) {
107        return restart(true,id,sec,msec);
108} // end restart_relative
109
110/** restart timer
111 * please note that this method actually overwrites the id of the message(!)
112 */
113bool TimerMsg::restart(bool rel, id_t id, int32 sec, int32 msec) {
114        relative = rel;
115        if (id && set_id(id)) {
116                time_sec = (sec<=0)?0:sec;
117                time_msec = (msec<=0)?0:msec;
118                action = ac_restart;
119                ok = true;
120        } else {
121                time_sec = 0;
122                time_msec = 0;
123                action = ac_ignore;
124                ok = false;
125        } // end if id
126        return ok;
127} // end restart
128
129/** Stop a timer. */
130bool TimerMsg::stop(id_t id) {
131        relative = false;
132        time_sec = 0;
133        time_msec = 0;
134        param1 = param2 = NULL;
135        if (id && set_id(id)) {
136                action = ac_stop;
137                ok = true;
138        } else {
139                action = ac_ignore;
140                ok = false;
141        } // end if id
142        return ok;
143} // end stop
144
145/** Stop all running timers. */
146bool TimerMsg::stop_all() {
147        relative = false,
148        time_sec = 0;
149        time_msec = 0;
150        param1 = param2 = NULL;
151        action = ac_stop_all;
152        ok = true;
153        return true;
154} // end stop_all
155
156/** Prepare message for sending it back as a reply message from the
157 * TimerModule when its timer expires.
158 */
159bool TimerMsg::set_elapsed() {
160        send_error = false;
161        action = ac_elapsed;
162        ok = true;
163        return ok;
164} // end set_elapsed
165
166bool TimerMsg::get_send_error() const {
167        return send_error;
168} // end get_send_error
169
170/** Set send_error flag and return old value. */
171bool TimerMsg::set_send_error(bool f) {
172        register bool o = send_error;
173        send_error = f;
174        return o;
175} // end set_send_error
176
177TimerMsg::param_t TimerMsg::get_param1() const { return param1; }
178
179TimerMsg::param_t TimerMsg::get_param2() const { return param2; }
180
181void TimerMsg::get_params(param_t& p1, param_t& p2) const {
182        p1 = param1;
183        p2 = param2;
184} // end get_params
185
186bool TimerMsg::is_absolute() const { return (!relative); }
187
188bool TimerMsg::is_relative() const { return relative; }
189
190/***** struct TimerModuleParam *****/
191
192/** @param sleep_time default sleep time
193 * @param sua send messages until aborted or just until stopped
194 * @param see send error messages as expedited data
195 * @param sre send reply messages as expedited data
196 */
197TimerModuleParam::TimerModuleParam(uint32 sleep_time, bool sua, bool see, bool sre)
198        : ThreadParam(sleep_time, "TimerModule", 2), send_until_abort(sua),
199        source(message::qaddr_timer), 
200        send_error_expedited(see), send_reply_expedited(sre) {
201        // nothing more to do
202} // end constructor TimerModuleParam
203
204/***** class TimerModule *****/
205
206/** Set parameters. */
207TimerModule::TimerModule(const TimerModuleParam& p) 
208        : Thread(p), timerparam(p) {
209        tmap.clear();
210        // register queue
211        QueueManager::instance()->register_queue(get_fqueue(),p.source);
212        DLog(timerparam.name, "Creating TimerModule object");
213} // end constructor TimerModule
214
215/** Stop all running timers. */
216TimerModule::~TimerModule() {
217        stop_all_timers();
218        DLog(timerparam.name, "Destroying TimerModule object");
219        QueueManager::instance()->unregister_queue(timerparam.source);
220
221} // end destructor TimerModule
222
223/** Devide Threads in thos which process the queue and those which process
224 * expired timers.
225 */
226void TimerModule::main_loop(uint32 nr) {
227  Log(INFO_LOG,LOG_NORMAL, timerparam.name, "Starting " << timerparam.name << " thread #" << nr << ", " << ((nr%2) ? "processing input queue" : "processing timer callbacks"));
228
229  if (nr%2) process_queue();
230  else process_elapsed_timers();
231
232  Log(INFO_LOG,LOG_NORMAL, timerparam.name,"Thread #" << nr << " stopped");
233} // end main_loop
234
235/** Wait for incomming mesages and evaluate message action.
236 * Messages are accepted until the module is asked to stop.
237 *
238 * The module mutex inherited from the Thread base class is locked here, so all
239 * called member functions are called inside a critical section if necessary.
240 */
241void TimerModule::process_queue() {
242  uint32 wait = timerparam.sleep_time*1000;
243  message* msg = NULL;
244  TimerMsg* tmsg = NULL;
245  FastQueue* fq = QueueManager::instance()->get_queue(message::qaddr_timer);
246  bool opresult = false;
247  if (!fq) {
248    Log(ERROR_LOG,LOG_ALERT, timerparam.name," cannot find input queue");
249    return;
250  } // end if not fq
251  // wait for messages
252  while (get_state()==STATE_RUN) {
253    msg = fq->dequeue_timedwait(wait);
254    if (msg) {
255      if (msg->get_type()==message::type_timer) {
256        tmsg = dynamic_cast<TimerMsg*>(msg);
257        if (tmsg) {
258          // begin critical section
259          lock(); // install_cleanup_thread_lock(TimerModule,this);
260          if (tmsg->is_ok()) {
261            // evaluate action
262            switch (tmsg->get_action()) {
263              case TimerMsg::ac_ignore:
264                      // do nothing
265                Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"received message with action set to ignore");
266                opresult = true;
267                break;
268              case TimerMsg::ac_start:
269                opresult = start_timer(tmsg);
270                break;
271              case TimerMsg::ac_restart:
272                opresult = restart_timer(tmsg);
273                break;
274              case TimerMsg::ac_stop:
275                opresult = stop_timer(tmsg);
276                break;
277              case TimerMsg::ac_stop_all:
278                opresult = stop_all_timers();
279                break;
280              default:
281                ERRLog(timerparam.name, "Wrong action " << tmsg->get_action() << " in message from " << tmsg->get_qaddr_name() << " to " << message::get_qaddr_name(timerparam.source) );
282               
283                opresult = false;
284            } // end switch get_action
285          } else {
286              Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"received message in invalid state, mid " << tmsg->get_id() );
287            opresult = false;
288          } // if tmsg->is_ok()
289          // error handling, message disposing
290          send_error_or_dispose(tmsg,opresult);
291          // end critical section
292          unlock(); // uninstall_cleanup(1);
293        } else {
294          Log(ERROR_LOG,LOG_ALERT, timerparam.name, "Cannot cast message from " << msg->get_qaddr_name() << " of type " << msg->get_type_name() << " to TimerMsg");
295          delete msg;
296        } // end if tmsg
297      } else {
298        ERRLog(timerparam.name,"received message that is not of type_timer from " << msg->get_qaddr_name() << ", type was " << msg->get_type_name());
299        delete msg;
300      } // end if type
301    } // end if msg
302  } // end while running
303} // end process_queue
304
305/** Check if timers expired and send reply messages.
306 * Reply messages are sent until the module is asked to abort if
307 * the flag send_until_abort is set true. Otherwise no messages are sent
308 * after a stop request.
309 */
310void TimerModule::process_elapsed_timers() {
311        state_t end_state;
312        uint32 num = 0;
313        uint32 sleeptime = timerparam.sleep_time*1000;
314        if (timerparam.send_until_abort) end_state = STATE_ABORT;
315        else end_state = STATE_STOP;
316        while(get_state()!=end_state) {
317                num = tm.check_timers_wait(sleeptime);
318                if (num) {
319                  Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"got " << num << " elapsed timer(s)");
320                } // end if num
321        } // end while state
322} // end process_elapsed_timers
323
324/** Starts a timer and stores its ID and the reply message in the hash maps. */
325bool TimerModule::start_timer(TimerMsg* m) {
326        timer_id_t tid = 0;
327        bool res = true;
328        message::id_t mid = m->get_id();
329        bool relative = m->is_relative();
330        int32 sec = 0;
331        int32 msec = 0;
332        if (mid) {
333          // lookup timer ID in map
334          if ((tid=tmap.lookup_tid(mid))) {
335            ERRLog(timerparam.name, m->get_qaddr_name() << " tried to start a timer with mid " << mid << ", but there is already a timer " << tid);
336            res = false;
337          } else {
338            // start timer
339            m->get_time(sec,msec);
340            if (relative) tid = tm.start_relative(this,sec,msec,NULL);
341            else tid = tm.start_absolute(this,sec,msec,NULL);
342            if (tid) {
343              // insert in map
344              tmap.insert(tid,m);
345              // timer successfully started
346              Log(EVENT_LOG,LOG_UNIMP, timerparam.name, "Timer " << tid << " (" << sec << "s " << msec << "ms) started for " 
347                                                         << m->get_qaddr_name() << " with mid " << mid);
348              res = true;
349            } else {
350              // timer not started
351              ERRLog(timerparam.name, "TimerManager in " << timerparam.name << " is unable to start a timer for " << m->get_qaddr_name());
352              res = false;
353            } // end if tid
354          } // end if lookup repmsg
355        } else {
356          ERRLog(timerparam.name, m->get_qaddr_name() << " tried to start a timer with message ID 0");
357          res = false;
358        } // end if repmsg
359        return res;
360} // end start_timer
361
362/** Restarts a timer and stores its ID and the reply message in the hash maps. */
363bool TimerModule::restart_timer(TimerMsg* m) {
364        timer_id_t tid = 0;
365        bool res = true;
366        message::id_t mid = m->get_id();
367        bool relative = m->is_relative();
368        TimerMsg* repmsg = NULL;
369        int32 sec = 0;
370        int32 msec = 0;
371        if (mid) {
372          // lookup timer_id and reply message for mid in map
373          tid = tmap.lookup_tid(mid);
374          repmsg = tmap.lookup_msg(tid);
375          if (tid && repmsg) {
376            // restart timer
377            m->get_time(sec,msec);
378            if (relative) res = tm.restart_relative(tid,sec,msec);
379            else res = tm.restart_absolute(tid,sec,msec);
380            if (res) {
381              // modify reply message
382              repmsg->restart(relative,mid,sec,msec);
383              // timer successfully restarted
384              DLog(timerparam.name, "Timer " << tid << ", mid " << mid << " restarted for " << m->get_qaddr_name());
385            } else {
386              // timer not restarted
387              ERRLog(timerparam.name, "TimerManager in " << timerparam.name << " is unable to restart a timer for " << m->get_qaddr_name() << ", mid " << mid);
388            } // end if res
389          } else {
390            if (tid) ERRLog(timerparam.name, m->get_qaddr_name() << " tried to restart a timer with mid " << mid << ": or no reply message for timer found");
391            if (repmsg)  ERRLog(timerparam.name, m->get_qaddr_name() << " tried to restart timer with mid " << mid << ": timer not found");
392            if ((!repmsg) & (!tid)) ERRLog(timerparam.name, m->get_qaddr_name() << " tried to restart timer with mid " << mid << ": neither timer nor reply message found");
393            res = false;
394          } // end if tid
395        } else {
396          ERRLog(timerparam.name, m->get_qaddr_name() << " tried to restart a timer with an invalid message ID");
397          res = false;
398        } // end if repmsg
399        return res;
400} // end restart_timer
401
402/** Stop a timer and remove its ID and reply message from the hash maps. */
403bool TimerModule::stop_timer(TimerMsg* m) {
404        timer_id_t tid = 0;
405        bool res = true;
406        message::id_t mid = m->get_id();
407        if (mid) {
408                // lookup timer_id for mid in map
409                tid = tmap.lookup_tid(mid);
410                if (tid) {
411                        // stop timer
412                        res = tm.stop(tid);
413                        if (res) {
414                                // delete from map
415                                tmap.erase(tid,mid,true);
416                                // timer stopped
417                                DLog(timerparam.name, "Stopped timer " << tid << ", mid " << mid << " for " << m->get_qaddr_name());
418                        } else {
419                                // timer not stopped
420                          ERRLog(timerparam.name, "TimerManager in " << timerparam.name << " is unable to stop timer " << tid << ", mid " << mid << " for " << m->get_qaddr_name());
421                        } // end if tid
422                } else {
423                  ERRLog(timerparam.name, m->get_qaddr_name() << " tried to stop a non-existing timer with mid " << mid);
424                  res = false;
425                } // end if tid
426        } else {
427          ERRLog(timerparam.name, m->get_qaddr_name() << " tried to stop a timer with an invalid message ID");
428          res = false;
429        } // end if repmsg
430        return res;
431} // end stop_timer
432
433/** Stop all timers and clear the hash maps. */
434bool TimerModule::stop_all_timers() {
435        uint32 num = 0;
436        // clear map
437        tmap.clear(true);
438        // clear TimerManager
439        num = tm.stop_all();
440        Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"stopped all timers, num " << num);
441        return true;
442} // end stop_all_timers
443
444/** Send back error message.
445 * If no error is necessary, the message is disposed.
446 * @param m message that is changed to an error message if
447 *              its flags are set appropriately.
448 * @param ok success or error?
449 */
450void TimerModule::send_error_or_dispose(TimerMsg* m, bool ok) {
451        message::qaddr_t dest;
452        if (!m) return;
453
454#ifndef _NO_LOGGING
455        message::id_t mid = m->get_id();        // only used for logging
456#endif
457
458        // Do we send errors?
459        if ((!ok) && m->get_send_error()) ok = false;
460        else ok = true;
461        if (ok) {
462                // dispose if not a start message
463                if (m->get_action()!=TimerMsg::ac_start) {
464                        dest = m->get_source();
465                        delete m;
466                        //Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"disposed message " << mid << " from " << message::get_qaddr_name(dest));
467                } // end if dispose message
468        } else {
469                // send error
470                dest = m->get_source();
471                m->set_ok(false);
472                if (m->send(timerparam.source,dest,timerparam.send_error_expedited)) {
473                  Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"sent error message w/ mid " << mid << " to " << message::get_qaddr_name(dest));
474                } else {
475                  ERRLog(timerparam.name,"cannot send error message w/ mid " << mid << " to " << message::get_qaddr_name(dest) << ", disposing it now");
476                  delete m;
477                } // end if sent error
478        } // end if ok
479} // end send_error_or_dispose
480
481/** This is the callback for the TimerManager used by the TimerModule object.
482 * @param timer timer ID
483 * @param callback_param additional callback parameter.
484 *
485 * The module mutex inherited from the Thread base class is locked here, so all
486 * called member functions are called inside a critical section if necessary.
487 */
488void TimerModule::timer_expired(timer_id_t timer, timer_callback_param_t callback_param) {
489        TimerMsg* msg = NULL;
490        message::qaddr_t dest;
491        message::id_t mid = 0;
492        // begin critical section
493        lock(); // install_cleanup_thread_lock(TimerModule,this);
494        // get reply message
495        msg = tmap.lookup_msg(timer);
496        if (msg) {
497                // store message ID for erasing this record from the map
498                mid = msg->get_id();
499                // send message
500                dest = msg->get_source();
501                if (msg->set_elapsed() && msg->send_back(timerparam.source,timerparam.send_reply_expedited)) {
502                  Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"sent reply mid " << mid << " for elapsed timer " << timer << " to " << message::get_qaddr_name(dest));
503                } else {
504                  ERRLog(timerparam.name,"cannot send reply mid " << mid << " for elapsed timer " << timer <<" to " << message::get_qaddr_name(dest));
505                  // dispose message
506                  delete msg;
507                } // end if send_back
508        } else {
509                // may be timer has been stopped
510          DLog(timerparam.name, "TimerModule::timer_expired cannot find reply message for a timer " << timer << ". Maybe the timer has been stopped");
511        } // end if msg
512        // erase (timer,mid) without disposing the reply message
513        tmap.erase(timer,mid,false);
514        // end critical section
515        unlock(); // uninstall_cleanup(1);
516} // end timer_expired
517
518/***** class TimerModule::TimerMap *****/
519
520bool TimerModule::TimerMap::insert(timer_id_t tid, TimerMsg* m) {
521        if (tid && m) {
522                message::id_t mid = m->get_id();
523                tid2mid[tid] = mid;
524                mid2tid[mid] = tid;
525                tid2msg[tid] = m;
526                return true;
527        } else return false;
528} // end insert
529
530/** Returns the message ID of the timer bound to timer ID or 0 if not
531 * found, since every timer must have an ID <> 0.
532 */
533message::id_t TimerModule::TimerMap::lookup_mid(timer_id_t tid) const {
534        const_tid2mid_it_t hit;
535        hit = tid2mid.find(tid);
536        if (hit!=tid2mid.end()) return hit->second;
537        else return 0;
538} // end lookup
539
540/** Returns the timer-ID of the timer bound to the message ID or 0 if not
541 * found, since 0 is never used as a timer ID.
542 */
543timer_id_t TimerModule::TimerMap::lookup_tid(message::id_t mid) const {
544        const_mid2tid_it_t hit;
545        if ((hit=mid2tid.find(mid))!=mid2tid.end()) return hit->second;
546        else return 0;
547} // end lookup
548
549/** Returns the timer message of the timer bound to timer ID or NULL if not
550 * found.
551 */
552TimerMsg* TimerModule::TimerMap::lookup_msg(timer_id_t tid) const {
553        const_tid2msg_it_t hit;
554        hit = tid2msg.find(tid);
555        if (hit!=tid2msg.end()) return hit->second;
556        else return NULL;
557} // end lookup_msg
558
559/** Please be sure that timer ID and message ID are bound to the same timer.
560 * No checking is done!
561 */
562void TimerModule::TimerMap::erase(timer_id_t tid, message::id_t mid, bool dispose) {
563        TimerMsg* m = NULL;
564        if (tid) {
565                if (dispose) {
566                        m = lookup_msg(tid);
567                        if (m) delete m;
568                } // end if dispose
569                tid2mid.erase(tid);
570                tid2msg.erase(tid);
571        } // end if tid
572        if (mid) mid2tid.erase(mid);
573} // end erase
574
575void TimerModule::TimerMap::clear(bool dispose) {
576        const_tid2msg_it_t hit;
577        if (dispose) {
578                for (hit=tid2msg.begin();hit!=tid2msg.end();hit++) {
579                        if (hit->second) delete hit->second;
580                } // end for hit
581        } // end if dispose
582        tid2mid.clear();
583        tid2msg.clear();
584        mid2tid.clear();
585} // end clear
586
587//@}
588
589} // end namespace protlib
Note: See TracBrowser for help on using the repository browser.