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