parking_bridge.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  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. /*! \file
  19. *
  20. * \brief Parking Bridge Class
  21. *
  22. * \author Jonathan Rose <jrose@digium.com>
  23. */
  24. #include "asterisk.h"
  25. #include "res_parking.h"
  26. #include "asterisk/astobj2.h"
  27. #include "asterisk/logger.h"
  28. #include "asterisk/say.h"
  29. #include "asterisk/term.h"
  30. #include "asterisk/features.h"
  31. #include "asterisk/bridge_internal.h"
  32. struct ast_bridge_parking
  33. {
  34. struct ast_bridge base;
  35. /* private stuff for parking */
  36. struct parking_lot *lot;
  37. };
  38. /*!
  39. * \internal
  40. * \brief ast_bridge parking class destructor
  41. * \since 12.0.0
  42. *
  43. * \param self Bridge to operate upon.
  44. *
  45. * \note XXX Stub... and it might go unused.
  46. *
  47. * \return Nothing
  48. */
  49. static void bridge_parking_destroy(struct ast_bridge_parking *self)
  50. {
  51. ast_bridge_base_v_table.destroy(&self->base);
  52. }
  53. static void bridge_parking_dissolving(struct ast_bridge_parking *self)
  54. {
  55. self->lot = NULL;
  56. ast_bridge_base_v_table.dissolving(&self->base);
  57. }
  58. static void destroy_parked_user(void *obj)
  59. {
  60. struct parked_user *pu = obj;
  61. ao2_cleanup(pu->lot);
  62. ao2_cleanup(pu->retriever);
  63. ast_free(pu->parker_dial_string);
  64. }
  65. /* Only call this on a parked user that hasn't had its parker_dial_string set already */
  66. static int parked_user_set_parker_dial_string(struct parked_user *pu, struct ast_channel *parker)
  67. {
  68. char *dial_string = ast_strdupa(ast_channel_name(parker));
  69. ast_channel_name_to_dial_string(dial_string);
  70. pu->parker_dial_string = ast_strdup(dial_string);
  71. if (!pu->parker_dial_string) {
  72. return -1;
  73. }
  74. return 0;
  75. }
  76. /*!
  77. * \internal
  78. * \since 12
  79. * \brief Construct a parked_user struct assigned to the specified parking lot
  80. *
  81. * \param lot The parking lot we are assigning the user to
  82. * \param parkee The channel being parked
  83. * \param parker The channel performing the park operation (may be the same channel)
  84. * \param parker_dial_string Takes priority over parker for setting the parker dial string if included
  85. * \param use_random_space if true, prioritize using a random parking space instead
  86. * of ${PARKINGEXTEN} and/or automatic assignment from the parking lot
  87. * \param time_limit If using a custom timeout, this should be supplied so that the
  88. * parked_user struct can provide this information for manager events. If <0,
  89. * use the parking lot limit instead.
  90. *
  91. * \retval NULL on failure
  92. * \retval reference to the parked user
  93. *
  94. * \note ao2_cleanup this reference when you are done using it or you'll cause leaks.
  95. */
  96. static struct parked_user *generate_parked_user(struct parking_lot *lot, struct ast_channel *chan, struct ast_channel *parker, const char *parker_dial_string, int use_random_space, int time_limit)
  97. {
  98. struct parked_user *new_parked_user;
  99. int preferred_space = -1; /* Initialize to use parking lot defaults */
  100. int parking_space;
  101. const char *parkingexten;
  102. if (lot->mode == PARKINGLOT_DISABLED) {
  103. ast_log(LOG_NOTICE, "Tried to park in a parking lot that is no longer able to be parked to.\n");
  104. return NULL;
  105. }
  106. new_parked_user = ao2_alloc(sizeof(*new_parked_user), destroy_parked_user);
  107. if (!new_parked_user) {
  108. return NULL;
  109. }
  110. if (use_random_space) {
  111. preferred_space = ast_random() % (lot->cfg->parking_stop - lot->cfg->parking_start + 1);
  112. preferred_space += lot->cfg->parking_start;
  113. } else {
  114. ast_channel_lock(chan);
  115. if ((parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"))) {
  116. parkingexten = ast_strdupa(parkingexten);
  117. }
  118. ast_channel_unlock(chan);
  119. if (!ast_strlen_zero(parkingexten)) {
  120. if (sscanf(parkingexten, "%30d", &preferred_space) != 1 || preferred_space <= 0) {
  121. ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n", parkingexten);
  122. ao2_ref(new_parked_user, -1);
  123. return NULL;
  124. }
  125. }
  126. }
  127. /* 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. */
  128. ao2_lock(lot);
  129. parking_space = parking_lot_get_space(lot, preferred_space);
  130. if (parking_space == -1) {
  131. ast_log(LOG_NOTICE, "Failed to get parking space in lot '%s'. All full.\n", lot->name);
  132. ao2_ref(new_parked_user, -1);
  133. ao2_unlock(lot);
  134. return NULL;
  135. }
  136. lot->next_space = ((parking_space + 1) - lot->cfg->parking_start) % (lot->cfg->parking_stop - lot->cfg->parking_start + 1) + lot->cfg->parking_start;
  137. new_parked_user->chan = chan;
  138. new_parked_user->parking_space = parking_space;
  139. /* Have the parked user take a reference to the parking lot. This reference should be immutable and released at destruction */
  140. new_parked_user->lot = lot;
  141. ao2_ref(lot, +1);
  142. new_parked_user->start = ast_tvnow();
  143. new_parked_user->time_limit = (time_limit >= 0) ? time_limit : lot->cfg->parkingtime;
  144. if (parker_dial_string) {
  145. new_parked_user->parker_dial_string = ast_strdup(parker_dial_string);
  146. } else {
  147. if (!parker || parked_user_set_parker_dial_string(new_parked_user, parker)) {
  148. ao2_ref(new_parked_user, -1);
  149. ao2_unlock(lot);
  150. return NULL;
  151. }
  152. }
  153. if (!new_parked_user->parker_dial_string) {
  154. ao2_ref(new_parked_user, -1);
  155. ao2_unlock(lot);
  156. return NULL;
  157. }
  158. /* Insert into the parking lot's parked user list. We can unlock the lot now. */
  159. ao2_link(lot->parked_users, new_parked_user);
  160. ao2_unlock(lot);
  161. return new_parked_user;
  162. }
  163. /* TODO CEL events for parking */
  164. /*!
  165. * \internal
  166. * \brief ast_bridge parking push method.
  167. * \since 12.0.0
  168. *
  169. * \param self Bridge to operate upon
  170. * \param bridge_channel Bridge channel to push
  171. * \param swap Bridge channel to swap places with if not NULL
  172. *
  173. * \note On entry, self is already locked
  174. *
  175. * \retval 0 on success
  176. * \retval -1 on failure
  177. */
  178. static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
  179. {
  180. struct parked_user *pu;
  181. const char *blind_transfer;
  182. RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup); /* XXX replace with ast_channel_cleanup when available */
  183. RAII_VAR(struct park_common_datastore *, park_datastore, NULL, park_common_datastore_free);
  184. ast_bridge_base_v_table.push(&self->base, bridge_channel, swap);
  185. ast_assert(self->lot != NULL);
  186. /* Answer the channel if needed */
  187. if (ast_channel_state(bridge_channel->chan) != AST_STATE_UP) {
  188. ast_answer(bridge_channel->chan);
  189. }
  190. if (swap) {
  191. int use_ringing = 0;
  192. ast_bridge_channel_lock(swap);
  193. pu = swap->bridge_pvt;
  194. if (!pu) {
  195. /* This should be impossible since the only way a channel can enter in the first place
  196. * is if it has a parked user associated with it */
  197. publish_parked_call_failure(bridge_channel->chan);
  198. ast_bridge_channel_unlock(swap);
  199. return -1;
  200. }
  201. /* Give the swap channel's parked user reference to the incoming channel */
  202. pu->chan = bridge_channel->chan;
  203. bridge_channel->bridge_pvt = pu;
  204. swap->bridge_pvt = NULL;
  205. if (ast_bridge_channel_has_role(swap, "holding_participant")) {
  206. const char *idle_mode = ast_bridge_channel_get_role_option(swap, "holding_participant", "idle_mode");
  207. if (!ast_strlen_zero(idle_mode) && !strcmp(idle_mode, "ringing")) {
  208. use_ringing = 1;
  209. }
  210. }
  211. ast_bridge_channel_unlock(swap);
  212. parking_set_duration(bridge_channel->features, pu);
  213. if (parking_channel_set_roles(bridge_channel->chan, self->lot, use_ringing)) {
  214. ast_log(LOG_WARNING, "Failed to apply holding bridge roles to %s while joining the parking lot.\n",
  215. ast_channel_name(bridge_channel->chan));
  216. }
  217. publish_parked_call(pu, PARKED_CALL_SWAP);
  218. return 0;
  219. }
  220. if (!(park_datastore = get_park_common_datastore_copy(bridge_channel->chan))) {
  221. /* There was either a failure to apply the datastore when performing park common setup or else we had alloc failures while cloning. Abort. */
  222. return -1;
  223. }
  224. parker = ast_channel_get_by_name(park_datastore->parker_uuid);
  225. /* If the parker and the parkee are the same channel pointer, then the channel entered using
  226. * the park application. It's possible that the channel that transferred it is still alive (particularly
  227. * when a multichannel bridge is parked), so try to get the real parker if possible. */
  228. ast_channel_lock(bridge_channel->chan);
  229. blind_transfer = pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER");
  230. blind_transfer = ast_strdupa(S_OR(blind_transfer, ""));
  231. ast_channel_unlock(bridge_channel->chan);
  232. if ((!parker || parker == bridge_channel->chan)
  233. && !ast_strlen_zero(blind_transfer)) {
  234. struct ast_channel *real_parker = ast_channel_get_by_name(blind_transfer);
  235. if (real_parker) {
  236. ao2_cleanup(parker);
  237. parker = real_parker;
  238. }
  239. }
  240. pu = generate_parked_user(self->lot, bridge_channel->chan, parker,
  241. park_datastore->parker_dial_string, park_datastore->randomize, park_datastore->time_limit);
  242. if (!pu) {
  243. publish_parked_call_failure(bridge_channel->chan);
  244. return -1;
  245. }
  246. /* If a comeback_override was provided, set it for the parked user's comeback string. */
  247. if (park_datastore->comeback_override) {
  248. ast_copy_string(pu->comeback, park_datastore->comeback_override, sizeof(pu->comeback));
  249. }
  250. /* Generate ParkedCall Stasis Message */
  251. publish_parked_call(pu, PARKED_CALL);
  252. /* If not a blind transfer and silence_announce isn't set, play the announcement to the parkee */
  253. if (ast_strlen_zero(blind_transfer) && !park_datastore->silence_announce) {
  254. char saynum_buf[16];
  255. snprintf(saynum_buf, sizeof(saynum_buf), "%d %d", 0, pu->parking_space);
  256. ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
  257. }
  258. /* Apply parking duration limits */
  259. parking_set_duration(bridge_channel->features, pu);
  260. /* Set this to the bridge pvt so that we don't have to refind the parked user associated with this bridge channel again. */
  261. bridge_channel->bridge_pvt = pu;
  262. ast_verb(3, "Parking '" COLORIZE_FMT "' in '" COLORIZE_FMT "' at space %d\n",
  263. COLORIZE(COLOR_BRMAGENTA, 0, ast_channel_name(bridge_channel->chan)),
  264. COLORIZE(COLOR_BRMAGENTA, 0, self->lot->name),
  265. pu->parking_space);
  266. parking_notify_metermaids(pu->parking_space, self->lot->cfg->parking_con, AST_DEVICE_INUSE);
  267. return 0;
  268. }
  269. /*!
  270. * \internal
  271. * \brief ast_bridge parking pull method.
  272. * \since 12.0.0
  273. *
  274. * \param self Bridge to operate upon.
  275. * \param bridge_channel Bridge channel to pull.
  276. *
  277. * \note On entry, self is already locked.
  278. *
  279. * \return Nothing
  280. */
  281. static void bridge_parking_pull(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
  282. {
  283. RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
  284. ast_bridge_base_v_table.pull(&self->base, bridge_channel);
  285. /* Take over the bridge channel's pu reference. It will be released when we are done. */
  286. pu = bridge_channel->bridge_pvt;
  287. bridge_channel->bridge_pvt = NULL;
  288. /* This should only happen if the exiting channel was swapped out */
  289. if (!pu) {
  290. return;
  291. }
  292. /* If we got here without the resolution being set, that's because the call was hung up for some reason without
  293. * timing out or being picked up. There may be some forcible park removals later, but the resolution should be
  294. * handled in those cases */
  295. ao2_lock(pu);
  296. if (pu->resolution == PARK_UNSET) {
  297. pu->resolution = PARK_ABANDON;
  298. }
  299. ao2_unlock(pu);
  300. /* Pull can still happen after the bridge starts dissolving, so make sure we still have a lot before trying to notify metermaids. */
  301. if (self->lot) {
  302. parking_notify_metermaids(pu->parking_space, self->lot->cfg->parking_con, AST_DEVICE_NOT_INUSE);
  303. }
  304. switch (pu->resolution) {
  305. case PARK_UNSET:
  306. /* This should be impossible now since the resolution is forcibly set to abandon if it was unset at this point. Resolution
  307. isn't allowed to be changed when it isn't currently PARK_UNSET. */
  308. break;
  309. case PARK_ABANDON:
  310. /* Since the call was abandoned without additional handling, we need to issue the give up event and unpark the user. */
  311. publish_parked_call(pu, PARKED_CALL_GIVEUP);
  312. unpark_parked_user(pu);
  313. break;
  314. case PARK_FORCED:
  315. /* PARK_FORCED is currently unused, but it is expected that it would be handled similar to PARK_ANSWERED.
  316. * There is currently no event related to forced parked calls either */
  317. break;
  318. case PARK_ANSWERED:
  319. /* If answered or forced, the channel should be pulled from the bridge as part of that process and unlinked from
  320. * the parking lot afterwards. We do need to apply bridge features though and play the courtesy tone if set. */
  321. publish_parked_call(pu, PARKED_CALL_UNPARKED);
  322. parked_call_retrieve_enable_features(bridge_channel->chan, pu->lot, AST_FEATURE_FLAG_BYCALLEE);
  323. if (pu->lot->cfg->parkedplay & AST_FEATURE_FLAG_BYCALLEE) {
  324. ast_bridge_channel_queue_playfile(bridge_channel, NULL, pu->lot->cfg->courtesytone, NULL);
  325. }
  326. break;
  327. case PARK_TIMEOUT:
  328. /* Timeout is similar to abandon because it simply sets the bridge state to end and doesn't
  329. * actually pull the channel. Because of that, unpark should happen in here. */
  330. publish_parked_call(pu, PARKED_CALL_TIMEOUT);
  331. parked_call_retrieve_enable_features(bridge_channel->chan, pu->lot, AST_FEATURE_FLAG_BYCALLEE);
  332. unpark_parked_user(pu);
  333. break;
  334. }
  335. }
  336. /*!
  337. * \internal
  338. * \brief ast_bridge parking notify_masquerade method.
  339. * \since 12.0.0
  340. *
  341. * \param self Bridge to operate upon.
  342. * \param bridge_channel Bridge channel that was masqueraded.
  343. *
  344. * \note On entry, self is already locked.
  345. * \note XXX Stub... and it will probably go unused.
  346. *
  347. * \return Nothing
  348. */
  349. static void bridge_parking_notify_masquerade(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
  350. {
  351. ast_bridge_base_v_table.notify_masquerade(&self->base, bridge_channel);
  352. }
  353. static void bridge_parking_get_merge_priority(struct ast_bridge_parking *self)
  354. {
  355. ast_bridge_base_v_table.get_merge_priority(&self->base);
  356. }
  357. struct ast_bridge_methods ast_bridge_parking_v_table = {
  358. .name = "parking",
  359. .destroy = (ast_bridge_destructor_fn) bridge_parking_destroy,
  360. .dissolving = (ast_bridge_dissolving_fn) bridge_parking_dissolving,
  361. .push = (ast_bridge_push_channel_fn) bridge_parking_push,
  362. .pull = (ast_bridge_pull_channel_fn) bridge_parking_pull,
  363. .notify_masquerade = (ast_bridge_notify_masquerade_fn) bridge_parking_notify_masquerade,
  364. .get_merge_priority = (ast_bridge_merge_priority_fn) bridge_parking_get_merge_priority,
  365. };
  366. static struct ast_bridge *ast_bridge_parking_init(struct ast_bridge_parking *self, struct parking_lot *bridge_lot)
  367. {
  368. if (!self) {
  369. return NULL;
  370. }
  371. /* If no lot is defined for the bridge, then we aren't allowing the bridge to be initialized. */
  372. if (!bridge_lot) {
  373. ao2_ref(self, -1);
  374. return NULL;
  375. }
  376. /* It doesn't need to be a reference since the bridge only lives as long as the parking lot lives. */
  377. self->lot = bridge_lot;
  378. return &self->base;
  379. }
  380. struct ast_bridge *bridge_parking_new(struct parking_lot *bridge_lot)
  381. {
  382. void *bridge;
  383. bridge = bridge_alloc(sizeof(struct ast_bridge_parking), &ast_bridge_parking_v_table);
  384. bridge = bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
  385. AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
  386. | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM, "Parking", bridge_lot->name, NULL);
  387. bridge = ast_bridge_parking_init(bridge, bridge_lot);
  388. bridge = bridge_register(bridge);
  389. return bridge;
  390. }