1 /*
2  * Copyright (c) 2010, Sangoma Technologies
3  * Moises Silva <moy@sangoma.com>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  *
17  * * Neither the name of the original author; nor the names of any contributors
18  * may be used to endorse or promote products derived from this software
19  * without specific prior written permission.
20  *
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #ifndef __FTDM_STATE_H__
36 #define __FTDM_STATE_H__
37 
38 /*! \file
39  * \brief State handling definitions
40  * \note Most, if not all of the state handling functions assume you have a lock acquired. Touching the channel
41  *       state is a sensitive matter that requires checks and careful thought and is typically a process that
42  *       is not encapsulated within a single function, therefore the lock must be explicitly acquired by the
43  *       caller (most of the time, signaling modules), process states, set a new state and process it, and
44  *       finally unlock the channel. See docs/locking.txt fore more info
45  */
46 
47 #ifdef __cplusplus
48 extern "C" {
49 #endif
50 
51 typedef enum {
52 	FTDM_CHANNEL_STATE_ANY = -1,
53 	FTDM_CHANNEL_STATE_END = -1,
54 	FTDM_CHANNEL_STATE_DOWN,
55 	FTDM_CHANNEL_STATE_HOLD,
56 	FTDM_CHANNEL_STATE_SUSPENDED,
57 	FTDM_CHANNEL_STATE_DIALTONE,
58 	FTDM_CHANNEL_STATE_COLLECT,
59 	FTDM_CHANNEL_STATE_RING,
60 	FTDM_CHANNEL_STATE_RINGING,
61 	FTDM_CHANNEL_STATE_BUSY,
62 	FTDM_CHANNEL_STATE_ATTN,
63 	FTDM_CHANNEL_STATE_GENRING,
64 	FTDM_CHANNEL_STATE_DIALING,
65 	FTDM_CHANNEL_STATE_GET_CALLERID,
66 	FTDM_CHANNEL_STATE_CALLWAITING,
67 	FTDM_CHANNEL_STATE_RESTART,
68 	FTDM_CHANNEL_STATE_PROCEED,
69 	FTDM_CHANNEL_STATE_PROGRESS,
70 	FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
71 	FTDM_CHANNEL_STATE_UP,
72 	FTDM_CHANNEL_STATE_TRANSFER,
73 	FTDM_CHANNEL_STATE_IDLE,
74 	FTDM_CHANNEL_STATE_TERMINATING,
75 	FTDM_CHANNEL_STATE_CANCEL,
76 	FTDM_CHANNEL_STATE_HANGUP,
77 	FTDM_CHANNEL_STATE_HANGUP_COMPLETE,
78 	FTDM_CHANNEL_STATE_IN_LOOP,
79 	FTDM_CHANNEL_STATE_RESET,
80 	FTDM_CHANNEL_STATE_INVALID
81 } ftdm_channel_state_t;
82 /* Purposely not adding ANY (-1) and END (-1) since FTDM_STR2ENUM_P works only on enums starting at zero */
83 #define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
84 		"RING", "RINGING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
85 		"RESTART", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "UP", "TRANSFER", "IDLE", "TERMINATING", "CANCEL", \
86 		"HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "RESET", "INVALID"
87 FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t)
88 
89 typedef struct {
90 	const char *file;
91 	const char *func;
92 	int line;
93 	ftdm_channel_state_t state; /*!< Current state (processed or not) */
94 	ftdm_channel_state_t last_state; /*!< Previous state */
95 	ftdm_time_t time; /*!< Time the state was set */
96 	ftdm_time_t end_time; /*!< Time the state processing was completed */
97 } ftdm_state_history_entry_t;
98 
99 typedef ftdm_status_t (*ftdm_channel_state_processor_t)(ftdm_channel_t *fchan);
100 
101 /*!
102  * \brief Process channel states by invoking the channel state processing routine
103  *        it will keep calling the processing routine while the state status
104  *        is FTDM_STATE_STATUS_NEW, it will not do anything otherwise
105  */
106 FT_DECLARE(ftdm_status_t) ftdm_channel_advance_states(ftdm_channel_t *fchan);
107 
108 FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const char *function, int line, ftdm_channel_t *fchan);
109 #define ftdm_channel_complete_state(obj) _ftdm_channel_complete_state(__FILE__, __FTDM_FUNC__, __LINE__, obj)
110 FT_DECLARE(int) ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state);
111 
112 /*!
113  * \brief Status of the current channel state
114  * \note A given state goes thru several status (yes, states for the state!)
115  * The order is always FTDM_STATE_STATUS_NEW -> FTDM_STATE_STATUS_PROCESSED -> FTDM_STATUS_COMPLETED
116  * However, is possible to go from NEW -> COMPLETED directly when the signaling module explicitly changes
117  * the state of the channel in the middle of processing the current state by calling the ftdm_set_state() API
118  *
119  * FTDM_STATE_STATUS_NEW -
120  *   Someone just set the state of the channel, either the signaling module or the user (implicitly through a call API).
121  *   This is accomplished by calling ftdm_channel_set_state() which changes the 'state' and 'last_state' memebers of
122  *   the ftdm_channel_t structure.
123  *
124  * FTDM_STATE_STATUS_PROCESSED -
125  *   The signaling module did something based on the new state.
126  *
127  *   This is accomplished via ftdm_channel_advance_states()
128  *
129  *   When ftdm_channel_advance_states(), at the very least, if the channel has its state in FTDM_STATE_STATUS_NEW, it
130  *   will move to FTDM_STATE_STATUS_PROCESSED, depending on what the signaling module does during the processing
131  *   the state may move to FTDM_STATE_STATUS_COMPLETED right after or wait for a signaling specific event to complete it.
132  *   It is also possible that more state transitions occur during the execution of ftdm_channel_advance_states() if one
133  *   state processing/completion leads to another state change, the function will not return until the chain of events
134  *   lead to a state that is not in FTDM_STATE_STATUS_NEW
135  *
136  * FTDM_STATE_STATUS_COMPLETED -
137  *   The signaling module completed the processing of the state and there is nothing further to be done for this state.
138  *
139  *   This is accomplished either explicitly by the signaling module by calling ftdm_channel_complete_state() or by
140  *   the signaling module implicitly by trying to set the state of the channel to a new state via ftdm_set_state()
141  *
142  *   When working with blocking channels (FTDM_CHANNEL_NONBLOCK flag not set), the user thread is signaled and unblocked
143  *   so it can continue.
144  *
145  *   When a state moves to this status is also possible for a signal FTDM_SIGEVENT_INDICATION_COMPLETED to be delivered
146  *   by the core if the state change was associated to an indication requested by the user,
147  */
148 typedef enum {
149 	FTDM_STATE_STATUS_NEW,
150 	FTDM_STATE_STATUS_PROCESSED,
151 	FTDM_STATE_STATUS_COMPLETED,
152 	FTDM_STATE_STATUS_INVALID
153 } ftdm_state_status_t;
154 #define CHANNEL_STATE_STATUS_STRINGS "NEW", "PROCESSED", "COMPLETED", "INVALID"
155 FTDM_STR2ENUM_P(ftdm_str2ftdm_state_status, ftdm_state_status2str, ftdm_state_status_t)
156 
157 typedef enum {
158 	ZSM_NONE,
159 	ZSM_UNACCEPTABLE,
160 	ZSM_ACCEPTABLE
161 } ftdm_state_map_type_t;
162 
163 typedef enum {
164 	ZSD_INBOUND,
165 	ZSD_OUTBOUND,
166 } ftdm_state_direction_t;
167 
168 #define FTDM_MAP_NODE_SIZE 512
169 #define FTDM_MAP_MAX FTDM_CHANNEL_STATE_INVALID+2
170 
171 struct ftdm_state_map_node {
172 	ftdm_state_direction_t direction;
173 	ftdm_state_map_type_t type;
174 	ftdm_channel_state_t check_states[FTDM_MAP_MAX];
175 	ftdm_channel_state_t states[FTDM_MAP_MAX];
176 };
177 typedef struct ftdm_state_map_node ftdm_state_map_node_t;
178 
179 struct ftdm_state_map {
180 	ftdm_state_map_node_t nodes[FTDM_MAP_NODE_SIZE];
181 };
182 typedef struct ftdm_state_map ftdm_state_map_t;
183 
184 /*!\brief Cancel the state processing for a channel (the channel must be locked when calling this function)
185  * \note Only the core should use this function
186  */
187 FT_DECLARE(ftdm_status_t) ftdm_channel_cancel_state(const char *file, const char *func, int line,
188 		ftdm_channel_t *ftdmchan);
189 
190 /*!\brief Set the state for a channel (the channel must be locked when calling this function)
191  * \note Signaling modules should use ftdm_set_state macro instead
192  * \note If this function is called with the wait parameter set to a non-zero value, the recursivity
193  *       of the channel lock must be == 1 because the channel will be unlocked/locked when waiting */
194 FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line,
195 		ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int wait, ftdm_usrmsg_t *usrmsg);
196 
197 /*!\brief Set the state of a channel immediately and implicitly complete the previous state if needed
198  * \note FTDM_SIGEVENT_INDICATION_COMPLETED will be sent if the state change
199  *       is associated to some indication (ie FTDM_CHANNEL_INDICATE_PROCEED)
200  * \note The channel must be locked when calling this function
201  * */
202 FT_DECLARE(ftdm_status_t) _ftdm_set_state(const char *file, const char *func, int line,
203 			ftdm_channel_t *fchan, ftdm_channel_state_t state);
204 #define ftdm_set_state(obj, s) _ftdm_set_state(__FILE__, __FTDM_FUNC__, __LINE__, obj, s);									\
205 
206 /*!\brief This macro is deprecated, signaling modules should always lock the channel themselves anyways since they must
207  * process first the user pending state changes then set a new state before releasing the lock
208  * this macro is here for backwards compatibility, DO NOT USE IT in new code since it is *always* wrong to set
209  * a state in a signaling module without checking and processing the current state first (and for that you must lock the channel)
210  */
211 #define ftdm_set_state_locked(obj, s) \
212 	do { \
213 		ftdm_channel_lock(obj); \
214 		ftdm_channel_set_state(__FILE__, __FTDM_FUNC__, __LINE__, obj, s, 0, NULL);									\
215 		ftdm_channel_unlock(obj); \
216 	} while(0);
217 
218 #define ftdm_set_state_r(obj, s, r) r = ftdm_channel_set_state(__FILE__, __FTDM_FUNC__, __LINE__, obj, s, 0);
219 
220 #define ftdm_set_state_all(span, state) \
221 	do { \
222 		uint32_t _j; \
223 		ftdm_mutex_lock((span)->mutex); \
224 		for(_j = 1; _j <= (span)->chan_count; _j++) { \
225 			if (!FTDM_IS_DCHAN(span->channels[_j])) { \
226 				ftdm_set_state_locked((span->channels[_j]), state); \
227 			} \
228 		} \
229 		ftdm_mutex_unlock((span)->mutex); \
230 	} while (0);
231 
232 #ifdef __cplusplus
233 }
234 #endif
235 
236 #endif
237 
238 /* For Emacs:
239  * Local Variables:
240  * mode:c
241  * indent-tabs-mode:t
242  * tab-width:4
243  * c-basic-offset:4
244  * End:
245  * For VIM:
246  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
247  */
248