/* * Copyright (c) 2007, Anthony Minessale II * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of the original author; nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "openzap.h" #include "zap_isdn.h" #include #ifdef ZAP_WANPIPE_SUPPORT #include "zap_wanpipe.h" #endif #ifdef ZAP_ZT_SUPPORT #include "zap_zt.h" #endif static int time_is_init = 0; static void time_init(void) { #ifdef WIN32 timeBeginPeriod(1); #endif time_is_init = 1; } static void time_end(void) { #ifdef WIN32 timeEndPeriod(1); #endif time_is_init = 0; } zap_time_t zap_current_time_in_ms(void) { #ifdef WIN32 return timeGetTime(); #else struct timeval tv; gettimeofday(&tv, NULL); return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); #endif } static struct { zap_hash_t *interface_hash; zap_mutex_t *mutex; } globals; /* enum lookup funcs */ ZAP_ENUM_NAMES(TONEMAP_NAMES, TONEMAP_STRINGS) ZAP_STR2ENUM(zap_str2zap_tonemap, zap_tonemap2str, zap_tonemap_t, TONEMAP_NAMES, ZAP_TONEMAP_INVALID) ZAP_ENUM_NAMES(OOB_NAMES, OOB_STRINGS) ZAP_STR2ENUM(zap_str2zap_oob_event, zap_oob_event2str, zap_oob_event_t, OOB_NAMES, ZAP_OOB_INVALID) ZAP_ENUM_NAMES(TRUNK_TYPE_NAMES, TRUNK_STRINGS) ZAP_STR2ENUM(zap_str2zap_trunk_type, zap_trunk_type2str, zap_trunk_type_t, TRUNK_TYPE_NAMES, ZAP_TRUNK_NONE) ZAP_ENUM_NAMES(SIGNAL_NAMES, SIGNAL_STRINGS) ZAP_STR2ENUM(zap_str2zap_signal_event, zap_signal_event2str, zap_signal_event_t, SIGNAL_NAMES, ZAP_SIGEVENT_INVALID) ZAP_ENUM_NAMES(CHANNEL_STATE_NAMES, CHANNEL_STATE_STRINGS) ZAP_STR2ENUM(zap_str2zap_channel_state, zap_channel_state2str, zap_channel_state_t, CHANNEL_STATE_NAMES, ZAP_CHANNEL_STATE_INVALID) static char *cut_path(char *in) { char *p, *ret = in; char delims[] = "/\\"; char *i; for (i = delims; *i; i++) { p = in; while ((p = strchr(p, *i)) != 0) { ret = ++p; } } return ret; } static void null_logger(char *file, const char *func, int line, int level, char *fmt, ...) { if (file && func && line && level && fmt) { return; } return; } static char *LEVEL_NAMES[] = { "EMERG", "ALERT", "CRIT", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG", NULL }; static int zap_log_level = 7; static void default_logger(char *file, const char *func, int line, int level, char *fmt, ...) { char *fp; char data[1024]; va_list ap; if (level < 0 || level > 7) { level = 7; } if (level > zap_log_level) { return; } fp = cut_path(file); va_start(ap, fmt); vsnprintf(data, sizeof(data), fmt, ap); fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data); va_end(ap); } zap_logger_t zap_log = null_logger; void zap_global_set_logger(zap_logger_t logger) { if (logger) { zap_log = logger; } else { zap_log = null_logger; } } void zap_global_set_default_logger(int level) { if (level < 0 || level > 7) { level = 7; } zap_log = default_logger; zap_log_level = level; } static int equalkeys(void *k1, void *k2) { return strcmp((char *) k1, (char *) k2) ? 0 : 1; } static uint32_t hashfromstring(void *ky) { unsigned char *str = (unsigned char *) ky; uint32_t hash = 0; int c; while ((c = *str++)) { hash = c + (hash << 6) + (hash << 16) - hash; } return hash; } zap_status_t zap_span_create(zap_io_interface_t *zio, zap_span_t **span) { zap_span_t *new_span = NULL; assert(zio != NULL); if (zio->span_index < ZAP_MAX_SPANS_INTERFACE) { new_span = &zio->spans[++zio->span_index]; memset(new_span, 0, sizeof(*new_span)); zap_set_flag(new_span, ZAP_SPAN_CONFIGURED); new_span->span_id = zio->span_index; new_span->zio = zio; zap_mutex_create(&new_span->mutex); zap_copy_string(new_span->tone_map[ZAP_TONEMAP_DIAL], "%(1000,0,350,440)", ZAP_TONEMAP_LEN); zap_copy_string(new_span->tone_map[ZAP_TONEMAP_RING], "%(2000,4000,440,480)", ZAP_TONEMAP_LEN); zap_copy_string(new_span->tone_map[ZAP_TONEMAP_BUSY], "%(500,500,480,620)", ZAP_TONEMAP_LEN); zap_copy_string(new_span->tone_map[ZAP_TONEMAP_ATTN], "%(100,100,1400,2060,2450,2600)", ZAP_TONEMAP_LEN); new_span->trunk_type = ZAP_TRUNK_NONE; *span = new_span; return ZAP_SUCCESS; } return ZAP_FAIL; } zap_status_t zap_span_close_all(zap_io_interface_t *zio) { zap_span_t *span; uint32_t i, j; for(i = 0; i < zio->span_index; i++) { span = &zio->spans[i]; for(j = 0; j < span->chan_count; j++) { zap_mutex_destroy(&span->channels[j].mutex); zap_buffer_destroy(&span->channels[j].digit_buffer); zap_buffer_destroy(&span->channels[j].dtmf_buffer); } if (span->mutex) { zap_mutex_destroy(&span->mutex); } if (span->isdn_data) { free(span->isdn_data); } if (span->analog_data) { free(span->isdn_data); } } return i ? ZAP_SUCCESS : ZAP_FAIL; } zap_status_t zap_span_load_tones(zap_span_t *span, char *mapname) { zap_config_t cfg; char *var, *val; int x = 0; if (!zap_config_open_file(&cfg, "tones.conf")) { snprintf(span->last_error, sizeof(span->last_error), "error loading tones."); return ZAP_FAIL; } while (zap_config_next_pair(&cfg, &var, &val)) { if (!strcasecmp(cfg.category, mapname) && var && val) { int index = zap_str2zap_tonemap(var); if (index > ZAP_TONEMAP_INVALID) { zap_log(ZAP_LOG_WARNING, "Unknown tone name %s\n", var); } else { zap_log(ZAP_LOG_DEBUG, "added tone [%s] = [%s]\n", var, val); zap_copy_string(span->tone_map[index], val, sizeof(span->tone_map[index])); x++; } } } if (!x) { snprintf(span->last_error, sizeof(span->last_error), "error loading tones."); return ZAP_FAIL; } return ZAP_SUCCESS; } zap_status_t zap_span_add_channel(zap_span_t *span, zap_socket_t sockfd, zap_chan_type_t type, zap_channel_t **chan) { if (span->chan_count < ZAP_MAX_CHANNELS_SPAN) { zap_channel_t *new_chan; new_chan = &span->channels[++span->chan_count]; new_chan->type = type; new_chan->sockfd = sockfd; new_chan->zio = span->zio; new_chan->span_id = span->span_id; new_chan->chan_id = span->chan_count; new_chan->span = span; zap_mutex_create(&new_chan->mutex); zap_buffer_create(&new_chan->digit_buffer, 128, 128, 0); zap_set_flag(new_chan, ZAP_CHANNEL_CONFIGURED | ZAP_CHANNEL_READY); *chan = new_chan; return ZAP_SUCCESS; } return ZAP_FAIL; } zap_status_t zap_span_find(const char *name, uint32_t id, zap_span_t **span) { zap_io_interface_t *zio; zap_span_t *fspan; zap_mutex_lock(globals.mutex); zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, (char *)name); zap_mutex_unlock(globals.mutex); if (!zio) { return ZAP_FAIL; } if (id > ZAP_MAX_SPANS_INTERFACE) { return ZAP_FAIL; } fspan = &zio->spans[id]; if (!zap_test_flag(fspan, ZAP_SPAN_CONFIGURED)) { return ZAP_FAIL; } *span = fspan; return ZAP_SUCCESS; } zap_status_t zap_span_set_event_callback(zap_span_t *span, zio_event_cb_t event_callback) { zap_mutex_lock(span->mutex); span->event_callback = event_callback; zap_mutex_unlock(span->mutex); return ZAP_SUCCESS; } zap_status_t zap_span_poll_event(zap_span_t *span, uint32_t ms) { assert(span->zio != NULL); if (span->zio->poll_event) { return span->zio->poll_event(span, ms); } return ZAP_NOTIMPL; } zap_status_t zap_span_next_event(zap_span_t *span, zap_event_t **event) { assert(span->zio != NULL); if (span->zio->next_event) { return span->zio->next_event(span, event); } return ZAP_NOTIMPL; } zap_status_t zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t event_callback) { zap_mutex_lock(zchan->mutex); zchan->event_callback = event_callback; zap_mutex_unlock(zchan->mutex); return ZAP_SUCCESS; } zap_status_t zap_channel_set_state(zap_channel_t *zchan, zap_channel_state_t state) { int ok = 1; zap_mutex_unlock(zchan->mutex); if (zchan->state == ZAP_CHANNEL_STATE_DOWN) { switch(state) { case ZAP_CHANNEL_STATE_BUSY: ok = 0; break; default: break; } } if (state == zchan->state) { ok = 0; } if (ok) { zap_set_flag(zchan, ZAP_CHANNEL_STATE_CHANGE); zchan->last_state = zchan->state; zchan->state = state; } zap_mutex_unlock(zchan->mutex); return ok ? ZAP_SUCCESS : ZAP_FAIL; } zap_status_t zap_channel_open_any(const char *name, uint32_t span_id, zap_direction_t direction, zap_channel_t **zchan) { zap_io_interface_t *zio; zap_status_t status = ZAP_FAIL; zap_channel_t *check; uint32_t i,j; zap_span_t *span; uint32_t span_max; zap_mutex_lock(globals.mutex); zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, (char *)name); zap_mutex_unlock(globals.mutex); if (!zio) { zap_log(ZAP_LOG_ERROR, "Invalid interface name!\n"); return ZAP_FAIL; } if (span_id) { span_max = span_id; } else { span_max = zio->span_index; } if (direction == ZAP_TOP_DOWN) { j = 1; } else { j = span_max; } zap_mutex_lock(globals.mutex); for(;;) { span = &zio->spans[j]; if (!zap_test_flag(span, ZAP_SPAN_CONFIGURED)) { goto next_loop; } if (direction == ZAP_TOP_DOWN) { if (j > span_max) { break; } } else { if (j == 0) { break; } } if (direction == ZAP_TOP_DOWN) { i = 1; } else { i = span->chan_count; } for(;;) { if (direction == ZAP_TOP_DOWN) { if (i > span->chan_count) { break; } } else { if (i == 0) { break; } } check = &span->channels[i]; if (zap_test_flag(check, ZAP_CHANNEL_READY) && !zap_test_flag(check, ZAP_CHANNEL_OPEN)) { status = check->zio->open(check); if (status == ZAP_SUCCESS) { zap_set_flag(check, ZAP_CHANNEL_OPEN); *zchan = check; return status; } } if (direction == ZAP_TOP_DOWN) { i++; } else { i--; } } next_loop: if (direction == ZAP_TOP_DOWN) { j++; } else { j--; } } zap_mutex_unlock(globals.mutex); return status; } static zap_status_t zap_channel_reset(zap_channel_t *zchan) { zap_clear_flag(zchan, ZAP_CHANNEL_OPEN); zchan->event_callback = NULL; zap_clear_flag(zchan, ZAP_CHANNEL_DTMF_DETECT); zap_clear_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF); if (zchan->tone_session.buffer) { teletone_destroy_session(&zchan->tone_session); memset(&zchan->tone_session, 0, sizeof(zchan->tone_session)); } if (zchan->dtmf_buffer) { zap_buffer_zero(zchan->dtmf_buffer); } if (zchan->digit_buffer) { zap_buffer_zero(zchan->digit_buffer); } zchan->dtmf_on = zchan->dtmf_off = 0; if (zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE)) { zchan->effective_codec = zchan->native_codec; zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8); zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE); } return ZAP_SUCCESS; } zap_status_t zap_channel_open_chan(zap_channel_t *zchan) { zap_status_t status = ZAP_FAIL; if ((status = zap_mutex_trylock(zchan->mutex)) != ZAP_SUCCESS) { return status; } if (zap_test_flag(zchan, ZAP_CHANNEL_READY) && ! zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) { status = zchan->span->zio->open(zchan); if (status == ZAP_SUCCESS) { zap_set_flag(zchan, ZAP_CHANNEL_OPEN); } } zap_mutex_unlock(zchan->mutex); return status; } zap_status_t zap_channel_open(const char *name, uint32_t span_id, uint32_t chan_id, zap_channel_t **zchan) { zap_io_interface_t *zio; zap_status_t status = ZAP_FAIL; zap_mutex_lock(globals.mutex); zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, (char *)name); zap_mutex_unlock(globals.mutex); if (span_id < ZAP_MAX_SPANS_INTERFACE && chan_id < ZAP_MAX_CHANNELS_SPAN && zio) { zap_channel_t *check; check = &zio->spans[span_id].channels[chan_id]; if ((status = zap_mutex_trylock(check->mutex)) != ZAP_SUCCESS) { return status; } if (zap_test_flag(check, ZAP_CHANNEL_READY) && ! zap_test_flag(check, ZAP_CHANNEL_OPEN)) { status = check->zio->open(check); if (status == ZAP_SUCCESS) { zap_set_flag(check, ZAP_CHANNEL_OPEN); *zchan = check; } } zap_mutex_unlock(check->mutex); } return status; } zap_status_t zap_channel_close(zap_channel_t **zchan) { zap_channel_t *check; zap_status_t status = ZAP_FAIL; assert(zchan != NULL); check = *zchan; assert(check != NULL); *zchan = NULL; zap_mutex_lock(check->mutex); if (zap_test_flag(check, ZAP_CHANNEL_OPEN)) { status = check->zio->close(check); if (status == ZAP_SUCCESS) { zap_channel_reset(check); *zchan = NULL; } } zap_mutex_unlock(check->mutex); return status; } static zap_status_t zchan_activate_dtmf_buffer(zap_channel_t *zchan) { if (zchan->dtmf_buffer) { return ZAP_SUCCESS; } if (zap_buffer_create(&zchan->dtmf_buffer, 1024, 3192, 0) != ZAP_SUCCESS) { zap_log(ZAP_LOG_ERROR, "Failed to allocate DTMF Buffer!\n"); snprintf(zchan->last_error, sizeof(zchan->last_error), "buffer error"); return ZAP_FAIL; } else { zap_log(ZAP_LOG_DEBUG, "Created DTMF Buffer!\n"); } if (!zchan->dtmf_on) { zchan->dtmf_on = 150; } if (!zchan->dtmf_off) { zchan->dtmf_off = 50; } memset(&zchan->tone_session, 0, sizeof(zchan->tone_session)); teletone_init_session(&zchan->tone_session, 1024, NULL, NULL); zchan->tone_session.rate = 8000; zchan->tone_session.duration = zchan->dtmf_on * (zchan->tone_session.rate / 1000); zchan->tone_session.wait = zchan->dtmf_off * (zchan->tone_session.rate / 1000); return ZAP_SUCCESS; } zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, void *obj) { zap_status_t status = ZAP_FAIL; assert(zchan != NULL); assert(zchan->zio != NULL); if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) { snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open"); return ZAP_FAIL; } zap_mutex_lock(zchan->mutex); switch(command) { case ZAP_COMMAND_SET_INTERVAL: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL)) { zchan->effective_interval = ZAP_COMMAND_OBJ_INT; if (zchan->effective_interval == zchan->native_interval) { zap_clear_flag(zchan, ZAP_CHANNEL_BUFFER); } else { zap_set_flag(zchan, ZAP_CHANNEL_BUFFER); } zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8); GOTO_STATUS(done, ZAP_SUCCESS); } } break; case ZAP_COMMAND_GET_INTERVAL: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL)) { ZAP_COMMAND_OBJ_INT = zchan->effective_interval; GOTO_STATUS(done, ZAP_SUCCESS); } } break; case ZAP_COMMAND_SET_CODEC: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) { zchan->effective_codec = ZAP_COMMAND_OBJ_INT; if (zchan->effective_codec == zchan->native_codec) { zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE); } else { zap_set_flag(zchan, ZAP_CHANNEL_TRANSCODE); } zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8); GOTO_STATUS(done, ZAP_SUCCESS); } } break; case ZAP_COMMAND_SET_NATIVE_CODEC: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) { zchan->effective_codec = zchan->native_codec; zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE); zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8); GOTO_STATUS(done, ZAP_SUCCESS); } } break; case ZAP_COMMAND_GET_CODEC: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) { ZAP_COMMAND_OBJ_INT = zchan->effective_codec; GOTO_STATUS(done, ZAP_SUCCESS); } } break; case ZAP_COMMAND_GET_NATIVE_CODEC: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) { ZAP_COMMAND_OBJ_INT = zchan->native_codec; GOTO_STATUS(done, ZAP_SUCCESS); } } break; case ZAP_COMMAND_ENABLE_TONE_DETECT: { /* if they don't have thier own, use ours */ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) { zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT; if (tt == ZAP_TONE_DTMF) { teletone_dtmf_detect_init (&zchan->dtmf_detect, 8000); zap_set_flag(zchan, ZAP_CHANNEL_DTMF_DETECT); zap_set_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF); GOTO_STATUS(done, ZAP_SUCCESS); } else { snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid command"); GOTO_STATUS(done, ZAP_FAIL); } } } break; case ZAP_COMMAND_DISABLE_TONE_DETECT: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) { zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT; if (tt == ZAP_TONE_DTMF) { teletone_dtmf_detect_init (&zchan->dtmf_detect, 8000); zap_clear_flag(zchan, ZAP_CHANNEL_DTMF_DETECT); zap_clear_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF); GOTO_STATUS(done, ZAP_SUCCESS); } else { snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid command"); GOTO_STATUS(done, ZAP_FAIL); } } } case ZAP_COMMAND_GET_DTMF_ON_PERIOD: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) { ZAP_COMMAND_OBJ_INT = zchan->dtmf_on; GOTO_STATUS(done, ZAP_SUCCESS); } } break; case ZAP_COMMAND_GET_DTMF_OFF_PERIOD: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) { ZAP_COMMAND_OBJ_INT = zchan->dtmf_on; GOTO_STATUS(done, ZAP_SUCCESS); } } break; case ZAP_COMMAND_SET_DTMF_ON_PERIOD: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) { int val = ZAP_COMMAND_OBJ_INT; if (val > 10 && val < 1000) { zchan->dtmf_on = val; GOTO_STATUS(done, ZAP_SUCCESS); } else { snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val); GOTO_STATUS(done, ZAP_FAIL); } } } break; case ZAP_COMMAND_SET_DTMF_OFF_PERIOD: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) { int val = ZAP_COMMAND_OBJ_INT; if (val > 10 && val < 1000) { zchan->dtmf_off = val; GOTO_STATUS(done, ZAP_SUCCESS); } else { snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val); GOTO_STATUS(done, ZAP_FAIL); } } } break; case ZAP_COMMAND_SEND_DTMF: { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) { char *cur; char *digits = ZAP_COMMAND_OBJ_CHAR_P; if (!zchan->dtmf_buffer) { if ((status = zchan_activate_dtmf_buffer(zchan)) != ZAP_SUCCESS) { GOTO_STATUS(done, status); } } zap_log(ZAP_LOG_DEBUG, "Adding DTMF SEQ [%s]\n", digits); for (cur = digits; *cur; cur++) { int wrote = 0; if ((wrote = teletone_mux_tones(&zchan->tone_session, &zchan->tone_session.TONES[(int)*cur]))) { zap_buffer_write(zchan->dtmf_buffer, zchan->tone_session.buffer, wrote * 2); } } zchan->skip_read_frames = 200; GOTO_STATUS(done, ZAP_SUCCESS); } } break; default: break; } if (!zchan->zio->command) { snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented"); GOTO_STATUS(done, ZAP_FAIL); } status = zchan->zio->command(zchan, command, obj); done: zap_mutex_unlock(zchan->mutex); return status; } zap_status_t zap_channel_wait(zap_channel_t *zchan, zap_wait_flag_t *flags, int32_t to) { assert(zchan != NULL); assert(zchan->zio != NULL); if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) { snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open"); return ZAP_FAIL; } if (!zchan->zio->wait) { snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented"); return ZAP_FAIL; } return zchan->zio->wait(zchan, flags, to); } /*******************************/ ZIO_CODEC_FUNCTION(zio_slin2ulaw) { int16_t sln_buf[512] = {0}, *sln = sln_buf; uint8_t *lp = data; uint32_t i; zap_size_t len = *datalen; if (max > len) { max = len; } memcpy(sln, data, max); for(i = 0; i < max; i++) { *lp++ = linear_to_ulaw(*sln++); } *datalen = max / 2; return ZAP_SUCCESS; } ZIO_CODEC_FUNCTION(zio_ulaw2slin) { int16_t *sln = data; uint8_t law[1024] = {0}, *lp = law; uint32_t i; zap_size_t len = *datalen; if (max > len) { max = len; } memcpy(law, data, max); for(i = 0; i < max; i++) { *sln++ = ulaw_to_linear(*lp++); } *datalen = max * 2; return ZAP_SUCCESS; } ZIO_CODEC_FUNCTION(zio_slin2alaw) { int16_t sln_buf[512] = {0}, *sln = sln_buf; uint8_t *lp = data; uint32_t i; zap_size_t len = *datalen; if (max > len) { max = len; } memcpy(sln, data, max); for(i = 0; i < max; i++) { *lp++ = linear_to_alaw(*sln++); } *datalen = max / 2; return ZAP_SUCCESS; } ZIO_CODEC_FUNCTION(zio_alaw2slin) { int16_t *sln = data; uint8_t law[1024] = {0}, *lp = law; uint32_t i; zap_size_t len = *datalen; if (max > len) { max = len; } memcpy(law, data, max); for(i = 0; i < max; i++) { *sln++ = alaw_to_linear(*lp++); } *datalen = max * 2; return ZAP_SUCCESS; } ZIO_CODEC_FUNCTION(zio_ulaw2alaw) { zap_size_t len = *datalen; uint32_t i; uint8_t *lp = data; if (max > len) { max = len; } for(i = 0; i < max; i++) { *lp = ulaw_to_alaw(*lp); lp++; } return ZAP_SUCCESS; } ZIO_CODEC_FUNCTION(zio_alaw2ulaw) { zap_size_t len = *datalen; uint32_t i; uint8_t *lp = data; if (max > len) { max = len; } for(i = 0; i < max; i++) { *lp = alaw_to_ulaw(*lp); lp++; } return ZAP_SUCCESS; } /******************************/ zap_size_t zap_channel_dequeue_dtmf(zap_channel_t *zchan, char *dtmf, zap_size_t len) { zap_size_t bytes = 0; assert(zchan != NULL); if (zap_buffer_inuse(zchan->digit_buffer)) { zap_mutex_lock(zchan->mutex); if ((bytes = zap_buffer_read(zchan->digit_buffer, dtmf, len)) > 0) { *(dtmf + bytes) = '\0'; } zap_mutex_unlock(zchan->mutex); } return bytes; } zap_status_t zap_channel_queue_dtmf(zap_channel_t *zchan, const char *dtmf) { zap_status_t status; register zap_size_t len, inuse; zap_size_t wr = 0; const char *p; assert(zchan != NULL); zap_mutex_lock(zchan->mutex); inuse = zap_buffer_inuse(zchan->digit_buffer); len = strlen(dtmf); if (len + inuse > zap_buffer_len(zchan->digit_buffer)) { zap_buffer_toss(zchan->digit_buffer, strlen(dtmf)); } p = dtmf; while (wr < len && p) { if (zap_is_dtmf(*p)) { wr++; } else { break; } p++; } status = zap_buffer_write(zchan->digit_buffer, dtmf, wr) ? ZAP_SUCCESS : ZAP_FAIL; zap_mutex_unlock(zchan->mutex); return status; } zap_status_t zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *datalen) { zap_status_t status = ZAP_FAIL; zio_codec_t codec_func = NULL; zap_size_t max = *datalen; assert(zchan != NULL); assert(zchan->zio != NULL); assert(zchan->zio != NULL); if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) { snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open"); return ZAP_FAIL; } if (!zchan->zio->read) { snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented"); return ZAP_FAIL; } status = zchan->zio->read(zchan, data, datalen); if (status == ZAP_SUCCESS && zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE) && zchan->effective_codec != zchan->native_codec) { if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_SLIN) { codec_func = zio_ulaw2slin; } else if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_ALAW) { codec_func = zio_ulaw2alaw; } else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_SLIN) { codec_func = zio_alaw2slin; } else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_ULAW) { codec_func = zio_alaw2ulaw; } if (codec_func) { status = codec_func(data, max, datalen); } else { snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!"); status = ZAP_FAIL; } } if (zap_test_flag(zchan, ZAP_CHANNEL_DTMF_DETECT)) { uint8_t sln_buf[1024] = {0}; int16_t *sln; zap_size_t slen = 0; char digit_str[80] = ""; if (zchan->effective_codec == ZAP_CODEC_SLIN) { sln = data; slen = *datalen / 2; } else { zap_size_t len = *datalen; uint32_t i; uint8_t *lp = data; slen = sizeof(sln_buf) / 2; if (len > slen) { len = slen; } sln = (int16_t *) sln_buf; for(i = 0; i < len; i++) { if (zchan->effective_codec == ZAP_CODEC_ULAW) { *sln++ = ulaw_to_linear(*lp++); } else if (zchan->effective_codec == ZAP_CODEC_ALAW) { *sln++ = alaw_to_linear(*lp++); } else { snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!"); return ZAP_FAIL; } } sln = (int16_t *) sln_buf; slen = len; } teletone_dtmf_detect(&zchan->dtmf_detect, sln, (int)slen); teletone_dtmf_get(&zchan->dtmf_detect, digit_str, sizeof(digit_str)); if(*digit_str) { zio_event_cb_t event_callback = NULL; zap_channel_queue_dtmf(zchan, digit_str); if (zchan->span->event_callback) { event_callback = zchan->span->event_callback; } else if (zchan->event_callback) { event_callback = zchan->event_callback; } if (event_callback) { zchan->event_header.channel = zchan; zchan->event_header.e_type = ZAP_EVENT_DTMF; zchan->event_header.data = digit_str; event_callback(zchan, &zchan->event_header); zchan->event_header.e_type = ZAP_EVENT_NONE; zchan->event_header.data = NULL; } if (zap_test_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF)) { zchan->skip_read_frames = 20; } if (zchan->skip_read_frames > 0) { memset(data, 0, *datalen); zchan->skip_read_frames--; } } } return status; } zap_status_t zap_channel_write(zap_channel_t *zchan, void *data, zap_size_t *datalen) { zap_status_t status = ZAP_FAIL; zio_codec_t codec_func = NULL; zap_size_t dtmf_blen, max = *datalen; assert(zchan != NULL); assert(zchan->zio != NULL); if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) { snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open"); return ZAP_FAIL; } if (!zchan->zio->write) { snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented"); return ZAP_FAIL; } if (zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE) && zchan->effective_codec != zchan->native_codec) { if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_SLIN) { codec_func = zio_slin2ulaw; } else if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_ALAW) { codec_func = zio_alaw2ulaw; } else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_SLIN) { codec_func = zio_slin2alaw; } else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_ULAW) { codec_func = zio_ulaw2alaw; } if (codec_func) { status = codec_func(data, max, datalen); } else { snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!"); status = ZAP_FAIL; } } if (zchan->dtmf_buffer && (dtmf_blen = zap_buffer_inuse(zchan->dtmf_buffer))) { zap_size_t dlen = *datalen; uint8_t auxbuf[1024]; zap_size_t len, br; if (zchan->native_codec != ZAP_CODEC_SLIN) { dlen *= 2; } len = dtmf_blen > dlen ? dlen : dtmf_blen; br = zap_buffer_read(zchan->dtmf_buffer, auxbuf, len); if (br < dlen) { memset(auxbuf + br, 0, dlen - br); } memcpy(data, auxbuf, dlen); if (zchan->native_codec != ZAP_CODEC_SLIN) { if (zchan->native_codec == ZAP_CODEC_ULAW) { *datalen = dlen; zio_slin2ulaw(data, max, datalen); } else if (zchan->native_codec == ZAP_CODEC_ALAW) { *datalen = dlen; zio_slin2alaw(data, max, datalen); } } } status = zchan->zio->write(zchan, data, datalen); return status; } static struct { zap_io_interface_t *wanpipe_interface; zap_io_interface_t *zt_interface; } interfaces; static uint32_t load_config(zap_io_interface_t *zio) { char cfg_name[256]; zap_config_t cfg; char *var, *val; int catno = -1; zap_span_t *span = NULL; int new_span = 0; unsigned configured = 0, d = 0; char name[80] = ""; char number[25] = ""; assert(zio != NULL); snprintf(cfg_name, sizeof(cfg_name), "%s.conf", zio->name); zap_log(ZAP_LOG_DEBUG, "configuring %s\n", zio->name); if (!zap_config_open_file(&cfg, cfg_name)) { return ZAP_FAIL; } while (zap_config_next_pair(&cfg, &var, &val)) { if (!strcasecmp(cfg.category, "span")) { if (cfg.catno != catno) { zap_log(ZAP_LOG_DEBUG, "found config for span\n"); catno = cfg.catno; new_span = 1; span = NULL; } if (new_span) { if (!strcasecmp(var, "enabled") && ! zap_true(val)) { zap_log(ZAP_LOG_DEBUG, "span (disabled)\n"); } else { if (zap_span_create(zio, &span) == ZAP_SUCCESS) { zap_log(ZAP_LOG_DEBUG, "created span %d\n", span->span_id); } else { zap_log(ZAP_LOG_CRIT, "failure creating span\n"); span = NULL; } } new_span = 0; continue; } if (!span) { continue; } zap_log(ZAP_LOG_DEBUG, "span %d [%s]=[%s]\n", span->span_id, var, val); if (!strcasecmp(var, "enabled")) { zap_log(ZAP_LOG_WARNING, "'enabled' command ignored when it's not the first command in a [span]\n"); } else if (!strcasecmp(var, "trunk_type")) { span->trunk_type = zap_str2zap_trunk_type(val); zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s'\n", zap_trunk_type2str(span->trunk_type)); } else if (!strcasecmp(var, "name")) { if (!strcasecmp(val, "undef")) { *name = '\0'; } else { zap_copy_string(name, val, sizeof(name)); } } else if (!strcasecmp(var, "number")) { if (!strcasecmp(val, "undef")) { *number = '\0'; } else { zap_copy_string(number, val, sizeof(number)); } } else if (!strcasecmp(var, "fxo-channel")) { if (span->trunk_type == ZAP_TRUNK_NONE) { span->trunk_type = ZAP_TRUNK_FXO; zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s'\n", zap_trunk_type2str(span->trunk_type)); } if (span->trunk_type == ZAP_TRUNK_FXO) { configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_FXO, name, number); } else { zap_log(ZAP_LOG_WARNING, "Cannot add FXO channels to an FXS trunk!\n"); } } else if (!strcasecmp(var, "fxs-channel")) { if (span->trunk_type == ZAP_TRUNK_NONE) { span->trunk_type = ZAP_TRUNK_FXS; zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s'\n", zap_trunk_type2str(span->trunk_type)); } if (span->trunk_type == ZAP_TRUNK_FXS) { configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_FXS, name, number); } else { zap_log(ZAP_LOG_WARNING, "Cannot add FXS channels to an FXO trunk!\n"); } } else if (!strcasecmp(var, "b-channel")) { configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_B, name, number); } else if (!strcasecmp(var, "d-channel")) { if (d) { zap_log(ZAP_LOG_WARNING, "ignoring extra d-channel\n"); } else { zap_chan_type_t qtype; if (!strncasecmp(val, "lapd:", 5)) { qtype = ZAP_CHAN_TYPE_DQ931; val += 5; } else { qtype = ZAP_CHAN_TYPE_DQ921; } configured += zio->configure_span(span, val, qtype, name, number); d++; } } } else if (zio->configure) { zio->configure(cfg.category, var, val, cfg.lineno); } else { zap_log(ZAP_LOG_ERROR, "unknown param [%s] '%s' / '%s'\n", cfg.category, var, val); } } zap_config_close_file(&cfg); zap_log(ZAP_LOG_INFO, "wanpipe configured %u channel(s)\n", configured); return configured; } zap_status_t zap_global_init(void) { zap_config_t cfg; char *var, *val; uint32_t configured = 0; int modcount; time_init(); zap_isdn_init(); memset(&interfaces, 0, sizeof(interfaces)); globals.interface_hash = create_hashtable(16, hashfromstring, equalkeys); modcount = 0; zap_mutex_create(&globals.mutex); #ifdef ZAP_WANPIPE_SUPPORT if (wanpipe_init(&interfaces.wanpipe_interface) == ZAP_SUCCESS) { zap_mutex_lock(globals.mutex); hashtable_insert(globals.interface_hash, (void *)interfaces.wanpipe_interface->name, interfaces.wanpipe_interface); zap_mutex_unlock(globals.mutex); modcount++; } else { zap_log(ZAP_LOG_ERROR, "Error initilizing wanpipe.\n"); } #endif #ifdef ZAP_ZT_SUPPORT if (zt_init(&interfaces.zt_interface) == ZAP_SUCCESS) { zap_mutex_lock(globals.mutex); hashtable_insert(globals.interface_hash, (void *)interfaces.zt_interface->name, interfaces.zt_interface); zap_mutex_unlock(globals.mutex); modcount++; } else { zap_log(ZAP_LOG_ERROR, "Error initilizing zt.\n"); } #endif if (!modcount) { zap_log(ZAP_LOG_ERROR, "Error initilizing anything.\n"); return ZAP_FAIL; } if (!zap_config_open_file(&cfg, "openzap.conf")) { zap_log(ZAP_LOG_ERROR, "Cannot open openzap.conf!\n"); return ZAP_FAIL; } while (zap_config_next_pair(&cfg, &var, &val)) { if (!strcasecmp(cfg.category, "openzap")) { if (!strcmp(var, "load")) { zap_io_interface_t *zio; zap_mutex_lock(globals.mutex); zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, val); zap_mutex_unlock(globals.mutex); if (zio) { configured += load_config(zio); } else { zap_log(ZAP_LOG_WARNING, "Attempted to load Non-Existant module '%s'\n", val); } } } } zap_config_close_file(&cfg); if (configured) { return ZAP_SUCCESS; } zap_log(ZAP_LOG_ERROR, "No modules configured!\n"); return ZAP_FAIL; } zap_status_t zap_global_destroy(void) { time_end(); #ifdef ZAP_ZT_SUPPORT if (interfaces.zt_interface) { zt_destroy(); zap_span_close_all(interfaces.zt_interface); } #endif #ifdef ZAP_WANPIPE_SUPPORT if (interfaces.wanpipe_interface) { wanpipe_destroy(); zap_span_close_all(interfaces.wanpipe_interface); } #endif hashtable_destroy(globals.interface_hash, 0); zap_mutex_destroy(&globals.mutex); return ZAP_SUCCESS; } uint32_t zap_separate_string(char *buf, char delim, char **array, int arraylen) { int argc; char *ptr; int quot = 0; char qc = '"'; char *e; int x; if (!buf || !array || !arraylen) { return 0; } memset(array, 0, arraylen * sizeof(*array)); ptr = buf; for (argc = 0; *ptr && (argc < arraylen - 1); argc++) { array[argc] = ptr; for (; *ptr; ptr++) { if (*ptr == qc) { if (quot) { quot--; } else { quot++; } } else if ((*ptr == delim) && !quot) { *ptr++ = '\0'; break; } } } if (*ptr) { array[argc++] = ptr; } /* strip quotes */ for (x = 0; x < argc; x++) { if (*(array[x]) == qc) { (array[x])++; if ((e = strchr(array[x], qc))) { *e = '\0'; } } } return argc; } void print_bits(uint8_t *b, int bl, char *buf, int blen, int e) { int i,j = 0, k, l = 0; if (blen < (bl * 10) + 2) { return; } for (k = 0 ; k < bl; k++) { buf[j++] = '['; if (e) { for(i = 7; i >= 0; i--) { buf[j++] = ((b[k] & (1 << i)) ? '1' : '0'); } } else { for(i = 0; i < 8; i++) { buf[j++] = ((b[k] & (1 << i)) ? '1' : '0'); } } buf[j++] = ']'; buf[j++] = ' '; if (++l == 6) { buf[j++] = '\n'; l = 0; } } buf[j++] = '\0'; }