static int opus_decoder_construct(struct ast_trans_pvt *pvt, int sampling_rate) { struct opus_coder_pvt *opvt = pvt->pvt; int error = 0; if (!valid_sampling_rate(sampling_rate)) { return -1; } opvt->sampling_rate = sampling_rate; opvt->multiplier = 48000/sampling_rate; opvt->fec = USE_FEC; /* FIXME: should be triggered by chan_sip */ opvt->opus = opus_decoder_create(sampling_rate, 1, &error); if (error != OPUS_OK) { ast_log(LOG_ERROR, "Error creating the Opus decoder: %s\n", opus_strerror(error)); return -1; } opvt->id = ast_atomic_fetchadd_int(&usage.decoder_id, 1) + 1; ast_atomic_fetchadd_int(&usage.decoders, +1); ast_debug(3, "Created decoder #%d (opus -> %d)\n", opvt->id, sampling_rate); return 0; }
int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var) { struct astobj2 *obj = INTERNAL_OBJ(user_data); struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; int res = 0; if (obj == NULL) { ast_assert(0); return -1; } switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) { case AO2_ALLOC_OPT_LOCK_MUTEX: obj_mutex = INTERNAL_OBJ_MUTEX(user_data); res = __ast_pthread_mutex_trylock(file, line, func, var, &obj_mutex->mutex.lock); #ifdef AO2_DEBUG if (!res) { ast_atomic_fetchadd_int(&ao2.total_locked, 1); } #endif break; case AO2_ALLOC_OPT_LOCK_RWLOCK: obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data); switch (lock_how) { case AO2_LOCK_REQ_MUTEX: case AO2_LOCK_REQ_WRLOCK: res = __ast_rwlock_trywrlock(file, line, func, &obj_rwlock->rwlock.lock, var); if (!res) { ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1); #ifdef AO2_DEBUG ast_atomic_fetchadd_int(&ao2.total_locked, 1); #endif } break; case AO2_LOCK_REQ_RDLOCK: res = __ast_rwlock_tryrdlock(file, line, func, &obj_rwlock->rwlock.lock, var); if (!res) { ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1); #ifdef AO2_DEBUG ast_atomic_fetchadd_int(&ao2.total_locked, 1); #endif } break; } break; case AO2_ALLOC_OPT_LOCK_NOLOCK: /* The ao2 object has no lock. */ return 0; default: ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n", user_data); return -1; } return res; }
static void *http_root(void *data) { int fd; struct sockaddr_in sin; socklen_t sinlen; struct ast_http_server_instance *ser; pthread_t launched; pthread_attr_t attr; for (;;) { int flags; ast_wait_for_input(httpfd, -1); sinlen = sizeof(sin); fd = accept(httpfd, (struct sockaddr *)&sin, &sinlen); if (fd < 0) { if ((errno != EAGAIN) && (errno != EINTR)) ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno)); continue; } if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) { close(fd); continue; } ser = ast_calloc(1, sizeof(*ser)); if (!ser) { ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno)); close(fd); ast_atomic_fetchadd_int(&session_count, -1); continue; } flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); ser->fd = fd; memcpy(&ser->requestor, &sin, sizeof(ser->requestor)); if ((ser->f = fdopen(ser->fd, "w+"))) { pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (ast_pthread_create_background(&launched, &attr, ast_httpd_helper_thread, ser)) { ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno)); fclose(ser->f); free(ser); ast_atomic_fetchadd_int(&session_count, -1); } pthread_attr_destroy(&attr); } else { ast_log(LOG_WARNING, "fdopen failed!\n"); close(ser->fd); free(ser); ast_atomic_fetchadd_int(&session_count, -1); } } return NULL; }
int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var) { struct astobj2 *obj = INTERNAL_OBJ(user_data); struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; int res = 0; int current_value; if (obj == NULL) { ast_assert(0); return -1; } switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) { case AO2_ALLOC_OPT_LOCK_MUTEX: obj_mutex = INTERNAL_OBJ_MUTEX(user_data); res = __ast_pthread_mutex_unlock(file, line, func, var, &obj_mutex->mutex.lock); #ifdef AO2_DEBUG if (!res) { ast_atomic_fetchadd_int(&ao2.total_locked, -1); } #endif break; case AO2_ALLOC_OPT_LOCK_RWLOCK: obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data); current_value = ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1) - 1; if (current_value < 0) { /* It was a WRLOCK that we are unlocking. Fix the count. */ ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -current_value); } res = __ast_rwlock_unlock(file, line, func, &obj_rwlock->rwlock.lock, var); #ifdef AO2_DEBUG if (!res) { ast_atomic_fetchadd_int(&ao2.total_locked, -1); } #endif break; case AO2_ALLOC_OPT_LOCK_NOLOCK: /* The ao2 object has no lock. */ break; default: ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n", user_data); res = -1; break; } return res; }
struct stasis_cp_all *stasis_cp_all_create(const char *name, snapshot_get_id id_fn) { char *cached_name = NULL; struct stasis_cp_all *all; static int cache_id; all = ao2_t_alloc(sizeof(*all), all_dtor, name); if (!all) { return NULL; } ast_asprintf(&cached_name, "cache_pattern:%d/%s", ast_atomic_fetchadd_int(&cache_id, +1), name); if (!cached_name) { ao2_ref(all, -1); return NULL; } all->topic = stasis_topic_create(name); all->topic_cached = stasis_topic_create(cached_name); ast_free(cached_name); all->cache = stasis_cache_create(id_fn); all->forward_all_to_cached = stasis_forward_all(all->topic, all->topic_cached); if (!all->topic || !all->topic_cached || !all->cache || !all->forward_all_to_cached) { ao2_ref(all, -1); return NULL; } return all; }
/* Helper methods */ static int opus_encoder_construct(struct ast_trans_pvt *pvt, int sampling_rate) { struct opus_coder_pvt *opvt = pvt->pvt; int error = 0; if (!valid_sampling_rate(sampling_rate)) { return -1; } opvt->sampling_rate = sampling_rate; opvt->multiplier = 48000/sampling_rate; opvt->fec = USE_FEC; opvt->opus = opus_encoder_create(sampling_rate, 1, OPUS_APPLICATION_VOIP, &error); if (error != OPUS_OK) { ast_log(LOG_ERROR, "Error creating the Opus encoder: %s\n", opus_strerror(error)); return -1; } if (sampling_rate == 8000) { opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); } else if (sampling_rate == 12000) { opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); } else if (sampling_rate == 16000) { opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); } else if (sampling_rate == 24000) { opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); } else if (sampling_rate == 48000) { opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); } opus_encoder_ctl(opvt->opus, OPUS_SET_INBAND_FEC(opvt->fec)); opvt->framesize = sampling_rate/50; opvt->id = ast_atomic_fetchadd_int(&usage.encoder_id, 1) + 1; ast_atomic_fetchadd_int(&usage.encoders, +1); ast_debug(3, "Created encoder #%d (%d -> opus)\n", opvt->id, sampling_rate); return 0; }
/*! /brief Create test element */ static char *ht_new(int i) { const int buflen = 12; char *keybuf = ao2_alloc(buflen, ht_delete); int needed; if (keybuf == NULL) { return NULL; } needed = snprintf(keybuf, buflen, "key%08x", i); ast_atomic_fetchadd_int(&alloc_count, 1); ast_assert(needed + 1 <= buflen); return keybuf; }
struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const char *linkedid, const char *file, int line, const char *function) { struct ast_channel *tmp; #if defined(REF_DEBUG) tmp = __ao2_alloc_debug(sizeof(*tmp), destructor, AO2_ALLOC_OPT_LOCK_MUTEX, "", file, line, function, 1); #elif defined(__AST_DEBUG_MALLOC) tmp = __ao2_alloc_debug(sizeof(*tmp), destructor, AO2_ALLOC_OPT_LOCK_MUTEX, "", file, line, function, 0); #else tmp = ao2_alloc(sizeof(*tmp), destructor); #endif if ((ast_string_field_init(tmp, 128))) { return ast_channel_unref(tmp); } if (!(tmp->dialed_causes = ao2_container_alloc(DIALED_CAUSES_BUCKETS, pvt_cause_hash_fn, pvt_cause_cmp_fn))) { return ast_channel_unref(tmp); } if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) { ast_channel_uniqueid_build(tmp, "%li.%d", (long)time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1)); } else { ast_channel_uniqueid_build(tmp, "%s-%li.%d", ast_config_AST_SYSTEM_NAME, (long)time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1)); } if (!ast_strlen_zero(linkedid)) { ast_string_field_set(tmp, linkedid, linkedid); } else { ast_string_field_set(tmp, linkedid, tmp->uniqueid); } return tmp; }
/*! * \brief Allocate and initialize a new worker thread * * This will create, initialize, and start the thread. * * \param pool The threadpool to which the worker will be added * \retval NULL Failed to allocate or start the worker thread * \retval non-NULL The newly-created worker thread */ static struct worker_thread *worker_thread_alloc(struct ast_threadpool *pool) { struct worker_thread *worker = ao2_alloc(sizeof(*worker), worker_thread_destroy); if (!worker) { return NULL; } worker->id = ast_atomic_fetchadd_int(&worker_id_counter, 1); ast_mutex_init(&worker->lock); ast_cond_init(&worker->cond, NULL); worker->pool = pool; worker->thread = AST_PTHREADT_NULL; worker->state = ALIVE; worker->options = pool->options; return worker; }
static void opustolin_destroy(struct ast_trans_pvt *arg) { struct opus_coder_pvt *opvt = arg->pvt; if (!opvt || !opvt->opus) { return; } opus_decoder_destroy(opvt->opus); opvt->opus = NULL; ast_atomic_fetchadd_int(&usage.decoders, -1); ast_debug(3, "Destroyed decoder #%d (opus->%d)\n", opvt->id, opvt->sampling_rate); }
struct ast_sip_sched_task *ast_sip_schedule_task(struct ast_taskprocessor *serializer, int interval, ast_sip_task sip_task, char *name, void *task_data, enum ast_sip_scheduler_task_flags flags) { #define ID_LEN 13 /* task_deadbeef */ struct ast_sip_sched_task *schtd; int res; if (interval < 0) { return NULL; } schtd = ao2_alloc((sizeof(*schtd) + (!ast_strlen_zero(name) ? strlen(name) : ID_LEN) + 1), schtd_destructor); if (!schtd) { return NULL; } schtd->task_id = ast_atomic_fetchadd_int(&task_count, 1); schtd->serializer = serializer; schtd->task = sip_task; if (!ast_strlen_zero(name)) { strcpy(schtd->name, name); /* Safe */ } else { sprintf(schtd->name, "task_%08x", schtd->task_id); } schtd->task_data = task_data; schtd->flags = flags; schtd->interval = interval; schtd->when_queued = ast_tvnow(); if (flags & AST_SIP_SCHED_TASK_DATA_AO2) { ao2_ref(task_data, +1); } res = ast_sched_add(scheduler_context, interval, push_to_serializer, (const void *)schtd); if (res < 0) { ao2_ref(schtd, -1); return NULL; } else { schtd->current_scheduler_id = res; ao2_link(tasks, schtd); } return schtd; #undef ID_LEN }
/*! /brief Grow the hash data as specified */ static void *hash_test_grow(void *d) { struct hash_test *data = d; int i; for (i = 0; i < data->max_grow; ++i) { char *obj; if (is_timed_out(data)) { return "Growth timed out"; } obj = ht_new(i); if (obj == NULL) { return "Allocation failed"; } ast_hashtab_insert_immediate(data->to_be_thrashed, obj); ast_atomic_fetchadd_int(&data->grow_count, 1); } return NULL; }
/*! \brief ast_smdi_interface destructor. */ void ast_smdi_interface_destroy(struct ast_smdi_interface *iface) { if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) { pthread_cancel(iface->thread); pthread_join(iface->thread, NULL); } iface->thread = AST_PTHREADT_STOP; if(iface->file) fclose(iface->file); ASTOBJ_CONTAINER_DESTROYALL(&iface->md_q, ast_smdi_md_message_destroy); ASTOBJ_CONTAINER_DESTROYALL(&iface->mwi_q, ast_smdi_mwi_message_destroy); ASTOBJ_CONTAINER_DESTROY(&iface->md_q); ASTOBJ_CONTAINER_DESTROY(&iface->mwi_q); free(iface); ast_atomic_fetchadd_int(&me->usecnt, -1); }
/*! /brief Grow the hash data as specified */ static void *hash_test_grow(void *d) { struct hash_test *data = d; int i; for (i = 0; i < data->max_grow; ++i) { char *ht; if (is_timed_out(data)) { printf("Growth timed out at %d\n", i); return "Growth timed out"; } ht = ht_new(i); if (ht == NULL) { return "Allocation failed"; } ao2_link(data->to_be_thrashed, ht); ao2_ref(ht, -1); ast_atomic_fetchadd_int(&data->grow_count, 1); } return NULL; }
/*! Randomly lookup data in the hash */ static void *hash_test_lookup(void *d) { struct hash_test *data = d; int max; unsigned seed = time(NULL); /* ast_atomic_fetchadd_int provide a memory fence so that the optimizer doesn't * optimize away reads. */ while ((max = ast_atomic_fetchadd_int(&data->grow_count, 0)) < data->max_grow) { int i; char *obj; char *from_ao2; if (is_timed_out(data)) { return "Lookup timed out"; } if (max == 0) { /* No data yet; yield and try again */ sched_yield(); continue; } /* Randomly lookup one object from the hash */ i = rand_r(&seed) % max; obj = ht_new(i); if (obj == NULL) { return "Allocation failed"; } from_ao2 = ao2_find(data->to_be_thrashed, obj, OBJ_POINTER); ao2_ref(obj, -1); ao2_ref(from_ao2, -1); if (from_ao2 == NULL) { return "Key unexpectedly missing"; } } return NULL; }
static int internal_ao2_ref(void *user_data, int delta, const char *file, int line, const char *func) { struct astobj2 *obj = INTERNAL_OBJ(user_data); struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; int current_value; int ret; if (obj == NULL) { ast_assert(0); return -1; } /* if delta is 0, just return the refcount */ if (delta == 0) { return obj->priv_data.ref_counter; } /* we modify with an atomic operation the reference counter */ ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta); current_value = ret + delta; #ifdef AO2_DEBUG ast_atomic_fetchadd_int(&ao2.total_refs, delta); #endif if (0 < current_value) { /* The object still lives. */ return ret; } /* this case must never happen */ if (current_value < 0) { ast_log(__LOG_ERROR, file, line, func, "Invalid refcount %d on ao2 object %p\n", current_value, user_data); ast_assert(0); /* stop here even if assert doesn't DO_CRASH */ return -1; } /* last reference, destroy the object */ if (obj->priv_data.destructor_fn != NULL) { obj->priv_data.destructor_fn(user_data); } #ifdef AO2_DEBUG ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size); ast_atomic_fetchadd_int(&ao2.total_objects, -1); #endif /* In case someone uses an object after it's been freed */ obj->priv_data.magic = 0; switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) { case AO2_ALLOC_OPT_LOCK_MUTEX: obj_mutex = INTERNAL_OBJ_MUTEX(user_data); ast_mutex_destroy(&obj_mutex->mutex.lock); ast_free(obj_mutex); break; case AO2_ALLOC_OPT_LOCK_RWLOCK: obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data); ast_rwlock_destroy(&obj_rwlock->rwlock.lock); ast_free(obj_rwlock); break; case AO2_ALLOC_OPT_LOCK_NOLOCK: ast_free(obj); break; default: ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n", user_data); break; } return ret; }
static void *ast_httpd_helper_thread(void *data) { char buf[4096]; char cookie[4096]; char timebuf[256]; struct ast_http_server_instance *ser = data; struct ast_variable *vars = NULL; char *uri, *c, *title=NULL; int status = 200, contentlength = 0; time_t t; unsigned int static_content = 0; if (fgets(buf, sizeof(buf), ser->f)) { /* Skip method */ uri = buf; while(*uri && (*uri > 32)) uri++; if (*uri) { *uri = '\0'; uri++; } /* Skip white space */ while (*uri && (*uri < 33)) uri++; if (*uri) { c = uri; while (*c && (*c > 32)) c++; if (*c) { *c = '\0'; } } while (fgets(cookie, sizeof(cookie), ser->f)) { /* Trim trailing characters */ while(!ast_strlen_zero(cookie) && (cookie[strlen(cookie) - 1] < 33)) { cookie[strlen(cookie) - 1] = '\0'; } if (ast_strlen_zero(cookie)) break; if (!strncasecmp(cookie, "Cookie: ", 8)) { vars = parse_cookies(cookie); } } if (*uri) { if (!strcasecmp(buf, "get")) c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars, &static_content); else c = ast_http_error(501, "Not Implemented", NULL, "Attempt to use unimplemented / unsupported method");\ } else c = ast_http_error(400, "Bad Request", NULL, "Invalid Request"); /* If they aren't mopped up already, clean up the cookies */ if (vars) ast_variables_destroy(vars); if (!c) c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error"); if (c) { time(&t); strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t)); ast_cli(ser->fd, "HTTP/1.1 %d %s\r\n", status, title ? title : "OK"); ast_cli(ser->fd, "Server: Asterisk/%s\r\n", ASTERISK_VERSION); ast_cli(ser->fd, "Date: %s\r\n", timebuf); ast_cli(ser->fd, "Connection: close\r\n"); if (!static_content) ast_cli(ser->fd, "Cache-Control: no-cache, no-store\r\n"); /* We set the no-cache headers only for dynamic content. * If you want to make sure the static file you requested is not from cache, * append a random variable to your GET request. Ex: 'something.html?r=109987734' */ if (contentlength) { char *tmp; tmp = strstr(c, "\r\n\r\n"); if (tmp) { ast_cli(ser->fd, "Content-length: %d\r\n", contentlength); if (write(ser->fd, c, (tmp + 4 - c)) < 0) { ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); } if (write(ser->fd, tmp + 4, contentlength) < 0) { ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); } } } else ast_cli(ser->fd, "%s", c); free(c); } if (title) free(title); } fclose(ser->f); free(ser); ast_atomic_fetchadd_int(&session_count, -1); return NULL; }
static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *file, int line, const char *func) { /* allocation */ struct astobj2 *obj; struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; switch (options & AO2_ALLOC_OPT_LOCK_MASK) { case AO2_ALLOC_OPT_LOCK_MUTEX: #if defined(__AST_DEBUG_MALLOC) obj_mutex = __ast_calloc(1, sizeof(*obj_mutex) + data_size, file, line, func); #else obj_mutex = ast_calloc(1, sizeof(*obj_mutex) + data_size); #endif if (obj_mutex == NULL) { return NULL; } ast_mutex_init(&obj_mutex->mutex.lock); obj = (struct astobj2 *) &obj_mutex->priv_data; break; case AO2_ALLOC_OPT_LOCK_RWLOCK: #if defined(__AST_DEBUG_MALLOC) obj_rwlock = __ast_calloc(1, sizeof(*obj_rwlock) + data_size, file, line, func); #else obj_rwlock = ast_calloc(1, sizeof(*obj_rwlock) + data_size); #endif if (obj_rwlock == NULL) { return NULL; } ast_rwlock_init(&obj_rwlock->rwlock.lock); obj = (struct astobj2 *) &obj_rwlock->priv_data; break; case AO2_ALLOC_OPT_LOCK_NOLOCK: #if defined(__AST_DEBUG_MALLOC) obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, func); #else obj = ast_calloc(1, sizeof(*obj) + data_size); #endif if (obj == NULL) { return NULL; } break; default: /* Invalid option value. */ ast_log(__LOG_DEBUG, file, line, func, "Invalid lock option requested\n"); return NULL; } /* Initialize common ao2 values. */ obj->priv_data.ref_counter = 1; obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */ obj->priv_data.data_size = data_size; obj->priv_data.options = options; obj->priv_data.magic = AO2_MAGIC; #ifdef AO2_DEBUG ast_atomic_fetchadd_int(&ao2.total_objects, 1); ast_atomic_fetchadd_int(&ao2.total_mem, data_size); ast_atomic_fetchadd_int(&ao2.total_refs, 1); #endif /* return a pointer to the user data */ return EXTERNAL_OBJ(obj); }
static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, int volfactor, const int fd, const char *mygroup, const char *spec, const char *exten, const char *context) { char nameprefix[AST_NAME_STRLEN]; char peer_name[AST_NAME_STRLEN + 5]; signed char zero_volume = 0; int waitms; int res; char *ptr; int num; int num_spyed_upon = 1; struct chanspy_ds chanspy_ds = { 0, }; ast_mutex_init(&chanspy_ds.lock); snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1)); if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ waitms = 100; for (;;) { struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; struct ast_channel *prev = NULL, *peer = NULL; if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); else if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } } res = ast_waitfordigit(chan, waitms); if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } /* reset for the next loop around, unless overridden later */ waitms = 100; num_spyed_upon = 0; for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds); peer_chanspy_ds; chanspy_ds_free(peer_chanspy_ds), prev = peer, peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { const char *group; int igrp = !mygroup; char *groups[25]; int num_groups = 0; char dup_group[512]; int x; char *s; peer = peer_chanspy_ds->chan; ast_mutex_unlock(&peer_chanspy_ds->lock); if (peer == prev) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_check_hangup(chan)) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { ast_channel_unlock(peer); continue; } if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { ast_channel_unlock(peer); continue; } if (mygroup) { if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { ast_copy_string(dup_group, group, sizeof(dup_group)); num_groups = ast_app_separate_args(dup_group, ':', groups, sizeof(groups) / sizeof(groups[0])); } for (x = 0; x < num_groups; x++) { if (!strcmp(mygroup, groups[x])) { igrp = 1; break; } } } if (!igrp) { ast_channel_unlock(peer); continue; } strcpy(peer_name, "spy-"); strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); ptr = strchr(peer_name, '/'); *ptr++ = '\0'; for (s = peer_name; s < ptr; s++) *s = tolower(*s); /* We have to unlock the peer channel here to avoid a deadlock. * So, when we need to dereference it again, we have to lock the * datastore and get the pointer from there to see if the channel * is still valid. */ ast_channel_unlock(peer); if (!ast_test_flag(flags, OPTION_QUIET)) { if (ast_fileexists(peer_name, NULL, NULL) != -1) { res = ast_streamfile(chan, peer_name, chan->language); if (!res) res = ast_waitstream(chan, ""); if (res) { chanspy_ds_free(peer_chanspy_ds); break; } } else res = ast_say_character_str(chan, peer_name, "", chan->language); if ((num = atoi(ptr))) ast_say_digits(chan, atoi(ptr), "", chan->language); } res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags); num_spyed_upon++; if (res == -1) { chanspy_ds_free(peer_chanspy_ds); break; } else if (res > 1 && spec) { struct ast_channel *next; snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); } else { /* stay on this channel, if it is still valid */ ast_mutex_lock(&peer_chanspy_ds->lock); if (peer_chanspy_ds->chan) { ast_channel_lock(peer_chanspy_ds->chan); next_chanspy_ds = peer_chanspy_ds; peer_chanspy_ds = NULL; } else { /* the channel is gone */ ast_mutex_unlock(&peer_chanspy_ds->lock); next_chanspy_ds = NULL; } } peer = NULL; } } if (res == -1 || ast_check_hangup(chan)) break; } ast_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); ast_mutex_lock(&chanspy_ds.lock); ast_mutex_unlock(&chanspy_ds.lock); ast_mutex_destroy(&chanspy_ds.lock); return res; }
/*! /brief Free test element */ static void ht_delete(void *obj) { ast_atomic_fetchadd_int(&alloc_count, -1); }
/*! * \internal * \brief Load and reload SMDI configuration. * \param reload this should be 1 if we are reloading and 0 if not. * * This function loads/reloads the SMDI configuration and starts and stops * interfaces accordingly. * * \return zero on success, -1 on failure, and 1 if no smdi interfaces were started. */ static int smdi_load(int reload) { struct ast_config *conf; struct ast_variable *v; struct ast_smdi_interface *iface = NULL; int res = 0; /* Config options */ speed_t baud_rate = B9600; /* 9600 baud rate */ tcflag_t paritybit = PARENB; /* even parity checking */ tcflag_t charsize = CS7; /* seven bit characters */ int stopbits = 0; /* One stop bit */ int msdstrip = 0; /* strip zero digits */ long msg_expiry = SMDI_MSG_EXPIRY_TIME; conf = ast_config_load(config_file); if (!conf) { if (reload) ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file); else ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file); return 1; } /* Mark all interfaces that we are listening on. We will unmark them * as we find them in the config file, this way we know any interfaces * still marked after we have finished parsing the config file should * be stopped. */ if (reload) ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces); for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) { if (!strcasecmp(v->name, "baudrate")) { if (!strcasecmp(v->value, "9600")) baud_rate = B9600; else if(!strcasecmp(v->value, "4800")) baud_rate = B4800; else if(!strcasecmp(v->value, "2400")) baud_rate = B2400; else if(!strcasecmp(v->value, "1200")) baud_rate = B1200; else { ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno); baud_rate = B9600; } } else if (!strcasecmp(v->name, "msdstrip")) { if (!sscanf(v->value, "%d", &msdstrip)) { ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno); msdstrip = 0; } else if (0 > msdstrip || msdstrip > 9) { ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno); msdstrip = 0; } } else if (!strcasecmp(v->name, "msgexpirytime")) { if (!sscanf(v->value, "%ld", &msg_expiry)) { ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno); msg_expiry = SMDI_MSG_EXPIRY_TIME; } } else if (!strcasecmp(v->name, "paritybit")) { if (!strcasecmp(v->value, "even")) paritybit = PARENB; else if (!strcasecmp(v->value, "odd")) paritybit = PARENB | PARODD; else if (!strcasecmp(v->value, "none")) paritybit = ~PARENB; else { ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno); paritybit = PARENB; } } else if (!strcasecmp(v->name, "charsize")) { if (!strcasecmp(v->value, "7")) charsize = CS7; else if (!strcasecmp(v->value, "8")) charsize = CS8; else { ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno); charsize = CS7; } } else if (!strcasecmp(v->name, "twostopbits")) { stopbits = ast_true(v->name); } else if (!strcasecmp(v->name, "smdiport")) { if (reload) { /* we are reloading, check if we are already * monitoring this interface, if we are we do * not want to start it again. This also has * the side effect of not updating different * setting for the serial port, but it should * be trivial to rewrite this section so that * options on the port are changed without * restarting the interface. Or the interface * could be restarted with out emptying the * queue. */ if ((iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) { ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name); ASTOBJ_UNMARK(iface); ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); continue; } } if (!(iface = ast_calloc(1, sizeof(*iface)))) continue; ASTOBJ_INIT(iface); ASTOBJ_CONTAINER_INIT(&iface->md_q); ASTOBJ_CONTAINER_INIT(&iface->mwi_q); ast_copy_string(iface->name, v->value, sizeof(iface->name)); if (!(iface->file = fopen(iface->name, "r"))) { ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno)); ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); continue; } iface->fd = fileno(iface->file); /* Set the proper attributes for our serial port. */ /* get the current attributes from the port */ if (tcgetattr(iface->fd, &iface->mode)) { ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno)); ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); continue; } /* set the desired speed */ if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) { ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno)); ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); continue; } /* set the stop bits */ if (stopbits) iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB; /* set two stop bits */ else iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB; /* set one stop bit */ /* set the parity */ iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit; /* set the character size */ iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize; /* commit the desired attributes */ if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) { ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno)); ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); continue; } /* set the msdstrip */ iface->msdstrip = msdstrip; /* set the message expiry time */ iface->msg_expiry = msg_expiry; /* start the listner thread */ if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Starting SMDI monitor thread for %s\n", iface->name); if (ast_pthread_create(&iface->thread, NULL, smdi_read, iface)) { ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name); ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); continue; } ASTOBJ_CONTAINER_LINK(&smdi_ifaces, iface); ASTOBJ_UNREF(iface, ast_smdi_interface_destroy); ast_atomic_fetchadd_int(&me->usecnt, +1); } else { ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file); } } ast_config_destroy(conf); /* Prune any interfaces we should no longer monitor. */ if (reload) ASTOBJ_CONTAINER_PRUNE_MARKED(&smdi_ifaces, ast_smdi_interface_destroy); ASTOBJ_CONTAINER_RDLOCK(&smdi_ifaces); /* TODO: this is bad, we need an ASTOBJ method for this! */ if (!smdi_ifaces.head) res = 1; ASTOBJ_CONTAINER_UNLOCK(&smdi_ifaces); return res; }
/*! \brief Convert a file from one format to another */ static int cli_audio_convert(int fd, int argc, char *argv[]) { int ret = RESULT_FAILURE; struct ast_filestream *fs_in = NULL, *fs_out = NULL; struct ast_frame *f; struct timeval start; int cost; char *file_in = NULL, *file_out = NULL; char *name_in, *ext_in, *name_out, *ext_out; ast_atomic_fetchadd_int(&me->usecnt, +1); if (argc != 3 || ast_strlen_zero(argv[1]) || ast_strlen_zero(argv[2])) { ret = RESULT_SHOWUSAGE; goto fail_out; } file_in = ast_strdupa(argv[1]); file_out = ast_strdupa(argv[2]); if (split_ext(file_in, &name_in, &ext_in)) { ast_cli(fd, "'%s' is an invalid filename!\n", argv[1]); goto fail_out; } if (!(fs_in = ast_readfile(name_in, ext_in, NULL, O_RDONLY, 0, 0))) { ast_cli(fd, "Unable to open input file: %s\n", argv[1]); goto fail_out; } if (split_ext(file_out, &name_out, &ext_out)) { ast_cli(fd, "'%s' is an invalid filename!\n", argv[2]); goto fail_out; } if (!(fs_out = ast_writefile(name_out, ext_out, NULL, O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) { ast_cli(fd, "Unable to open output file: %s\n", argv[2]); goto fail_out; } start = ast_tvnow(); while ((f = ast_readframe(fs_in))) { if (ast_writestream(fs_out, f)) { ast_cli(fd, "Failed to convert %s.%s to %s.%s!\n", name_in, ext_in, name_out, ext_out); goto fail_out; } } cost = ast_tvdiff_ms(ast_tvnow(), start); ast_cli(fd, "Converted %s.%s to %s.%s in %dms\n", name_in, ext_in, name_out, ext_out, cost); ret = RESULT_SUCCESS; fail_out: if (fs_out) { ast_closestream(fs_out); if (ret != RESULT_SUCCESS) ast_filedelete(name_out, ext_out); } if (fs_in) ast_closestream(fs_in); ast_atomic_fetchadd_int(&me->usecnt, -1); return ret; }
struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan, enum stasis_app_snoop_direction spy, enum stasis_app_snoop_direction whisper, const char *app, const char *app_args, const char *snoop_id) { RAII_VAR(struct stasis_app_snoop *, snoop, NULL, ao2_cleanup); struct ast_format_cap *caps; pthread_t thread; struct ast_assigned_ids assignedids = { .uniqueid = snoop_id, }; if (spy == STASIS_SNOOP_DIRECTION_NONE && whisper == STASIS_SNOOP_DIRECTION_NONE) { return NULL; } snoop = ao2_alloc_options(sizeof(*snoop), snoop_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!snoop) { return NULL; } /* Allocate a buffer to store the Stasis application and arguments in */ snoop->app = ast_str_create(64); if (!snoop->app) { return NULL; } ast_str_set(&snoop->app, 0, "%s", app); if (!ast_strlen_zero(app_args)) { ast_str_append(&snoop->app, 0, ",%s", app_args); } /* Set up a timer for the Snoop channel so it wakes up at a specific interval */ snoop->timer = ast_timer_open(); if (!snoop->timer) { return NULL; } ast_timer_set_rate(snoop->timer, 1000 / SNOOP_INTERVAL); /* Determine which signed linear format should be used */ snoop_determine_format(chan, snoop); /* Allocate a Snoop channel and set up various parameters */ snoop->chan = ast_channel_alloc(1, AST_STATE_UP, "", "", "", "", "", &assignedids, NULL, 0, "Snoop/%s-%08x", ast_channel_uniqueid(chan), (unsigned)ast_atomic_fetchadd_int((int *)&chan_idx, +1)); if (!snoop->chan) { return NULL; } ast_copy_string(snoop->uniqueid, ast_channel_uniqueid(chan), sizeof(snoop->uniqueid)); /* To keep the channel valid on the Snoop structure until it is destroyed we bump the ref up here */ ast_channel_ref(snoop->chan); ast_channel_tech_set(snoop->chan, &snoop_tech); ao2_ref(snoop, +1); ast_channel_tech_pvt_set(snoop->chan, snoop); ast_channel_set_fd(snoop->chan, 0, ast_timer_fd(snoop->timer)); /* The format on the Snoop channel will be this signed linear format, and it will never change */ caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!caps) { ast_channel_unlock(snoop->chan); ast_hangup(snoop->chan); return NULL; } ast_format_cap_append(caps, snoop->spy_format, 0); ast_channel_nativeformats_set(snoop->chan, caps); ao2_ref(caps, -1); ast_channel_set_writeformat(snoop->chan, snoop->spy_format); ast_channel_set_rawwriteformat(snoop->chan, snoop->spy_format); ast_channel_set_readformat(snoop->chan, snoop->spy_format); ast_channel_set_rawreadformat(snoop->chan, snoop->spy_format); ast_channel_unlock(snoop->chan); if (spy != STASIS_SNOOP_DIRECTION_NONE) { if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_SPY, spy, &snoop->spy_direction, &snoop->spy)) { ast_hangup(snoop->chan); return NULL; } snoop->spy_samples = ast_format_get_sample_rate(snoop->spy_format) / (1000 / SNOOP_INTERVAL); snoop->spy_active = 1; } /* If whispering is enabled set up the audiohook */ if (whisper != STASIS_SNOOP_DIRECTION_NONE) { if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_WHISPER, whisper, &snoop->whisper_direction, &snoop->whisper)) { ast_hangup(snoop->chan); return NULL; } snoop->whisper_active = 1; } /* Create the thread which services the Snoop channel */ ao2_ref(snoop, +1); if (ast_pthread_create_detached_background(&thread, NULL, snoop_stasis_thread, snoop)) { ao2_cleanup(snoop); /* No other thread is servicing this channel so we can immediately hang it up */ ast_hangup(snoop->chan); return NULL; } publish_chanspy_message(snoop, 1); /* The caller of this has a reference as well */ return ast_channel_ref(snoop->chan); }
static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, int volfactor, const int fd, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context) { char nameprefix[AST_NAME_STRLEN]; char peer_name[AST_NAME_STRLEN + 5]; char exitcontext[AST_MAX_CONTEXT] = ""; signed char zero_volume = 0; int waitms; int res; char *ptr; int num; int num_spyed_upon = 1; struct chanspy_ds chanspy_ds; if (ast_test_flag(flags, OPTION_EXIT)) { const char *c; if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) ast_copy_string(exitcontext, c, sizeof(exitcontext)); else if (!ast_strlen_zero(chan->macrocontext)) ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); else ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); } ast_mutex_init(&chanspy_ds.lock); snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1)); if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ waitms = 100; for (;;) { struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; struct ast_channel *prev = NULL, *peer = NULL; if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); else if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } } res = ast_waitfordigit(chan, waitms); if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } /* reset for the next loop around, unless overridden later */ waitms = 100; num_spyed_upon = 0; for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds); peer_chanspy_ds; chanspy_ds_free(peer_chanspy_ds), prev = peer, peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { const char *group; int igrp = !mygroup; char *groups[25]; int num_groups = 0; char dup_group[512]; int x; char *s; char *buffer; char *end; char *ext; char *form_enforced; int ienf = !myenforced; peer = peer_chanspy_ds->chan; ast_mutex_unlock(&peer_chanspy_ds->lock); if (peer == prev) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_check_hangup(chan)) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { ast_channel_unlock(peer); continue; } if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { ast_channel_unlock(peer); continue; } if (mygroup) { if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { ast_copy_string(dup_group, group, sizeof(dup_group)); num_groups = ast_app_separate_args(dup_group, ':', groups, ARRAY_LEN(groups)); } for (x = 0; x < num_groups; x++) { if (!strcmp(mygroup, groups[x])) { igrp = 1; break; } } } if (!igrp) { ast_channel_unlock(peer); continue; } if (myenforced) { /* We don't need to allocate more space than just the length of (peer->name) for ext as we will cut the channel name's ending before copying into ext */ ext = alloca(strlen(peer->name)); form_enforced = alloca(strlen(myenforced) + 3); strcpy(form_enforced, ":"); strcat(form_enforced, myenforced); strcat(form_enforced, ":"); buffer = ast_strdupa(peer->name); if ((end = strchr(buffer, '-'))) { *end++ = ':'; *end = '\0'; } strcpy(ext, ":"); strcat(ext, buffer); if (strcasestr(form_enforced, ext)) ienf = 1; } if (!ienf) continue; strcpy(peer_name, "spy-"); strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); ptr = strchr(peer_name, '/'); *ptr++ = '\0'; for (s = peer_name; s < ptr; s++) *s = tolower(*s); /* We have to unlock the peer channel here to avoid a deadlock. * So, when we need to dereference it again, we have to lock the * datastore and get the pointer from there to see if the channel * is still valid. */ ast_channel_unlock(peer); if (!ast_test_flag(flags, OPTION_QUIET)) { if (ast_fileexists(peer_name, NULL, NULL) != -1) { res = ast_streamfile(chan, peer_name, chan->language); if (!res) res = ast_waitstream(chan, ""); if (res) { chanspy_ds_free(peer_chanspy_ds); break; } } else res = ast_say_character_str(chan, peer_name, "", chan->language); if ((num = atoi(ptr))) ast_say_digits(chan, atoi(ptr), "", chan->language); } res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext); num_spyed_upon++; if (res == -1) { chanspy_ds_free(peer_chanspy_ds); goto exit; } else if (res == -2) { res = 0; chanspy_ds_free(peer_chanspy_ds); goto exit; } else if (res > 1 && spec) { struct ast_channel *next; snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); } else { /* stay on this channel, if it is still valid */ ast_mutex_lock(&peer_chanspy_ds->lock); if (peer_chanspy_ds->chan) { ast_channel_lock(peer_chanspy_ds->chan); next_chanspy_ds = peer_chanspy_ds; peer_chanspy_ds = NULL; } else { /* the channel is gone */ ast_mutex_unlock(&peer_chanspy_ds->lock); next_chanspy_ds = NULL; } } peer = NULL; } } if (res == -1 || ast_check_hangup(chan)) break; } exit: ast_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); ast_mutex_lock(&chanspy_ds.lock); ast_mutex_unlock(&chanspy_ds.lock); ast_mutex_destroy(&chanspy_ds.lock); return res; }
struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap) { struct ast_unreal_pvt *unreal; static const struct ast_jb_conf jb_conf = { .flags = 0, .max_size = -1, .resync_threshold = -1, .impl = "", .target_extra = -1, }; unreal = ao2_alloc(size, destructor); if (!unreal) { return NULL; } unreal->reqcap = ast_format_cap_dup(cap); if (!unreal->reqcap) { ao2_ref(unreal, -1); return NULL; } memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf)); return unreal; } struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p, const struct ast_channel_tech *tech, int semi1_state, int semi2_state, const char *exten, const char *context, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, struct ast_callid *callid) { struct ast_channel *owner; struct ast_channel *chan; struct ast_format fmt; struct ast_assigned_ids id1 = {NULL, NULL}; struct ast_assigned_ids id2 = {NULL, NULL}; int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1); /* set unique ids for the two channels */ if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) { id1.uniqueid = assignedids->uniqueid; id2.uniqueid = assignedids->uniqueid2; } /* if id1 given but not id2, use default of id1;2 */ if (id1.uniqueid && ast_strlen_zero(id2.uniqueid)) { char *uniqueid2; uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 2); strcpy(uniqueid2, id1.uniqueid);/* Safe */ strcat(uniqueid2, ";2");/* Safe */ id2.uniqueid = uniqueid2; } /* * Allocate two new Asterisk channels * * Make sure that the ;2 channel gets the same linkedid as ;1. * You can't pass linkedid to both allocations since if linkedid * isn't set, then each channel will generate its own linkedid. */ if (!(owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL, exten, context, &id1, requestor, 0, "%s/%s-%08x;1", tech->type, p->name, generated_seqno))) { ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n"); return NULL; } if (callid) { ast_channel_callid_set(owner, callid); } ast_channel_tech_set(owner, tech); ao2_ref(p, +1); ast_channel_tech_pvt_set(owner, p); ast_format_cap_copy(ast_channel_nativeformats(owner), p->reqcap); /* Determine our read/write format and set it on each channel */ ast_best_codec(p->reqcap, &fmt); ast_format_copy(ast_channel_writeformat(owner), &fmt); ast_format_copy(ast_channel_rawwriteformat(owner), &fmt); ast_format_copy(ast_channel_readformat(owner), &fmt); ast_format_copy(ast_channel_rawreadformat(owner), &fmt); ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE); ast_jb_configure(owner, &p->jb_conf); if (ast_channel_cc_params_init(owner, requestor ? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) { ao2_ref(p, -1); ast_channel_unlock(owner); ast_channel_release(owner); return NULL; } p->owner = owner; ast_channel_unlock(owner); if (!(chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL, exten, context, &id2, owner, 0, "%s/%s-%08x;2", tech->type, p->name, generated_seqno))) { ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n"); ao2_ref(p, -1); ast_channel_release(owner); return NULL; } if (callid) { ast_channel_callid_set(chan, callid); } ast_channel_tech_set(chan, tech); ao2_ref(p, +1); ast_channel_tech_pvt_set(chan, p); ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap); /* Format was already determined when setting up owner */ ast_format_copy(ast_channel_writeformat(chan), &fmt); ast_format_copy(ast_channel_rawwriteformat(chan), &fmt); ast_format_copy(ast_channel_readformat(chan), &fmt); ast_format_copy(ast_channel_rawreadformat(chan), &fmt); ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE); p->chan = chan; ast_channel_unlock(chan); return owner; }