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

Diff revision 12

This is not the most recent revision of the diff. The latest diff is revision 16. See what's changed.

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...
trunk/apps/app_directed_pickup.c
Revision 317665 New Change
[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
	int res = 0;

   
104
	struct ast_party_connected_line connected_caller;

   
105
	struct ast_channel *chans[2] = { chan, target };

   
106

    
   

   
107
	ast_debug(1, "Call pickup on '%s' by '%s'\n", target->name, chan->name);

   
108
	ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);

   
109

    
   

   
110
	ast_party_connected_line_init(&connected_caller);

   
111
	ast_party_connected_line_copy(&connected_caller, &target->connected);

   
112
	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;

   
113
	if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {

   
114
		ast_channel_update_connected_line(chan, &connected_caller, NULL);

   
115
	}

   
116
	ast_party_connected_line_free(&connected_caller);

   
117

    
   

   
118
	ast_channel_lock(chan);

   
119
	ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);

   
120
	ast_channel_unlock(chan);

   
121
	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;

   
122
	ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);

   
123
	ast_party_connected_line_free(&connected_caller);

   
124

    
   

   
125
	if ((res = ast_answer(chan))) {

   
126
		ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);

   
127
		return -1;

   
128
	}

   
129

    
   

   
130
	if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {

   
131
		ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);

   
132
		return -1;

   
133
	}

   
134

    
   

   
135
	if ((res = ast_channel_masquerade(target, chan))) {

   
136
		ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);

   
137
		return -1;

   
138
	}

   
139

    
   

   
140
	/* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */

   
141
	ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,

   
142
		"Channel: %s\r\nTargetChannel: %s\r\n", chan->name, target->name);

   
143

    
   

   
144
	return res;
Moved to 273

   
145
}
Moved to 274

   
146

    
   

   
147
/* 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 */
148
static int can_pickup(struct ast_channel *chan)
101
static int can_pickup(struct ast_channel *chan)
149
{
102
{
150
	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)) {
151
		return 1;
108
		return 1;
152
	else
109
	}
153
		return 0;
110
	return 0;
154
}
111
}
155

    
   
112

   
156
struct pickup_by_name_args {
113
struct pickup_by_name_args {
157
	const char *name;
114
	const char *name;
[+20] [20] 53 lines
[+20] [+] static int pickup_by_channel(struct ast_channel *chan, char *pickup)
211
		return -1;
168
		return -1;
212
	}
169
	}
213

    
   
170

   
214
	/* 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 */
215
	if (chan != target) {
172
	if (chan != target) {
216
		res = pickup_do(chan, target);
173
		res = ast_do_pickup(chan, target);
217
	}
174
	}
218

    
   

   
219
	ast_channel_unlock(target);
175
	ast_channel_unlock(target);
220
	target = ast_channel_unref(target);
176
	target = ast_channel_unref(target);
221

    
   
177

   
222
	return res;
178
	return res;
223
}
179
}
[+20] [20] 10 lines
[+20] [+] static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
234
	}
190
	}
235

    
   
191

   
236
	while ((target = ast_channel_iterator_next(iter))) {
192
	while ((target = ast_channel_iterator_next(iter))) {
237
		ast_channel_lock(target);
193
		ast_channel_lock(target);
238
		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);
239
			break;
196
			break;
240
		}
197
		}
241
		ast_channel_unlock(target);
198
		ast_channel_unlock(target);
242
		target = ast_channel_unref(target);
199
		target = ast_channel_unref(target);
243
	}
200
	}
244

    
   
201

   
245
	ast_channel_iterator_destroy(iter);
202
	ast_channel_iterator_destroy(iter);
246

    
   
203

   
247
	if (target) {
204
	if (target) {
248
		res = pickup_do(chan, target);
205
		res = ast_do_pickup(chan, target);
249
		ast_channel_unlock(target);
206
		ast_channel_unlock(target);
250
		target = ast_channel_unref(target);
207
		target = ast_channel_unref(target);
251
	}
208
	}
252

    
   
209

   
253
	return res;
210
	return res;
[+20] [20] 21 lines
[+20] [+] static int find_by_mark(void *obj, void *arg, void *data, int flags)
275
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)
276
{
233
{
277
	struct ast_channel *target;
234
	struct ast_channel *target;
278
	int res = -1;
235
	int res = -1;
279

    
   
236

   
280
	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))) {
Moved from 144

    
   
238
		return res;
Moved from 145

    
   
239
	}

    
   
240

   
281
		ast_channel_lock(target);
241
	ast_channel_lock(target);
282
		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
	}
283
		ast_channel_unlock(target);
247
	ast_channel_unlock(target);
284
		target = ast_channel_unref(target);
248
	target = ast_channel_unref(target);

    
   
249

   
Moved from 144

    
   
250
	return res;
Moved from 145

    
   
251
}

    
   
252

   

    
   
253
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)

    
   
254
{

    
   
255
	struct ast_channel *chan = obj;

    
   
256
	struct ast_channel *c = data;

    
   
257
	int i;

    
   
258

   

    
   
259
	ast_channel_lock(chan);

    
   
260
	i = (c != chan) && (chan->pickupgroup & c->callgroup) &&

    
   
261
		can_pickup(chan);

    
   
262

   

    
   
263
	ast_channel_unlock(chan);

    
   
264
	return i ? CMP_MATCH | CMP_STOP : 0;
285
	}
265
}
286

    
   
266

   

    
   
267
static int pickup_by_group(struct ast_channel *chan)

    
   
268
{

    
   
269
	struct ast_channel *target;

    
   
270
	int res = -1;

    
   
271

   

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

    
   
273
		return res;
Moved from 145

    
   
274
	}

    
   
275

   

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

    
   
277
	ast_channel_lock(target);

    
   
278
	if (can_pickup(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
	}

    
   
283
	ast_channel_unlock(target);

    
   
284
	target = ast_channel_unref(target);

    
   
285

   
287
	return res;
286
	return res;
288
}
287
}
289

    
   
288

   
290
/* application entry point for Pickup() */
289
/* application entry point for Pickup() */
291
static int pickup_exec(struct ast_channel *chan, const char *data)
290
static int pickup_exec(struct ast_channel *chan, const char *data)
292
{
291
{
293
	int res = 0;
292
	int res = 0;
294
	char *tmp = ast_strdupa(data);
293
	char *tmp = ast_strdupa(data);
295
	char *exten = NULL, *context = NULL;
294
	char *exten = NULL, *context = NULL;
296

    
   
295

   
297
	if (ast_strlen_zero(data)) {
296
	if (ast_strlen_zero(data)) {
298
		res = ast_pickup_call(chan);
297
		res = pickup_by_group(chan);
299
		return res;
298
		return res;
300
	}
299
	}
301
	
300

   
302
	/* Parse extension (and context if there) */
301
	/* Parse extension (and context if there) */
303
	while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
302
	while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
304
		if ((context = strchr(exten, '@')))
303
		if ((context = strchr(exten, '@')))
305
			*context++ = '\0';
304
			*context++ = '\0';
306
		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)
339
	struct ast_channel *target;
338
	struct ast_channel *target;
340
	int res = -1;
339
	int res = -1;
341

    
   
340

   
342
	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))) {
343
		ast_channel_lock(target);
342
		ast_channel_lock(target);
344
		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
		}
345
		ast_channel_unlock(target);
348
		ast_channel_unlock(target);
346
		target = ast_channel_unref(target);
349
		target = ast_channel_unref(target);
347
	}
350
	}
348

    
   
351

   
349
	return res;
352
	return res;
[+20] [20] 64 lines
trunk/channels/chan_sip.c
Revision 317665 New Change
 
trunk/include/asterisk/features.h
Revision 317665 New Change
 
trunk/main/features.c
Revision 317665 New Change
 
  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...

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.