Review Board 1.7.16


Fix directed group pickup feature code *8 with pickupsounds enabled , deadlock and segfault, affects 1.8.0 and trunk

Review Request #1185 - Created April 17, 2011 and submitted

Alec Davis
trunk
18654
Reviewers
asterisk-dev
rmudgett
Asterisk
Since 1.8, the new pickupsound and pickupfailsound in features.conf cause many issues.

1). chan_sip:handle_request_invite() shouldn't be playing out the fail/success audio, as it has 'netlock' locked.
2). dialplan applications for directed_pickups shouldn't beep.
3). feature code for directed pickup should beep on success/failure if configured.

Moved app_directed:pickup_do() to features:ast_do_pickup().

Functions below, all now use the new ast_do_pickup()
app_directed_pickup.c:
   pickup_by_channel()
   pickup_by_exten()
   pickup_by_mark()
   pickup_by_part()
features.c:
   ast_pickup_call()

Created a sip_pickup() thread to handle the pickup and playout the audio, spawned from handle_request_invite.
pickup using *8 feature code, with pickup sounds enabled/disabled

exten => 71,1,Pickup()           ; any ringing extension in same pickupgroup 
exten => 72,1,Pickup(85@phones)  ; dahdi extension
exten => 73,1,Pickup(823@phones) ; sip extension

Changes between revision 4 and 16

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

  1. trunk/apps/app_directed_pickup.c: Loading...
  2. trunk/channels/chan_sip.c: Loading...
  3. trunk/include/asterisk/features.h: Loading...
  4. trunk/main/features.c: Loading...
  5. trunk/res/res_features.exports.in: Loading...
trunk/apps/app_directed_pickup.c
Diff Revision 4 Diff Revision 16
[20] 94 lines
[+20] [+] ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
95

    
   
95

   
96
static const char app[] = "Pickup";
96
static const char app[] = "Pickup";
97
static const char app2[] = "PickupChan";
97
static const char app2[] = "PickupChan";
98
/*! \todo This application should return a result code, like PICKUPRESULT */
98
/*! \todo This application should return a result code, like PICKUPRESULT */
99

    
   
99

   
100
/* Perform actual pickup between two channels */

   
101
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)

   
102
{

   
103
	return ast_do_pickup(chan, target);

   
104
}

   
105

    
   

   
106
/* Helper function that determines whether a channel is capable of being picked up */
100
/* Helper function that determines whether a channel is capable of being picked up */
107
static int can_pickup(struct ast_channel *chan)
101
static int can_pickup(struct ast_channel *chan)
108
{
102
{
109
	if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
103
	if (!chan->pbx && !chan->masq &&

    
   
104
		!ast_test_flag(chan, AST_FLAG_ZOMBIE) &&

    
   
105
		(chan->_state == AST_STATE_RINGING ||

    
   
106
		 chan->_state == AST_STATE_RING ||

    
   
107
		 chan->_state == AST_STATE_DOWN)) {
110
		return 1;
108
		return 1;
111
	else
109
	}
112
		return 0;
110
	return 0;
113
}
111
}
114

    
   
112

   
115
struct pickup_by_name_args {
113
struct pickup_by_name_args {
116
	const char *name;
114
	const char *name;
[+20] [20] 53 lines
[+20] [+] static int pickup_by_channel(struct ast_channel *chan, char *pickup)
170
		return -1;
168
		return -1;
171
	}
169
	}
172

    
   
170

   
173
	/* Just check that we are not picking up the SAME as target */
171
	/* Just check that we are not picking up the SAME as target */
174
	if (chan != target) {
172
	if (chan != target) {
175
		res = pickup_do(chan, target);
173
		res = ast_do_pickup(chan, target);
176
	}
174
	}
177

    
   

   
178
	ast_channel_unlock(target);
175
	ast_channel_unlock(target);
179
	target = ast_channel_unref(target);
176
	target = ast_channel_unref(target);
180

    
   
177

   
181
	return res;
178
	return res;
182
}
179
}
[+20] [20] 10 lines
[+20] [+] static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
193
	}
190
	}
194

    
   
191

   
195
	while ((target = ast_channel_iterator_next(iter))) {
192
	while ((target = ast_channel_iterator_next(iter))) {
196
		ast_channel_lock(target);
193
		ast_channel_lock(target);
197
		if ((chan != target) && can_pickup(target)) {
194
		if ((chan != target) && can_pickup(target)) {

    
   
195
			ast_log(LOG_NOTICE, "%s pickup by %s\n", target->name, chan->name);
198
			break;
196
			break;
199
		}
197
		}
200
		ast_channel_unlock(target);
198
		ast_channel_unlock(target);
201
		target = ast_channel_unref(target);
199
		target = ast_channel_unref(target);
202
	}
200
	}
203

    
   
201

   
204
	ast_channel_iterator_destroy(iter);
202
	ast_channel_iterator_destroy(iter);
205

    
   
203

   
206
	if (target) {
204
	if (target) {
207
		res = pickup_do(chan, target);
205
		res = ast_do_pickup(chan, target);
208
		ast_channel_unlock(target);
206
		ast_channel_unlock(target);
209
		target = ast_channel_unref(target);
207
		target = ast_channel_unref(target);
210
	}
208
	}
211

    
   
209

   
212
	return res;
210
	return res;
[+20] [20] 21 lines
[+20] [+] static int find_by_mark(void *obj, void *arg, void *data, int flags)
234
static int pickup_by_mark(struct ast_channel *chan, const char *mark)
232
static int pickup_by_mark(struct ast_channel *chan, const char *mark)
235
{
233
{
236
	struct ast_channel *target;
234
	struct ast_channel *target;
237
	int res = -1;
235
	int res = -1;
238

    
   
236

   
239
	if ((target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
237
	if (!(target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {

    
   
238
		return res;

    
   
239
	}

    
   
240

   
240
		ast_channel_lock(target);
241
	ast_channel_lock(target);
241
		res = pickup_do(chan, target);
242
	if (can_pickup(target)) {

    
   
243
		res = ast_do_pickup(chan, target);

    
   
244
	} else {

    
   
245
		ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);

    
   
246
	}
242
		ast_channel_unlock(target);
247
	ast_channel_unlock(target);
243
		target = ast_channel_unref(target);
248
	target = ast_channel_unref(target);
244
	}

   
245

    
   
249

   
246
	return res;
250
	return res;
247
}
251
}
248

    
   
252

   
249
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
253
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
250
{
254
{
251
	struct ast_channel *c = data;

   
252
	struct ast_channel *chan = obj;
255
	struct ast_channel *chan = obj;

    
   
256
	struct ast_channel *c = data;

    
   
257
	int i;
253

    
   
258

   
254
	ast_channel_lock(chan);
259
	ast_channel_lock(chan);
255
	int i = !chan->pbx &&
260
	i = (c != chan) && (c->pickupgroup & chan->callgroup) &&
256
		(c != chan) &&
261
		can_pickup(chan);
257
		(chan->pickupgroup & c->callgroup) &&

   
258
		((chan->_state == AST_STATE_RINGING) || (chan->_state == AST_STATE_RING)) &&

   
259
		!c->masq;

   
260

    
   
262

   
261
	ast_channel_unlock(chan);
263
	ast_channel_unlock(chan);
262
	return i ? CMP_MATCH | CMP_STOP : 0;
264
	return i ? CMP_MATCH | CMP_STOP : 0;
263
}
265
}
264

    
   
266

   
265
static int pickup_by_group(struct ast_channel *chan)
267
static int pickup_by_group(struct ast_channel *chan)
266
{
268
{
267
	struct ast_channel *target;
269
	struct ast_channel *target;
268
	int res = -1;
270
	int res = -1;
269
	if ((target = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
271

   

    
   
272
	if (!(target = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {

    
   
273
		return res;

    
   
274
	}

    
   
275

   

    
   
276
	ast_log(LOG_NOTICE, "%s, pickup attempt by %s\n", target->name, chan->name);
270
		ast_channel_lock(target);
277
	ast_channel_lock(target);

    
   
278
	if (can_pickup(target)) {
271
		res = ast_do_pickup(chan, target);
279
		res = ast_do_pickup(chan, target);

    
   
280
	} else {

    
   
281
		ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);

    
   
282
	}
272
		ast_channel_unlock(target);
283
	ast_channel_unlock(target);
273
		target = ast_channel_unref(target);
284
	target = ast_channel_unref(target);
274
	}
285

   
275
	return res;
286
	return res;
276
}
287
}
277

    
   
288

   
278
/* application entry point for Pickup() */
289
/* application entry point for Pickup() */
279
static int pickup_exec(struct ast_channel *chan, const char *data)
290
static int pickup_exec(struct ast_channel *chan, const char *data)
[+20] [20] 4 lines
[+20] static int pickup_by_group(struct ast_channel *chan)
284

    
   
295

   
285
	if (ast_strlen_zero(data)) {
296
	if (ast_strlen_zero(data)) {
286
		res = pickup_by_group(chan);
297
		res = pickup_by_group(chan);
287
		return res;
298
		return res;
288
	}
299
	}
289
	
300

   
290
	/* Parse extension (and context if there) */
301
	/* Parse extension (and context if there) */
291
	while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
302
	while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
292
		if ((context = strchr(exten, '@')))
303
		if ((context = strchr(exten, '@')))
293
			*context++ = '\0';
304
			*context++ = '\0';
294
		if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
305
		if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
[+20] [20] 32 lines
[+20] [+] static int pickup_by_part(struct ast_channel *chan, const char *part)
327
	struct ast_channel *target;
338
	struct ast_channel *target;
328
	int res = -1;
339
	int res = -1;
329

    
   
340

   
330
	if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
341
	if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
331
		ast_channel_lock(target);
342
		ast_channel_lock(target);
332
		res = pickup_do(chan, target);
343
		if (can_pickup(target)) {

    
   
344
			res = ast_do_pickup(chan, target);

    
   
345
		} else {

    
   
346
			ast_log(LOG_WARNING, "target has gone, or not ringing anymore for %s\n", chan->name);

    
   
347
		}
333
		ast_channel_unlock(target);
348
		ast_channel_unlock(target);
334
		target = ast_channel_unref(target);
349
		target = ast_channel_unref(target);
335
	}
350
	}
336

    
   
351

   
337
	return res;
352
	return res;
[+20] [20] 64 lines
trunk/channels/chan_sip.c
Diff Revision 4 Diff Revision 16
 
trunk/include/asterisk/features.h
Diff Revision 4 Diff Revision 16
 
trunk/main/features.c
Diff Revision 4 Diff Revision 16
 
trunk/res/res_features.exports.in
Diff Revision 4 Diff Revision 16 - File Reverted
 
  1. trunk/apps/app_directed_pickup.c: Loading...
  2. trunk/channels/chan_sip.c: Loading...
  3. trunk/include/asterisk/features.h: Loading...
  4. trunk/main/features.c: Loading...
  5. trunk/res/res_features.exports.in: Loading...

https://reviewboard.asterisk.org/ runs on a server provided by Digium, Inc. and uses bandwidth donated to the open source Asterisk community by API Digital Communications in Huntsville, AL USA.
Please report problems with this site to asteriskteam@digium.com.