This source file includes following definitions.
- FTDM_ENUM_NAMES
- FT_DECLARE
- FT_DECLARE
- ftdm_parse_state_map
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- write_history_entry
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 #include "private/ftdm_core.h"
36
37 FTDM_ENUM_NAMES(CHANNEL_STATE_NAMES, CHANNEL_STATE_STRINGS)
38 FTDM_STR2ENUM(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t, CHANNEL_STATE_NAMES, FTDM_CHANNEL_STATE_INVALID)
39
40 FTDM_ENUM_NAMES(CHANNEL_STATE_STATUS_NAMES, CHANNEL_STATE_STATUS_STRINGS)
41 FTDM_STR2ENUM(ftdm_str2ftdm_state_status, ftdm_state_status2str, ftdm_state_status_t, CHANNEL_STATE_STATUS_NAMES, FTDM_STATE_STATUS_INVALID)
42
43
44 FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *fchan)
45 {
46 ftdm_channel_lock(fchan);
47
48 if (fchan->init_state != FTDM_CHANNEL_STATE_DOWN) {
49 ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, fchan, fchan->init_state, 1);
50 fchan->init_state = FTDM_CHANNEL_STATE_DOWN;
51 }
52
53 ftdm_channel_unlock(fchan);
54 return FTDM_SUCCESS;
55 }
56
57 FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const char *func, int line, ftdm_channel_t *fchan)
58 {
59 uint8_t hindex = 0;
60 ftdm_time_t diff = 0;
61 ftdm_channel_state_t state = fchan->state;
62
63 if (fchan->state_status == FTDM_STATE_STATUS_COMPLETED) {
64 ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL,
65 "State change flag set but state is not completed\n");
66 return FTDM_SUCCESS;
67 }
68
69 ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
70
71 if (state == FTDM_CHANNEL_STATE_PROGRESS) {
72 ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
73 } else if (state == FTDM_CHANNEL_STATE_UP) {
74 ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
75 ftdm_set_flag(fchan, FTDM_CHANNEL_MEDIA);
76 ftdm_set_flag(fchan, FTDM_CHANNEL_ANSWERED);
77 } else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
78 ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
79 ftdm_set_flag(fchan, FTDM_CHANNEL_MEDIA);
80 } else if (state == FTDM_CHANNEL_STATE_DIALING) {
81 ftdm_sigmsg_t msg;
82 memset(&msg, 0, sizeof(msg));
83 msg.channel = fchan;
84 msg.event_id = FTDM_SIGEVENT_DIALING;
85 ftdm_span_send_signal(fchan->span, &msg);
86 }
87
88
89
90
91 ftdm_ack_indication(fchan, fchan->indication, FTDM_SUCCESS);
92
93 hindex = (fchan->hindex == 0) ? (ftdm_array_len(fchan->history) - 1) : (fchan->hindex - 1);
94
95 ftdm_assert(!fchan->history[hindex].end_time, "End time should be zero!\n");
96
97 fchan->history[hindex].end_time = ftdm_current_time_in_ms();
98
99 fchan->state_status = FTDM_STATE_STATUS_COMPLETED;
100
101 diff = fchan->history[hindex].end_time - fchan->history[hindex].time;
102
103 ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Completed state change from %s to %s in %llums\n",
104 ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(state), diff);
105
106
107 if (ftdm_test_flag(fchan, FTDM_CHANNEL_BLOCKING)) {
108 ftdm_clear_flag(fchan, FTDM_CHANNEL_BLOCKING);
109 ftdm_interrupt_signal(fchan->state_completed_interrupt);
110 }
111
112 return FTDM_SUCCESS;
113 }
114
115 FT_DECLARE(ftdm_status_t) _ftdm_set_state(const char *file, const char *func, int line,
116 ftdm_channel_t *fchan, ftdm_channel_state_t state)
117 {
118 if (fchan->state_status != FTDM_STATE_STATUS_COMPLETED) {
119
120
121
122 _ftdm_channel_complete_state(file, func, line, fchan);
123 }
124 return ftdm_channel_set_state(file, func, line, fchan, state, 0);
125 }
126
127 static int ftdm_parse_state_map(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, ftdm_state_map_t *state_map)
128 {
129 int x = 0, ok = 0;
130 ftdm_state_direction_t direction = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? ZSD_OUTBOUND : ZSD_INBOUND;
131
132 for(x = 0; x < FTDM_MAP_NODE_SIZE; x++) {
133 int i = 0, proceed = 0;
134 if (!state_map->nodes[x].type) {
135 break;
136 }
137
138 if (state_map->nodes[x].direction != direction) {
139 continue;
140 }
141
142 if (state_map->nodes[x].check_states[0] == FTDM_ANY_STATE) {
143 proceed = 1;
144 } else {
145 for(i = 0; i < FTDM_MAP_MAX; i++) {
146 if (state_map->nodes[x].check_states[i] == ftdmchan->state) {
147 proceed = 1;
148 break;
149 }
150 }
151 }
152
153 if (!proceed) {
154 continue;
155 }
156
157 for(i = 0; i < FTDM_MAP_MAX; i++) {
158 ok = (state_map->nodes[x].type == ZSM_ACCEPTABLE);
159 if (state_map->nodes[x].states[i] == FTDM_END) {
160 break;
161 }
162 if (state_map->nodes[x].states[i] == state) {
163 ok = !ok;
164 goto end;
165 }
166 }
167 }
168 end:
169
170 return ok;
171 }
172
173 FT_DECLARE(ftdm_status_t) ftdm_channel_cancel_state(const char *file, const char *func, int line, ftdm_channel_t *fchan)
174 {
175 ftdm_time_t diff;
176 ftdm_channel_state_t state;
177 ftdm_channel_state_t last_state;
178 uint8_t hindex = 0;
179
180 if (!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE)) {
181 ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Cannot cancel state change from %s to %s, it was already processed\n",
182 ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(fchan->state));
183 return FTDM_FAIL;
184 }
185
186 if (fchan->state_status != FTDM_STATE_STATUS_NEW) {
187 ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Failed to cancel state change from %s to %s, state is not new anymore\n",
188 ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(fchan->state));
189 return FTDM_FAIL;
190 }
191
192
193 hindex = (fchan->hindex == 0) ? (ftdm_array_len(fchan->history) - 1) : (fchan->hindex - 1);
194 diff = fchan->history[hindex].end_time - fchan->history[hindex].time;
195
196
197 state = fchan->state;
198 last_state = fchan->last_state;
199
200 fchan->state = fchan->last_state;
201 fchan->state_status = FTDM_STATE_STATUS_COMPLETED;
202 fchan->last_state = fchan->history[hindex].last_state;
203 fchan->hindex = hindex;
204
205
206 ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
207
208
209 ftdm_ack_indication(fchan, fchan->indication, FTDM_ECANCELED);
210
211
212 if (ftdm_test_flag(fchan, FTDM_CHANNEL_BLOCKING)) {
213 ftdm_clear_flag(fchan, FTDM_CHANNEL_BLOCKING);
214 ftdm_interrupt_signal(fchan->state_completed_interrupt);
215 }
216
217
218
219
220 ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Cancelled state change from %s to %s in %llums\n",
221 ftdm_channel_state2str(last_state), ftdm_channel_state2str(state), diff);
222
223 return FTDM_SUCCESS;
224 }
225
226
227 #define DEFAULT_WAIT_TIME 1000
228 FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int waitrq)
229 {
230 ftdm_status_t status;
231 int ok = 1;
232 int waitms = DEFAULT_WAIT_TIME;
233
234 if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
235 ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR, "Ignored state change request from %s to %s, the channel is not ready\n",
236 ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
237 return FTDM_FAIL;
238 }
239
240 if (ftdmchan->state_status != FTDM_STATE_STATUS_COMPLETED) {
241 ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR,
242 "Ignored state change request from %s to %s, the previous state change has not been processed yet (status = %s)\n",
243 ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state),
244 ftdm_state_status2str(ftdmchan->state_status));
245 return FTDM_FAIL;
246 }
247
248 if (ftdmchan->state == state) {
249 ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Why bother changing state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
250 return FTDM_FAIL;
251 }
252
253 if (!ftdmchan->state_completed_interrupt) {
254 status = ftdm_interrupt_create(&ftdmchan->state_completed_interrupt, FTDM_INVALID_SOCKET);
255 if (status != FTDM_SUCCESS) {
256 ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_CRIT,
257 "Failed to create state change interrupt when moving from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
258 return status;
259 }
260 }
261
262
263 if (ftdmchan->span->state_map) {
264 ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map);
265 goto end;
266 }
267
268
269 switch(ftdmchan->state) {
270 case FTDM_CHANNEL_STATE_HANGUP:
271 case FTDM_CHANNEL_STATE_TERMINATING:
272 {
273 ok = 0;
274 switch(state) {
275 case FTDM_CHANNEL_STATE_DOWN:
276 case FTDM_CHANNEL_STATE_BUSY:
277 case FTDM_CHANNEL_STATE_RESTART:
278 ok = 1;
279 break;
280 default:
281 break;
282 }
283 }
284 break;
285 case FTDM_CHANNEL_STATE_UP:
286 {
287 ok = 1;
288 switch(state) {
289 case FTDM_CHANNEL_STATE_PROGRESS:
290 case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
291 case FTDM_CHANNEL_STATE_RING:
292 ok = 0;
293 break;
294 default:
295 break;
296 }
297 }
298 break;
299 case FTDM_CHANNEL_STATE_DOWN:
300 {
301 ok = 0;
302
303 switch(state) {
304 case FTDM_CHANNEL_STATE_DIALTONE:
305 case FTDM_CHANNEL_STATE_COLLECT:
306 case FTDM_CHANNEL_STATE_DIALING:
307 case FTDM_CHANNEL_STATE_RING:
308 case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
309 case FTDM_CHANNEL_STATE_PROGRESS:
310 case FTDM_CHANNEL_STATE_IDLE:
311 case FTDM_CHANNEL_STATE_GET_CALLERID:
312 case FTDM_CHANNEL_STATE_GENRING:
313 ok = 1;
314 break;
315 default:
316 break;
317 }
318 }
319 break;
320 case FTDM_CHANNEL_STATE_BUSY:
321 {
322 switch(state) {
323 case FTDM_CHANNEL_STATE_UP:
324 ok = 0;
325 break;
326 default:
327 break;
328 }
329 }
330 break;
331 case FTDM_CHANNEL_STATE_RING:
332 {
333 switch(state) {
334 case FTDM_CHANNEL_STATE_UP:
335 ok = 1;
336 break;
337 default:
338 break;
339 }
340 }
341 break;
342 default:
343 break;
344 }
345
346 end:
347
348 if (!ok) {
349 ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "VETO state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
350 goto done;
351 }
352
353 ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Changed state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
354 ftdmchan->last_state = ftdmchan->state;
355 ftdmchan->state = state;
356 ftdmchan->state_status = FTDM_STATE_STATUS_NEW;
357 ftdmchan->history[ftdmchan->hindex].file = file;
358 ftdmchan->history[ftdmchan->hindex].func = func;
359 ftdmchan->history[ftdmchan->hindex].line = line;
360 ftdmchan->history[ftdmchan->hindex].state = ftdmchan->state;
361 ftdmchan->history[ftdmchan->hindex].last_state = ftdmchan->last_state;
362 ftdmchan->history[ftdmchan->hindex].time = ftdm_current_time_in_ms();
363 ftdmchan->history[ftdmchan->hindex].end_time = 0;
364 ftdmchan->hindex++;
365 if (ftdmchan->hindex == ftdm_array_len(ftdmchan->history)) {
366 ftdmchan->hindex = 0;
367 }
368 ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
369
370 ftdm_mutex_lock(ftdmchan->span->mutex);
371 ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
372 if (ftdmchan->span->pendingchans) {
373 ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan);
374 }
375 ftdm_mutex_unlock(ftdmchan->span->mutex);
376
377 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NONBLOCK)) {
378
379 goto done;
380 }
381
382 if (!waitrq) {
383
384 goto done;
385 }
386
387
388 ftdm_set_flag(ftdmchan, FTDM_CHANNEL_BLOCKING);
389
390 ftdm_mutex_unlock(ftdmchan->mutex);
391
392 status = ftdm_interrupt_wait(ftdmchan->state_completed_interrupt, waitms);
393
394 ftdm_mutex_lock(ftdmchan->mutex);
395
396 if (status != FTDM_SUCCESS) {
397 ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_BLOCKING);
398 ftdm_log_chan_ex(ftdmchan, file, func, line,
399 FTDM_LOG_LEVEL_WARNING, "state change from %s to %s was most likely not completed after aprox %dms\n",
400 ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(state), DEFAULT_WAIT_TIME);
401 ok = 0;
402 goto done;
403 }
404 done:
405 return ok ? FTDM_SUCCESS : FTDM_FAIL;
406 }
407
408 FT_DECLARE(int) ftdm_channel_get_state(const ftdm_channel_t *ftdmchan)
409 {
410 int state;
411 ftdm_channel_lock(ftdmchan);
412 state = ftdmchan->state;
413 ftdm_channel_unlock(ftdmchan);
414 return state;
415 }
416
417 FT_DECLARE(const char *) ftdm_channel_get_state_str(const ftdm_channel_t *ftdmchan)
418 {
419 const char *state;
420 ftdm_channel_lock(ftdmchan);
421 state = ftdm_channel_state2str(ftdmchan->state);
422 ftdm_channel_unlock(ftdmchan);
423 return state;
424 }
425
426 FT_DECLARE(int) ftdm_channel_get_last_state(const ftdm_channel_t *ftdmchan)
427 {
428 int last_state;
429 ftdm_channel_lock(ftdmchan);
430 last_state = ftdmchan->last_state;
431 ftdm_channel_unlock(ftdmchan);
432 return last_state;
433 }
434
435 FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *ftdmchan)
436 {
437 const char *state;
438 ftdm_channel_lock(ftdmchan);
439 state = ftdm_channel_state2str(ftdmchan->last_state);
440 ftdm_channel_unlock(ftdmchan);
441 return state;
442 }
443
444 static void write_history_entry(const ftdm_channel_t *fchan, ftdm_stream_handle_t *stream, int i, ftdm_time_t *prevtime)
445 {
446 char func[255];
447 char line[255];
448 char states[255];
449 const char *filename = NULL;
450 snprintf(states, sizeof(states), "%-5.15s => %-5.15s", ftdm_channel_state2str(fchan->history[i].last_state), ftdm_channel_state2str(fchan->history[i].state));
451 snprintf(func, sizeof(func), "[%s]", fchan->history[i].func);
452 filename = strrchr(fchan->history[i].file, *FTDM_PATH_SEPARATOR);
453 if (!filename) {
454 filename = fchan->history[i].file;
455 } else {
456 filename++;
457 }
458 if (!(*prevtime)) {
459 *prevtime = fchan->history[i].time;
460 }
461 snprintf(line, sizeof(func), "[%s:%d]", filename, fchan->history[i].line);
462 stream->write_function(stream, "%-30.30s %-30.30s %-30.30s %lums\n", states, func, line, (fchan->history[i].time - *prevtime));
463 *prevtime = fchan->history[i].time;
464 }
465
466 FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan)
467 {
468 uint8_t i = 0;
469 ftdm_time_t currtime = 0;
470 ftdm_time_t prevtime = 0;
471
472 ftdm_stream_handle_t stream = { 0 };
473 FTDM_STANDARD_STREAM(stream);
474 if (!fchan->history[0].file) {
475 stream.write_function(&stream, "-- No state history --\n");
476 return stream.data;
477 }
478
479 stream.write_function(&stream, "%-30.30s %-30.30s %-30.30s %s",
480 "-- States --", "-- Function --", "-- Location --", "-- Time Offset --\n");
481
482 for (i = fchan->hindex; i < ftdm_array_len(fchan->history); i++) {
483 if (!fchan->history[i].file) {
484 break;
485 }
486 write_history_entry(fchan, &stream, i, &prevtime);
487 }
488
489 for (i = 0; i < fchan->hindex; i++) {
490 write_history_entry(fchan, &stream, i, &prevtime);
491 }
492
493 currtime = ftdm_current_time_in_ms();
494
495 stream.write_function(&stream, "\nTime since last state change: %lums\n", (currtime - prevtime));
496
497 return stream.data;
498 }
499
500 FT_DECLARE(ftdm_status_t) ftdm_channel_advance_states(ftdm_channel_t *fchan)
501 {
502 ftdm_channel_state_t state;
503
504 ftdm_assert_return(fchan->span->state_processor, FTDM_FAIL, "Cannot process states without a state processor!\n");
505
506 while (fchan->state_status == FTDM_STATE_STATUS_NEW) {
507 state = fchan->state;
508 ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Executing state processor for %s\n", ftdm_channel_state2str(fchan->state));
509 fchan->span->state_processor(fchan);
510 if (state == fchan->state && fchan->state_status == FTDM_STATE_STATUS_NEW) {
511
512
513
514
515 fchan->state_status = FTDM_STATE_STATUS_PROCESSED;
516 }
517 }
518
519 return FTDM_SUCCESS;
520 }
521
522 FT_DECLARE(int) ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state)
523 {
524 uint32_t j;
525 for(j = 1; j <= span->chan_count; j++) {
526 if (span->channels[j]->state != state || ftdm_test_flag(span->channels[j], FTDM_CHANNEL_STATE_CHANGE)) {
527 return 0;
528 }
529 }
530 return 1;
531 }
532
533
534
535
536
537
538
539
540
541
542