res_parking: Fix some simple bugs
[asterisk/asterisk.git] / res / parking / parking_bridge.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Jonathan Rose <jrose@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Parking Bridge Class
22  *
23  * \author Jonathan Rose <jrose@digium.com>
24  */
25
26 #include "asterisk.h"
27 #include "asterisk/logger.h"
28 #include "res_parking.h"
29 #include "asterisk/astobj2.h"
30 #include "asterisk/features.h"
31 #include "asterisk/say.h"
32
33 struct ast_bridge_parking
34 {
35         struct ast_bridge base;
36
37         /* private stuff for parking */
38         struct parking_lot *lot;
39 };
40
41 /*!
42  * \internal
43  * \brief ast_bridge parking class destructor
44  * \since 12.0.0
45  *
46  * \param self Bridge to operate upon.
47  *
48  * \note XXX Stub... and it might go unused.
49  *
50  * \return Nothing
51  */
52 static void bridge_parking_destroy(struct ast_bridge_parking *self)
53 {
54         ast_bridge_base_v_table.destroy(&self->base);
55 }
56
57 static void bridge_parking_dissolving(struct ast_bridge_parking *self)
58 {
59         self->lot = NULL;
60         ast_bridge_base_v_table.dissolving(&self->base);
61 }
62
63 static void destroy_parked_user(void *obj)
64 {
65         struct parked_user *pu = obj;
66
67         ao2_cleanup(pu->lot);
68         pu->lot = NULL;
69
70         ao2_cleanup(pu->parker);
71         pu->parker = NULL;
72 }
73
74 /*!
75  * \internal
76  * \since 12
77  * \brief Construct a parked_user struct assigned to the specified parking lot
78  *
79  * \param lot The parking lot we are assigning the user to
80  * \param parkee The channel being parked
81  * \param parker The channel performing the park operation (may be the same channel)
82  * \param use_random_space if true, prioritize using a random parking space instead
83  *        of ${PARKINGEXTEN} and/or automatic assignment from the parking lot
84  * \param time_limit If using a custom timeout, this should be supplied so that the
85  *        parked_user struct can provide this information for manager events. If <0,
86  *        use the parking lot limit instead.
87  *
88  * \retval NULL on failure
89  * \retval reference to the parked user
90  *
91  * \note ao2_cleanup this reference when you are done using it or you'll cause leaks.
92  */
93 static struct parked_user *generate_parked_user(struct parking_lot *lot, struct ast_channel *chan, struct ast_channel *parker, int use_random_space, int time_limit)
94 {
95         struct parked_user *new_parked_user;
96         int preferred_space = -1; /* Initialize to use parking lot defaults */
97         int parking_space;
98         const char *parkingexten;
99
100         if (lot->mode == PARKINGLOT_DISABLED) {
101                 ast_log(LOG_NOTICE, "Tried to park in a parking lot that is no longer able to be parked to.\n");
102                 return NULL;
103         }
104
105         new_parked_user = ao2_alloc(sizeof(*new_parked_user), destroy_parked_user);
106         if (!new_parked_user) {
107                 return NULL;
108         }
109
110
111         if (use_random_space) {
112                 preferred_space = ast_random() % (lot->cfg->parking_stop - lot->cfg->parking_start + 1);
113                 preferred_space += lot->cfg->parking_start;
114         } else {
115                 ast_channel_lock(chan);
116                 if ((parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"))) {
117                         parkingexten = ast_strdupa(parkingexten);
118                 }
119                 ast_channel_unlock(chan);
120
121                 if (!ast_strlen_zero(parkingexten)) {
122                         if (sscanf(parkingexten, "%30d", &preferred_space) != 1 || preferred_space <= 0) {
123                                 ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n", parkingexten);
124                                 ao2_ref(new_parked_user, -1);
125                                 return NULL;
126                         }
127                 }
128         }
129
130
131         /* We need to keep the lot locked between parking_lot_get_space and actually placing it in the lot. Or until we decide not to. */
132         ao2_lock(lot);
133
134         parking_space = parking_lot_get_space(lot, preferred_space);
135         if (parking_space == -1) {
136                 ast_log(LOG_NOTICE, "Failed to get parking space in lot '%s'. All full.\n", lot->name);
137                 ao2_ref(new_parked_user, -1);
138                 ao2_unlock(lot);
139                 return NULL;
140         }
141
142         lot->next_space = ((parking_space + 1) - lot->cfg->parking_start) % (lot->cfg->parking_stop - lot->cfg->parking_start + 1) + lot->cfg->parking_start;
143         new_parked_user->chan = chan;
144         new_parked_user->parking_space = parking_space;
145
146         /* Have the parked user take a reference to the parking lot. This reference should be immutable and released at destruction */
147         new_parked_user->lot = lot;
148         ao2_ref(lot, +1);
149
150         new_parked_user->start = ast_tvnow();
151         new_parked_user->time_limit = (time_limit >= 0) ? time_limit : lot->cfg->parkingtime;
152         new_parked_user->parker = ast_channel_snapshot_create(parker);
153         if (!new_parked_user->parker) {
154                 ao2_ref(new_parked_user, -1);
155                 ao2_unlock(lot);
156                 return NULL;
157         }
158
159         /* Insert into the parking lot's parked user list. We can unlock the lot now. */
160         ao2_link(lot->parked_users, new_parked_user);
161         ao2_unlock(lot);
162
163         return new_parked_user;
164 }
165
166 /* TODO CEL events for parking */
167
168 /*!
169  * \internal
170  * \brief ast_bridge parking push method.
171  * \since 12.0.0
172  *
173  * \param self Bridge to operate upon
174  * \param bridge_channel Bridge channel to push
175  * \param swap Bridge channel to swap places with if not NULL
176  *
177  * \note On entry, self is already locked
178  *
179  * \retval 0 on success
180  * \retval -1 on failure
181  */
182 static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
183 {
184         struct parked_user *pu;
185         int randomize = 0;
186         int time_limit = -1;
187         int silence = 0;
188         const char *blind_transfer;
189         RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);
190         RAII_VAR(char *, parker_uuid, NULL, ast_free);
191         RAII_VAR(char *, comeback_override, NULL, ast_free);
192
193         ast_bridge_base_v_table.push(&self->base, bridge_channel, swap);
194
195         ast_assert(self->lot != NULL);
196
197         /* Answer the channel if needed */
198         if (ast_channel_state(bridge_channel->chan) != AST_STATE_UP) {
199                 ast_answer(bridge_channel->chan);
200         }
201
202         if (swap) {
203                 ao2_lock(swap);
204                 pu = swap->bridge_pvt;
205                 if (!pu) {
206                         /* This should be impossible since the only way a channel can enter in the first place
207                          * is if it has a parked user associated with it */
208                         publish_parked_call_failure(bridge_channel->chan);
209                         ao2_unlock(swap);
210                         return -1;
211                 }
212
213                 /* Give the swap channel's parked user reference to the incoming channel */
214                 pu->chan = bridge_channel->chan;
215                 bridge_channel->bridge_pvt = pu;
216                 swap->bridge_pvt = NULL;
217
218                 /* TODO Add a parked call swap message type to relay information about parked channel swaps */
219
220                 ao2_unlock(swap);
221
222                 parking_set_duration(bridge_channel->features, pu);
223
224                 /* BUGBUG Adding back local channel swapping made us not hear music on hold for the channel that got swapped
225                  * into the parking lot. Setting the roels back up gets around that, but we still need to deal with the ringing option
226                  * to the park application here somehow.
227                  */
228                 parking_channel_set_roles(bridge_channel->chan, self->lot, 0);
229
230                 return 0;
231         }
232
233         get_park_common_datastore_data(bridge_channel->chan, &parker_uuid, &comeback_override, &randomize, &time_limit, &silence);
234         parker = ast_channel_get_by_name(parker_uuid);
235
236         /* If the parker and the parkee are the same channel pointer, then the channel entered using
237          * the park application. It's possible the the blindtransfer channel is still alive (particularly
238          * when a multichannel bridge is parked), so try to get the real parker if possible. */
239         ast_channel_lock(bridge_channel->chan);
240         blind_transfer = S_OR(pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER"),
241                 ast_channel_name(bridge_channel->chan));
242         if (blind_transfer) {
243                 blind_transfer = ast_strdupa(blind_transfer);
244         }
245         ast_channel_unlock(bridge_channel->chan);
246
247         if (parker == bridge_channel->chan) {
248                 struct ast_channel *real_parker = ast_channel_get_by_name(blind_transfer);
249                 if (real_parker) {
250                         ao2_cleanup(parker);
251                         parker = real_parker;
252                 }
253         }
254
255         if (!parker) {
256                 return -1;
257         }
258
259         pu = generate_parked_user(self->lot, bridge_channel->chan, parker, randomize, time_limit);
260         if (!pu) {
261                 publish_parked_call_failure(bridge_channel->chan);
262                 return -1;
263         }
264
265         /* If a comeback_override was provided, set it for the parked user's comeback string. */
266         if (comeback_override) {
267                 strncpy(pu->comeback, comeback_override, sizeof(pu->comeback));
268                 pu->comeback[sizeof(pu->comeback) - 1] = '\0';
269         }
270
271         /* Generate ParkedCall Stasis Message */
272         publish_parked_call(pu, PARKED_CALL);
273
274         /* If the parkee and the parker are the same and silence_announce isn't set, play the announcement to the parkee */
275         if (!strcmp(blind_transfer, ast_channel_name(bridge_channel->chan)) && !silence) {
276                 char saynum_buf[16];
277                 snprintf(saynum_buf, sizeof(saynum_buf), "%u %u", 0, pu->parking_space);
278                 ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
279         }
280
281         /* Apply parking duration limits */
282         parking_set_duration(bridge_channel->features, pu);
283
284         /* Set this to the bridge pvt so that we don't have to refind the parked user associated with this bridge channel again. */
285         bridge_channel->bridge_pvt = pu;
286
287         return 0;
288 }
289
290 /*!
291  * \internal
292  * \brief ast_bridge parking pull method.
293  * \since 12.0.0
294  *
295  * \param self Bridge to operate upon.
296  * \param bridge_channel Bridge channel to pull.
297  *
298  * \note On entry, self is already locked.
299  *
300  * \return Nothing
301  */
302 static void bridge_parking_pull(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
303 {
304         RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
305         ast_bridge_base_v_table.pull(&self->base, bridge_channel);
306
307         /* Take over the bridge channel's pu reference. It will be released when we are done. */
308         pu = bridge_channel->bridge_pvt;
309         bridge_channel->bridge_pvt = NULL;
310
311         /* This should only happen if the exiting channel was swapped out */
312         if (!pu) {
313                 return;
314         }
315
316         /* If we got here without the resolution being set, that's because the call was hung up for some reason without
317          * timing out or being picked up. There may be some forcible park removals later, but the resolution should be
318          * handled in those cases */
319         ao2_lock(pu);
320         if (pu->resolution == PARK_UNSET) {
321                 pu->resolution = PARK_ABANDON;
322         }
323         ao2_unlock(pu);
324
325         switch (pu->resolution) {
326         case PARK_UNSET:
327                 /* This should be impossible now since the resolution is forcibly set to abandon if it was unset at this point. Resolution
328                    isn't allowed to be changed when it isn't currently PARK_UNSET. */
329                 return;
330         case PARK_ABANDON:
331                 /* Since the call was abandoned without additional handling, we need to issue the give up event and unpark the user. */
332                 publish_parked_call(pu, PARKED_CALL_GIVEUP);
333                 unpark_parked_user(pu);
334                 return;
335         case PARK_FORCED:
336                 /* PARK_FORCED is currently unused, but it is expected that it would be handled similar to PARK_ANSWERED.
337                  * There is currently no event related to forced parked calls either */
338                 return;
339         case PARK_ANSWERED:
340                 /* If answered or forced, the channel should be pulled from the bridge as part of that process and unlinked from
341                  * the parking lot afterwards. We do need to apply bridge features though and play the courtesy tone if set. */
342                 publish_parked_call(pu, PARKED_CALL_UNPARKED);
343                 parked_call_retrieve_enable_features(bridge_channel->chan, pu->lot, AST_FEATURE_FLAG_BYCALLEE);
344
345                 if (pu->lot->cfg->parkedplay & AST_FEATURE_FLAG_BYCALLEE) {
346                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, pu->lot->cfg->courtesytone, NULL);
347                 }
348
349                 return;
350         case PARK_TIMEOUT:
351                 /* Timeout is similar to abandon because it simply sets the bridge state to end and doesn't
352                  * actually pull the channel. Because of that, unpark should happen in here. */
353                 publish_parked_call(pu, PARKED_CALL_TIMEOUT);
354                 unpark_parked_user(pu);
355                 return;
356         }
357 }
358
359 /*!
360  * \internal
361  * \brief ast_bridge parking notify_masquerade method.
362  * \since 12.0.0
363  *
364  * \param self Bridge to operate upon.
365  * \param bridge_channel Bridge channel that was masqueraded.
366  *
367  * \note On entry, self is already locked.
368  * \note XXX Stub... and it will probably go unused.
369  *
370  * \return Nothing
371  */
372 static void bridge_parking_notify_masquerade(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
373 {
374         ast_bridge_base_v_table.notify_masquerade(&self->base, bridge_channel);
375 }
376
377 static void bridge_parking_get_merge_priority(struct ast_bridge_parking *self)
378 {
379         ast_bridge_base_v_table.get_merge_priority(&self->base);
380 }
381
382 struct ast_bridge_methods ast_bridge_parking_v_table = {
383         .name = "parking",
384         .destroy = (ast_bridge_destructor_fn) bridge_parking_destroy,
385         .dissolving = (ast_bridge_dissolving_fn) bridge_parking_dissolving,
386         .push = (ast_bridge_push_channel_fn) bridge_parking_push,
387         .pull = (ast_bridge_pull_channel_fn) bridge_parking_pull,
388         .notify_masquerade = (ast_bridge_notify_masquerade_fn) bridge_parking_notify_masquerade,
389         .get_merge_priority = (ast_bridge_merge_priority_fn) bridge_parking_get_merge_priority,
390 };
391
392 static struct ast_bridge *ast_bridge_parking_init(struct ast_bridge_parking *self, struct parking_lot *bridge_lot)
393 {
394         if (!self) {
395                 return NULL;
396         }
397
398         /* If no lot is defined for the bridge, then we aren't allowing the bridge to be initialized. */
399         if (!bridge_lot) {
400                 ao2_ref(self, -1);
401                 return NULL;
402         }
403
404         /* It doesn't need to be a reference since the bridge only lives as long as the parking lot lives. */
405         self->lot = bridge_lot;
406
407         return &self->base;
408 }
409
410 struct ast_bridge *bridge_parking_new(struct parking_lot *bridge_lot)
411 {
412         void *bridge;
413
414         bridge = ast_bridge_alloc(sizeof(struct ast_bridge_parking), &ast_bridge_parking_v_table);
415         bridge = ast_bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
416                 AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
417                 | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM);
418         bridge = ast_bridge_parking_init(bridge, bridge_lot);
419         bridge = ast_bridge_register(bridge);
420         return bridge;
421 }