1 /*
2  *  (c) 2007 iptego GmbH
3  *
4  * This file is part of SEMS, a free SIP media server.
5  *
6  * SEMS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version. This program is released under
10  * the GPL with the additional exemption that compiling, linking,
11  * and/or using OpenSSL is allowed.
12  *
13  * For a license to use the SEMS software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * SEMS is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 /** @file AmCallWatcher.h */
28 #ifndef _AM_CALL_WATCHER_H
29 #define _AM_CALL_WATCHER_H
30 
31 //
32 // States are put into map on an Initialize event.
33 // States are held in a map identified by call_id
34 // (opaque identifier) and updated with Update events.
35 // Once an Obsolete event is received, the states are
36 // moved to soft-state map, where they are held until
37 // queried to a maximum of WATCHER_SOFT_EXPIRE_SECONDS
38 
39 #define WATCHER_SOFT_EXPIRE_SECONDS  5
40 
41 #include <string>
42 using std::string;
43 
44 #include <map>
45 
46 #include <utility>
47 using std::pair;
48 
49 #include "AmEventQueue.h"
50 #include "AmEvent.h"
51 #include "AmThread.h"
52 
53 class CallStatus;
54 
55 /**
56  * \brief event that carries out call status update
57  */
58 class CallStatusUpdateEvent : public AmEvent {
59   string call_id;
60 
61   CallStatus* init_status;
62 
63  public:
64   enum UpdateType {
65     Initialize = 0,
66     Update,
67     Obsolete
68   };
69 
CallStatusUpdateEvent(UpdateType t,const string & call_id)70   CallStatusUpdateEvent(UpdateType t, const string& call_id)
71     : AmEvent(t), call_id(call_id)  { }
72 
73   // implicit: initialize
CallStatusUpdateEvent(const string & call_id,CallStatus * init_status)74   CallStatusUpdateEvent(const string& call_id, CallStatus* init_status)
75     : AmEvent(Initialize), call_id(call_id), init_status(init_status)  { }
76 
~CallStatusUpdateEvent()77   ~CallStatusUpdateEvent() { }
78 
get_call_id()79   string get_call_id() { return call_id; }
get_init_status()80   CallStatus* get_init_status() { return init_status; }
81 };
82 
83 /**
84  * \brief interface for an update-able call status (AmCallWatcher)
85  */
86 class CallStatus
87 {
88  public:
CallStatus()89   CallStatus()  { }
~CallStatus()90   virtual ~CallStatus() { }
91 
92   /** update from an event */
93   virtual void update(CallStatusUpdateEvent* e) = 0;
94 
95   /** get a copy of self with relevant data */
96   virtual CallStatus* copy() = 0;
dump()97   virtual void dump() { }
98 };
99 
100 class AmCallWatcherGarbageCollector;
101 /**
102  * \brief manages call status to be queried by external processes
103  * call watcher is an entity for managing call status
104  * via events that change status. Events are executed in a
105  * separate thread serially by processing the event queue,
106  * so synchronous status queries do not block the thread
107  * reporting the status change.
108  */
109 class AmCallWatcher
110 : public AmThread,
111   public AmEventQueue,
112   public AmEventHandler
113 {
114  public:
115   typedef std::map<string, CallStatus*> CallStatusMap;
116   typedef std::map<string, pair<CallStatus*, time_t> > CallStatusTimedMap;
117 
118  private:
119   CallStatusMap states;
120   AmMutex       states_mut;
121 
122 
123   CallStatusTimedMap soft_states;
124   AmMutex            soft_states_mut;
125   AmCallWatcherGarbageCollector* garbage_collector;
126 
127  public:
128   AmCallWatcher();
129   ~AmCallWatcher();
130 
131   // thread
132   void run();
133   void on_stop();
134 
135   // eventhandler
136   void process(AmEvent*);
137 
138   CallStatus* getStatus(const string& call_id);
139 
140   // dump all states
141   void dump();
142 };
143 
144 /**
145  * \brief garbage collector for the AmCallWatcher
146  *
147  * checks garbage every two seconds.
148  * A bit inefficient with two threads, but AmCallWatcher
149  * shouldn't be blocked by event.
150  */
151 class AmCallWatcherGarbageCollector
152 : public AmThread
153 {
154   AmMutex& mut;
155   AmCallWatcher::CallStatusTimedMap& garbage;
156  public:
AmCallWatcherGarbageCollector(AmMutex & mut,AmCallWatcher::CallStatusTimedMap & garbage)157   AmCallWatcherGarbageCollector(AmMutex& mut,
158 				AmCallWatcher::CallStatusTimedMap& garbage)
159     : mut(mut), garbage(garbage) {}
160   void run();
on_stop()161   void on_stop() { }
162 };
163 
164 #endif
165