static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause) { struct ast_channel *chan; struct ast_format format; const char *conf_name = data; chan = ast_channel_alloc(1, AST_STATE_UP, NULL, NULL, NULL, NULL, NULL, NULL, 0, "CBRec/conf-%s-uid-%d", conf_name, (int) ast_random()); if (!chan) { return NULL; } if (ast_channel_add_bridge_role(chan, "recorder")) { ast_channel_release(chan); return NULL; } ast_format_set(&format, AST_FORMAT_SLINEAR, 0); ast_channel_tech_set(chan, conf_record_get_tech()); ast_format_cap_add_all(ast_channel_nativeformats(chan)); ast_format_copy(ast_channel_writeformat(chan), &format); ast_format_copy(ast_channel_rawwriteformat(chan), &format); ast_format_copy(ast_channel_readformat(chan), &format); ast_format_copy(ast_channel_rawreadformat(chan), &format); return chan; }
char *ast_generate_random_string(char *buf, size_t size) { int i; for (i = 0; i < size - 1; ++i) { buf[i] = 'a' + (ast_random() % 26); } buf[i] = '\0'; return buf; }
/*! * \brief Create a new OGG/Vorbis filestream and set it up for writing. * \param s File pointer that points to on-disk storage. * \param comment Comment that should be embedded in the OGG/Vorbis file. * \return A new filestream. */ static int ogg_vorbis_rewrite(struct ast_filestream *s, const char *comment) { ogg_packet header; ogg_packet header_comm; ogg_packet header_code; struct ogg_vorbis_desc *tmp = (struct ogg_vorbis_desc *) s->_private; tmp->writing = 1; tmp->writing_pcm_pos = 0; vorbis_info_init(&tmp->vi); if (vorbis_encode_init_vbr(&tmp->vi, 1, DEFAULT_SAMPLE_RATE, 0.4)) { ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n"); return -1; } vorbis_comment_init(&tmp->vc); vorbis_comment_add_tag(&tmp->vc, "ENCODER", "Asterisk PBX"); if (comment) vorbis_comment_add_tag(&tmp->vc, "COMMENT", (char *) comment); vorbis_analysis_init(&tmp->vd, &tmp->vi); vorbis_block_init(&tmp->vd, &tmp->vb); ogg_stream_init(&tmp->os, ast_random()); vorbis_analysis_headerout(&tmp->vd, &tmp->vc, &header, &header_comm, &header_code); ogg_stream_packetin(&tmp->os, &header); ogg_stream_packetin(&tmp->os, &header_comm); ogg_stream_packetin(&tmp->os, &header_code); while (!tmp->eos) { if (ogg_stream_flush(&tmp->os, &tmp->og) == 0) break; if (!fwrite(tmp->og.header, 1, tmp->og.header_len, s->f)) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } if (!fwrite(tmp->og.body, 1, tmp->og.body_len, s->f)) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } if (ogg_page_eos(&tmp->og)) tmp->eos = 1; } return 0; }
static int page_exec(struct ast_channel *chan, const char *data) { char *tech, *resource, *tmp; char confbridgeopts[128], originator[AST_CHANNEL_NAME]; struct page_options options = { { 0, }, { 0, } }; unsigned int confid = ast_random(); struct ast_app *app; int res = 0, pos = 0, i = 0; struct ast_dial **dial_list; unsigned int num_dials; int timeout = 0; char *parse; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(devices); AST_APP_ARG(options); AST_APP_ARG(timeout); );
static int random_exec(struct ast_channel *chan, void *data) { int res=0; struct localuser *u; char *s; char *prob; int probint; static int deprecated = 0; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Random requires an argument ([probability]:[[context|]extension|]priority)\n"); return -1; } LOCAL_USER_ADD(u); s = ast_strdupa(data); prob = strsep(&s,":"); if ((!prob) || (sscanf(prob, "%d", &probint) != 1)) probint = 0; if (!deprecated) { deprecated = 1; ast_log(LOG_WARNING, "Random is deprecated in Asterisk 1.4. Replace with GotoIf($[${RAND(0,99)} + %d >= 100]?%s)\n", probint, s); } if ((ast_random() % 100) + probint >= 100) { res = ast_parseable_goto(chan, s); if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Random branches to (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1); } LOCAL_USER_REMOVE(u); return res; }
static char *handle_cli_sched_bench(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ast_sched_context *con; struct timeval start; unsigned int num, i; int *sched_ids = NULL; switch (cmd) { case CLI_INIT: e->command = "sched benchmark"; e->usage = "" "Usage: sched benchmark <num>\n" ""; return NULL; case CLI_GENERATE: return NULL; } if (a->argc != e->args + 1) { return CLI_SHOWUSAGE; } if (sscanf(a->argv[e->args], "%u", &num) != 1) { return CLI_SHOWUSAGE; } if (!(con = ast_sched_context_create())) { ast_cli(a->fd, "Test failed - could not create scheduler context\n"); return CLI_FAILURE; } if (!(sched_ids = ast_malloc(sizeof(*sched_ids) * num))) { ast_cli(a->fd, "Test failed - memory allocation failure\n"); goto return_cleanup; } ast_cli(a->fd, "Testing ast_sched_add() performance - timing how long it takes " "to add %u entries at random time intervals from 0 to 60 seconds\n", num); start = ast_tvnow(); for (i = 0; i < num; i++) { int when = abs(ast_random()) % 60000; if ((sched_ids[i] = ast_sched_add(con, when, sched_cb, NULL)) == -1) { ast_cli(a->fd, "Test failed - sched_add returned -1\n"); goto return_cleanup; } } ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start)); ast_cli(a->fd, "Testing ast_sched_del() performance - timing how long it takes " "to delete %u entries with random time intervals from 0 to 60 seconds\n", num); start = ast_tvnow(); for (i = 0; i < num; i++) { if (ast_sched_del(con, sched_ids[i]) == -1) { ast_cli(a->fd, "Test failed - sched_del returned -1\n"); goto return_cleanup; } } ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start)); return_cleanup: ast_sched_context_destroy(con); if (sched_ids) { ast_free(sched_ids); } return CLI_SUCCESS; }
/*! * \internal * \since 12 * \brief Construct a parked_user struct assigned to the specified parking lot * * \param lot The parking lot we are assigning the user to * \param parkee The channel being parked * \param parker The channel performing the park operation (may be the same channel) * \param parker_dial_string Takes priority over parker for setting the parker dial string if included * \param use_random_space if true, prioritize using a random parking space instead * of ${PARKINGEXTEN} and/or automatic assignment from the parking lot * \param time_limit If using a custom timeout, this should be supplied so that the * parked_user struct can provide this information for manager events. If <0, * use the parking lot limit instead. * * \retval NULL on failure * \retval reference to the parked user * * \note ao2_cleanup this reference when you are done using it or you'll cause leaks. */ 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) { struct parked_user *new_parked_user; int preferred_space = -1; /* Initialize to use parking lot defaults */ int parking_space; const char *parkingexten; if (lot->mode == PARKINGLOT_DISABLED) { ast_log(LOG_NOTICE, "Tried to park in a parking lot that is no longer able to be parked to.\n"); return NULL; } new_parked_user = ao2_alloc(sizeof(*new_parked_user), destroy_parked_user); if (!new_parked_user) { return NULL; } if (use_random_space) { preferred_space = ast_random() % (lot->cfg->parking_stop - lot->cfg->parking_start + 1); preferred_space += lot->cfg->parking_start; } else { ast_channel_lock(chan); if ((parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"))) { parkingexten = ast_strdupa(parkingexten); } ast_channel_unlock(chan); if (!ast_strlen_zero(parkingexten)) { if (sscanf(parkingexten, "%30d", &preferred_space) != 1 || preferred_space <= 0) { ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n", parkingexten); ao2_ref(new_parked_user, -1); return NULL; } } } /* 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. */ ao2_lock(lot); parking_space = parking_lot_get_space(lot, preferred_space); if (parking_space == -1) { ast_log(LOG_NOTICE, "Failed to get parking space in lot '%s'. All full.\n", lot->name); ao2_ref(new_parked_user, -1); ao2_unlock(lot); return NULL; } lot->next_space = ((parking_space + 1) - lot->cfg->parking_start) % (lot->cfg->parking_stop - lot->cfg->parking_start + 1) + lot->cfg->parking_start; new_parked_user->chan = chan; new_parked_user->parking_space = parking_space; /* Have the parked user take a reference to the parking lot. This reference should be immutable and released at destruction */ new_parked_user->lot = lot; ao2_ref(lot, +1); new_parked_user->start = ast_tvnow(); new_parked_user->time_limit = (time_limit >= 0) ? time_limit : lot->cfg->parkingtime; if (parker_dial_string) { new_parked_user->parker_dial_string = ast_strdup(parker_dial_string); } else { if (parked_user_set_parker_dial_string(new_parked_user, parker)) { ao2_ref(new_parked_user, -1); ao2_unlock(lot); return NULL; } } if (!new_parked_user->parker_dial_string) { ao2_ref(new_parked_user, -1); ao2_unlock(lot); return NULL; } /* Insert into the parking lot's parked user list. We can unlock the lot now. */ ao2_link(lot->parked_users, new_parked_user); ao2_unlock(lot); return new_parked_user; }
static int astobj2_test_helper(int use_hash, int use_cmp, unsigned int lim, struct ast_test *test) { struct ao2_container *c1; struct ao2_container *c2; struct ao2_iterator it; struct test_obj *obj; struct test_obj tmp_obj; int bucket_size; int increment = 0; int destructor_count = 0; int num; int res = AST_TEST_PASS; /* This test needs at least 5 objects */ if (lim < 5) { lim = 5; } bucket_size = (ast_random() % ((lim / 4) + 1)) + 1; c1 = ao2_container_alloc(bucket_size, use_hash ? test_hash_cb : NULL, use_cmp ? test_cmp_cb : NULL); c2 = ao2_container_alloc(bucket_size, test_hash_cb, test_cmp_cb); if (!c1 || !c2) { ast_test_status_update(test, "ao2_container_alloc failed.\n"); res = AST_TEST_FAIL; goto cleanup; } /* Create objects and link into container */ destructor_count = lim; for (num = 1; num <= lim; num++) { if (!(obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor))) { ast_test_status_update(test, "ao2_alloc failed.\n"); res = AST_TEST_FAIL; goto cleanup; } snprintf(obj->c, sizeof(obj->c), "zombie #%d", num); obj->destructor_count = &destructor_count; obj->i = num; ao2_link(c1, obj); ao2_ref(obj, -1); if (ao2_container_count(c1) != num) { ast_test_status_update(test, "container did not link correctly\n"); res = AST_TEST_FAIL; } } ast_test_status_update(test, "Container created: random bucket size %d: number of items: %d\n", bucket_size, lim); /* Testing ao2_find with no flags */ num = 100; for (; num; num--) { int i = (ast_random() % ((lim / 2)) + 1); /* find a random object */ tmp_obj.i = i; if (!(obj = ao2_find(c1, &tmp_obj, 0))) { res = AST_TEST_FAIL; ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with no flags failed.\n", i); } else { /* a correct match will only take place when the custom cmp function is used */ if (use_cmp && obj->i != i) { ast_test_status_update(test, "object %d does not match object %d\n", obj->i, tmp_obj.i); res = AST_TEST_FAIL; } ao2_ref(obj, -1); } } /* Testing ao2_find with OBJ_POINTER */ num = 75; for (; num; num--) { int i = (ast_random() % ((lim / 2)) + 1); /* find a random object */ snprintf(tmp_obj.c, sizeof(tmp_obj.c), "zombie #%d", i); tmp_obj.i = i; if (!(obj = ao2_find(c1, &tmp_obj, OBJ_POINTER))) { res = AST_TEST_FAIL; ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_POINTER flag failed.\n", i); } else { /* a correct match will only take place when the custom cmp function is used */ if (use_cmp && obj->i != i) { ast_test_status_update(test, "object %d does not match object %d\n", obj->i, tmp_obj.i); res = AST_TEST_FAIL; } ao2_ref(obj, -1); } } /* Testing ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE. * In this test items are unlinked from c1 and placed in c2. Then * unlinked from c2 and placed back into c1. * * For this module and set of custom hash/cmp functions, an object * should only be found if the astobj2 default cmp function is used. * This test is designed to mimic the chan_iax.c call number use case. */ num = lim < 25 ? lim : 25; for (; num; num--) { if (!(obj = ao2_find(c1, NULL, OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE))) { if (!use_cmp) { ast_test_status_update(test, "ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE failed with default hash function.\n"); res = AST_TEST_FAIL; } } else { if (use_cmp) { ast_test_status_update(test, "ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE failed with custom hash function.\n"); res = AST_TEST_FAIL; } ao2_link(c2, obj); ao2_ref(obj, -1); } } it = ao2_iterator_init(c2, 0); while ((obj = ao2_iterator_next(&it))) { ao2_unlink(c2, obj); ao2_link(c1, obj); ao2_ref(obj, -1); } ao2_iterator_destroy(&it); /* Test Callback with no flags. */ increment = 0; ao2_callback(c1, 0, increment_cb, &increment); if (increment != lim) { ast_test_status_update(test, "callback with no flags failed. Increment is %d\n", increment); res = AST_TEST_FAIL; } /* Test Callback with OBJ_NODATA. This should do nothing different than with no flags here. */ increment = 0; ao2_callback(c1, OBJ_NODATA, increment_cb, &increment); if (increment != lim) { ast_test_status_update(test, "callback with OBJ_NODATA failed. Increment is %d\n", increment); res = AST_TEST_FAIL; } /* Is the container count what we expect after all the finds and unlinks?*/ if (ao2_container_count(c1) != lim) { ast_test_status_update(test, "container count does not match what is expected after ao2_find tests.\n"); res = AST_TEST_FAIL; } /* Testing iterator. Unlink a single object and break. do not add item back */ it = ao2_iterator_init(c1, 0); num = (lim / 4) + 1; while ((obj = ao2_iterator_next(&it))) { if (obj->i == num) { ao2_ref(obj, -1); ao2_unlink(c1, obj); break; } ao2_ref(obj, -1); } ao2_iterator_destroy(&it); /* Is the container count what we expect after removing a single item? */ if (ao2_container_count(c1) != (lim - 1)) { ast_test_status_update(test, "unlink during iterator failed. Number %d was not removed.\n", num); res = AST_TEST_FAIL; } /* Test unlink all with OBJ_MULTIPLE, leave a single object for the container to destroy */ ao2_callback(c1, OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA, all_but_one_cb, NULL); /* check to make sure all test_obj destructors were called except for 1 */ if (destructor_count != 1) { ast_test_status_update(test, "OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA failed. destructor count %d\n", destructor_count); res = AST_TEST_FAIL; } cleanup: /* destroy containers */ if (c1) { ao2_ref(c1, -1); } if (c2) { ao2_ref(c2, -1); } if (destructor_count > 0) { ast_test_status_update(test, "all destructors were not called, destructor count is %d\n", destructor_count); res = AST_TEST_FAIL; } else if (destructor_count < 0) { ast_test_status_update(test, "Destructor was called too many times, destructor count is %d\n", destructor_count); res = AST_TEST_FAIL; } return res; }
static int page_exec(struct ast_channel *chan, void *data) { struct ast_module_user *u; char *options, *tech, *resource, *tmp; char meetmeopts[88], originator[AST_CHANNEL_NAME]; struct ast_flags flags = { 0 }; unsigned int confid = ast_random(); struct ast_app *app; int res = 0, pos = 0, i = 0; struct ast_dial *dials[MAX_DIALS]; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "This application requires at least one argument (destination(s) to page)\n"); return -1; } u = ast_module_user_add(chan); if (!(app = pbx_findapp("MeetMe"))) { ast_log(LOG_WARNING, "There is no MeetMe application available!\n"); ast_module_user_remove(u); return -1; }; options = ast_strdupa(data); ast_copy_string(originator, chan->name, sizeof(originator)); if ((tmp = strchr(originator, '-'))) *tmp = '\0'; tmp = strsep(&options, "|"); if (options) ast_app_parse_options(page_opts, &flags, NULL, options); snprintf(meetmeopts, sizeof(meetmeopts), "MeetMe|%ud|%s%sqxdw(5)", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m"), (ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") ); /* Go through parsing/calling each device */ while ((tech = strsep(&tmp, "&"))) { struct ast_dial *dial = NULL; /* don't call the originating device */ if (!strcasecmp(tech, originator)) continue; /* If no resource is available, continue on */ if (!(resource = strchr(tech, '/'))) { ast_log(LOG_WARNING, "Incomplete destination '%s' supplied.\n", tech); continue; } *resource++ = '\0'; /* Create a dialing structure */ if (!(dial = ast_dial_create())) { ast_log(LOG_WARNING, "Failed to create dialing structure.\n"); continue; } /* Append technology and resource */ ast_dial_append(dial, tech, resource); /* Set ANSWER_EXEC as global option */ ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, meetmeopts); /* Run this dial in async mode */ ast_dial_run(dial, chan, 1); /* Put in our dialing array */ dials[pos++] = dial; } if (!ast_test_flag(&flags, PAGE_QUIET)) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); } if (!res) { snprintf(meetmeopts, sizeof(meetmeopts), "%ud|A%s%sqxd", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "t"), (ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") ); pbx_exec(chan, app, meetmeopts); } /* Go through each dial attempt cancelling, joining, and destroying */ for (i = 0; i < pos; i++) { struct ast_dial *dial = dials[i]; /* We have to wait for the async thread to exit as it's possible Meetme won't throw them out immediately */ ast_dial_join(dial); /* Hangup all channels */ ast_dial_hangup(dial); /* Destroy dialing structure */ ast_dial_destroy(dial); } ast_module_user_remove(u); return -1; }