56
56
#include "asterisk/stasis_channels.h"
57
57
#include "asterisk/json.h"
58
58
#include "asterisk/format_cache.h"
59
+ #include "asterisk/vector.h"
59
60
60
61
#define AST_NAME_STRLEN 256
61
62
#define NUM_SPYGROUPS 128
@@ -856,7 +857,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
856
857
}
857
858
858
859
static struct ast_autochan * next_channel (struct ast_channel_iterator * iter ,
859
- struct ast_channel * chan )
860
+ struct ast_channel * chan , struct ast_vector_const_string * skip )
860
861
{
861
862
struct ast_channel * next ;
862
863
struct ast_autochan * autochan_store ;
@@ -867,8 +868,21 @@ static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
867
868
}
868
869
869
870
for (; (next = ast_channel_iterator_next (iter )); ast_channel_unref (next )) {
870
- if (!strncmp (ast_channel_name (next ), "DAHDI/pseudo" , pseudo_len )
871
- || next == chan ) {
871
+ const char * name = ast_channel_name (next );
872
+ int do_next = 0 ;
873
+
874
+ if (!strncmp (name , "DAHDI/pseudo" , pseudo_len ) || next == chan ) {
875
+ do_next = 1 ;
876
+ } else {
877
+ for (unsigned i = 0 ; i < AST_VECTOR_SIZE (skip ); ++ i ) {
878
+ if (!strcmp (name , AST_VECTOR_GET (skip , i ))) {
879
+ do_next = 1 ;
880
+ break ;
881
+ }
882
+ }
883
+ }
884
+
885
+ if (do_next ) {
872
886
continue ;
873
887
}
874
888
@@ -899,7 +913,8 @@ struct channel_spy_context {
899
913
const char * name_context ;
900
914
};
901
915
902
- static int channel_spy_consume_iterator (struct ast_channel_iterator * iter ,
916
+ static int channel_spy_select_one (struct ast_channel_iterator * iter ,
917
+ struct ast_vector_const_string * channels_spied_upon ,
903
918
struct ast_channel * chan , int * num_spied_upon ,
904
919
int * volfactor , const int fd , const struct spy_dtmf_options * user_options ,
905
920
struct ast_flags * flags , const char * exitcontext , const struct channel_spy_context * ctx )
@@ -908,11 +923,12 @@ static int channel_spy_consume_iterator(struct ast_channel_iterator *iter,
908
923
struct ast_channel * prev = NULL ;
909
924
int res = 0 ;
910
925
911
- for (autochan = next_channel (iter , chan );
926
+ for (autochan = next_channel (iter , chan , channels_spied_upon );
912
927
autochan ;
913
928
prev = autochan -> chan ,
914
929
ast_autochan_destroy (autochan ),
915
- autochan = next_autochan ?: next_channel (iter , chan ),
930
+ autochan = next_autochan ?: (
931
+ iter ? next_channel (iter , chan , channels_spied_upon ) : NULL ),
916
932
next_autochan = NULL ) {
917
933
int igrp = !ctx -> mygroup ;
918
934
int ienf = !ctx -> myenforced ;
@@ -1010,6 +1026,19 @@ static int channel_spy_consume_iterator(struct ast_channel_iterator *iter,
1010
1026
continue ;
1011
1027
}
1012
1028
1029
+ /* Important! We destroy the channel iterator here, freeing unrelated channels
1030
+ * that are held by refcount. We're now holding on to exactly one victim channel. */
1031
+ iter = ast_channel_iterator_destroy (iter );
1032
+
1033
+ /* BUG: In theory, we're leaking (hoarding) memory until either:
1034
+ * - the spying channels hangs up, or
1035
+ * - we do a full iteration without getting finding a single channel to spy on.
1036
+ * When either event occurs, the memory is freed. This is more
1037
+ * likely to happen than not. */
1038
+ AST_VECTOR_APPEND (channels_spied_upon , ast_strdup (ast_channel_name (autochan -> chan )));
1039
+ ast_debug (1 , "After adding %s we have %zu items in the channels_spied_upon list\n" ,
1040
+ ast_channel_name (autochan -> chan ), AST_VECTOR_SIZE (channels_spied_upon ));
1041
+
1013
1042
if (!ast_test_flag (flags , OPTION_QUIET )) {
1014
1043
char peer_name [AST_NAME_STRLEN + 5 ];
1015
1044
char * ptr , * s ;
@@ -1088,19 +1117,24 @@ static int channel_spy_consume_iterator(struct ast_channel_iterator *iter,
1088
1117
}
1089
1118
} else if (res == 0 && ast_test_flag (flags , OPTION_EXITONHANGUP )) {
1090
1119
ast_autochan_destroy (autochan );
1091
- res = -2 ;
1120
+ res = -2 ; /* propagates stop, but with 0 exit status */
1092
1121
break ;
1093
1122
}
1094
1123
}
1095
1124
1096
- if (ast_test_flag (flags , OPTION_STOP ) && !next_autochan ) {
1097
- /* a single iteration was completed */
1098
- res = -2 ;
1125
+ if (iter ) {
1126
+ iter = ast_channel_iterator_destroy (iter );
1099
1127
}
1100
1128
1101
1129
return res ;
1102
1130
}
1103
1131
1132
+ /* Same as ast_free_ptr(), but this allows us to free const char*'s without the
1133
+ * compiler complaining about touching const. */
1134
+ static void free_const_ptr (const char * ptr ) {
1135
+ ast_free ((char * )ptr );
1136
+ }
1137
+
1104
1138
static int common_exec (struct ast_channel * chan , struct ast_flags * flags ,
1105
1139
int volfactor , const int fd , struct spy_dtmf_options * user_options ,
1106
1140
const struct channel_spy_context * ctx )
@@ -1111,6 +1145,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
1111
1145
int res ;
1112
1146
int num_spied_upon = 1 ;
1113
1147
struct ast_channel_iterator * iter = NULL ;
1148
+ struct ast_vector_const_string channels_spied_upon ;
1114
1149
1115
1150
if (ast_test_flag (flags , OPTION_EXIT )) {
1116
1151
const char * c ;
@@ -1128,6 +1163,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
1128
1163
1129
1164
ast_channel_set_flag (chan , AST_FLAG_SPYING );
1130
1165
1166
+ AST_VECTOR_INIT (& channels_spied_upon , 0 );
1131
1167
1132
1168
for (;;) {
1133
1169
if (!ast_test_flag (flags , OPTION_QUIET ) && num_spied_upon ) {
@@ -1177,7 +1213,6 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
1177
1213
1178
1214
res = ast_waitfordigit (chan , waitms );
1179
1215
if (res < 0 ) {
1180
- iter = ast_channel_iterator_destroy (iter );
1181
1216
ast_channel_clear_flag (chan , AST_FLAG_SPYING );
1182
1217
break ;
1183
1218
}
@@ -1186,25 +1221,50 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
1186
1221
tmp [0 ] = res ;
1187
1222
tmp [1 ] = '\0' ;
1188
1223
if (!ast_goto_if_exists (chan , exitcontext , tmp , 1 )) {
1189
- iter = ast_channel_iterator_destroy (iter );
1190
1224
break ;
1191
1225
}
1192
1226
ast_debug (2 , "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n" , tmp , exitcontext );
1193
1227
}
1194
1228
1229
+ /* The channel_spy_select_one spies on at most one channel. It
1230
+ * destroys the iterator so the unused channels can be freed asap. */
1195
1231
num_spied_upon = 0 ;
1196
- res = channel_spy_consume_iterator (iter , chan , & num_spied_upon , & volfactor , fd , user_options , flags , exitcontext , ctx );
1197
-
1198
- iter = ast_channel_iterator_destroy (iter );
1232
+ res = channel_spy_select_one (iter , & channels_spied_upon , chan , & num_spied_upon , & volfactor , fd , user_options , flags , exitcontext , ctx );
1233
+ iter = NULL ;
1199
1234
1200
1235
if (res == -2 ) {
1236
+ /* propagated stop */
1201
1237
res = 0 ;
1202
1238
break ;
1203
- } else if (res == -1 || ast_check_hangup (chan )) {
1239
+ } else if (res == -1 ) {
1240
+ /* stop because of error */
1241
+ break ;
1242
+ } else if (ast_check_hangup (chan )) {
1243
+ /* stop because spy hung up */
1204
1244
break ;
1205
1245
}
1246
+
1247
+ if (num_spied_upon == 0 ) {
1248
+ if (ast_test_flag (flags , OPTION_STOP )) {
1249
+ /* stop after one fully depleted iterator */
1250
+ break ;
1251
+ }
1252
+
1253
+ /* If we did spy on a channel, we'll keep the channels_spied_upon
1254
+ * list. If we spied on nothing, we'll wipe it so we
1255
+ * can restart the iteration. */
1256
+ AST_VECTOR_RESET (& channels_spied_upon , free_const_ptr );
1257
+ }
1258
+ }
1259
+
1260
+ if (iter ) {
1261
+ iter = ast_channel_iterator_destroy (iter );
1206
1262
}
1207
1263
1264
+ /* Make sure we free our temp storage. */
1265
+ AST_VECTOR_RESET (& channels_spied_upon , free_const_ptr );
1266
+ AST_VECTOR_FREE (& channels_spied_upon );
1267
+
1208
1268
ast_channel_clear_flag (chan , AST_FLAG_SPYING );
1209
1269
1210
1270
ast_channel_setoption (chan , AST_OPTION_TXGAIN , & zero_volume , sizeof (zero_volume ), 0 );
0 commit comments