diff --git a/libs/freetdm/mod_openzap/Makefile b/libs/freetdm/mod_openzap/Makefile index 2ff7f24232..7edd420cdf 100644 --- a/libs/freetdm/mod_openzap/Makefile +++ b/libs/freetdm/mod_openzap/Makefile @@ -9,6 +9,6 @@ include $(BASE)/build/modmake.rules local_depend: $(OZA) $(OZA): - cd $(OZ_DIR) && $(MAKE) ZAP_MODS=wanpipe + cd $(OZ_DIR) && $(MAKE) ZAP_MODS="wanpipe zt" ZAP_CFLAGS="-g -ggdb" diff --git a/libs/freetdm/src/hashtable.c b/libs/freetdm/src/hashtable.c index c903d3ca67..fff5e99347 100644 --- a/libs/freetdm/src/hashtable.c +++ b/libs/freetdm/src/hashtable.c @@ -213,29 +213,19 @@ hashtable_remove(struct hashtable *h, void *k) /*****************************************************************************/ /* destroy */ void -hashtable_destroy(struct hashtable *h, int free_values) +hashtable_destroy(struct hashtable *h, int free_keys, int free_values) { unsigned int i; struct entry *e, *f; struct entry **table = h->table; - if (free_values) - { - for (i = 0; i < h->tablelength; i++) + + for (i = 0; i < h->tablelength; i++) { e = table[i]; while (NULL != e) - { f = e; e = e->next; freekey(f->k); free(f->v); free(f); } + { f = e; e = e->next; if (free_keys) freekey(f->k); if (free_values) free(f->v); free(f); } } - } - else - { - for (i = 0; i < h->tablelength; i++) - { - e = table[i]; - while (NULL != e) - { f = e; e = e->next; freekey(f->k); free(f); } - } - } + free(h->table); free(h); } diff --git a/libs/freetdm/src/include/hashtable.h b/libs/freetdm/src/include/hashtable.h index e6d23ff52f..4019a69ff9 100644 --- a/libs/freetdm/src/include/hashtable.h +++ b/libs/freetdm/src/include/hashtable.h @@ -166,7 +166,7 @@ hashtable_count(struct hashtable *h); */ void -hashtable_destroy(struct hashtable *h, int free_values); +hashtable_destroy(struct hashtable *h, int free_keys, int free_values); #endif /* __HASHTABLE_CWC22_H__ */ diff --git a/libs/freetdm/src/include/zap_types.h b/libs/freetdm/src/include/zap_types.h index d1fcb9248d..2c97f40aed 100644 --- a/libs/freetdm/src/include/zap_types.h +++ b/libs/freetdm/src/include/zap_types.h @@ -46,6 +46,7 @@ typedef int zap_socket_t; #endif typedef size_t zap_size_t; +typedef ssize_t zap_ssize_t; struct zap_io_interface; #define ZAP_COMMAND_OBJ_INT *((int *)obj) diff --git a/libs/freetdm/src/include/zap_zt.h b/libs/freetdm/src/include/zap_zt.h index bc070302d1..47b5470b7f 100644 --- a/libs/freetdm/src/include/zap_zt.h +++ b/libs/freetdm/src/include/zap_zt.h @@ -34,6 +34,8 @@ #ifndef ZAP_ZT_H #define ZAP_ZT_H #include "openzap.h" +#include +#include /* Hardware interface structures and defines */ /* Based on documentation of the structures required for the hardware interface */ @@ -69,6 +71,8 @@ struct zt_params { int pulse_after_time; }; +typedef struct zt_params zt_params_t; + /* Used with ioctl: ZT_CONFLINK, ZT_GETCONF and ZT_SETCONF */ struct zt_confinfo { int chan_no; /* Channel Number, 0 for current */ @@ -164,13 +168,13 @@ typedef enum { ZT_RINGOFF = 6 } zt_hookstate_t; -typedef enum { - ZT_MAINT_NONE = 0, /* Normal Mode */ - ZT_MAINT_LOCALLOOP = 1, /* Local Loopback */ - ZT_MAINT_REMOTELOOP = 2, /* Remote Loopback */ - ZT_MAINT_LOOPUP = 3, /* Send Loopup Code */ - ZT_MAINT_LOOPDOWN = 4, /* Send Loopdown Code */ - ZT_MAINT_LOOPSTOP = 5, /* Stop Sending Loop Codes */ +typedef enum { + ZT_MAINT_NONE = 0, /* Normal Mode */ + ZT_MAINT_LOCALLOOP = 1, /* Local Loopback */ + ZT_MAINT_REMOTELOOP = 2, /* Remote Loopback */ + ZT_MAINT_LOOPUP = 3, /* Send Loopup Code */ + ZT_MAINT_LOOPDOWN = 4, /* Send Loopdown Code */ + ZT_MAINT_LOOPSTOP = 5 /* Stop Sending Loop Codes */ } zt_maintenance_mode_t; diff --git a/libs/freetdm/src/testanalog.c b/libs/freetdm/src/testanalog.c index 82e9e8df89..c42f40fc46 100644 --- a/libs/freetdm/src/testanalog.c +++ b/libs/freetdm/src/testanalog.c @@ -71,11 +71,15 @@ int main(int argc, char *argv[]) zap_log(ZAP_LOG_DEBUG, "OpenZAP loaded\n"); - if (zap_span_find("wanpipe", 1, &span) != ZAP_SUCCESS) { + if (zap_span_find("zt", 1, &span) != ZAP_SUCCESS) { zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span\n"); + exit(-1); } - zap_analog_configure_span(span, "us", 2000, 11, on_signal); + if (zap_analog_configure_span(span, "us", 2000, 11, on_signal) != ZAP_SUCCESS) { + zap_log(ZAP_LOG_ERROR, "Error configuring OpenZAP span\n"); + exit(-1); + } zap_analog_start(span); while(zap_test_flag(span->analog_data, ZAP_ANALOG_RUNNING)) { diff --git a/libs/freetdm/src/testapp.c b/libs/freetdm/src/testapp.c index 75ddae66e5..d980a034df 100644 --- a/libs/freetdm/src/testapp.c +++ b/libs/freetdm/src/testapp.c @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) top: //if (zap_channel_open_any("wanpipe", 0, ZAP_TOP_DOWN, &chan) == ZAP_SUCCESS) { - if (zap_channel_open("wanpipe", 1, 1, &chan) == ZAP_SUCCESS) { + if (zap_channel_open("zt", 1, 1, &chan) == ZAP_SUCCESS) { int x = 0; printf("opened channel %d:%d\n", chan->span_id, chan->chan_id); @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) unsigned char buf[2048]; zap_size_t len = sizeof(buf); zap_wait_flag_t flags = ZAP_READ; - + if (zap_channel_wait(chan, &flags, -1) == ZAP_FAIL) { printf("wait FAIL! %d [%s]\n", len, chan->last_error); } diff --git a/libs/freetdm/src/zap_analog.c b/libs/freetdm/src/zap_analog.c index b6314dc339..eb5c381d7d 100644 --- a/libs/freetdm/src/zap_analog.c +++ b/libs/freetdm/src/zap_analog.c @@ -253,6 +253,7 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) } } + if (last_digit && ((elapsed - last_digit > data->digit_timeout) || strlen(dtmf) > data->max_dialstr)) { zap_log(ZAP_LOG_DEBUG, "Number obtained [%s]\n", dtmf); zap_set_state_locked(chan, ZAP_CHANNEL_STATE_IDLE); diff --git a/libs/freetdm/src/zap_io.c b/libs/freetdm/src/zap_io.c index 845cba7ef9..7890ceaaa2 100644 --- a/libs/freetdm/src/zap_io.c +++ b/libs/freetdm/src/zap_io.c @@ -229,9 +229,11 @@ zap_status_t zap_span_close_all(zap_io_interface_t *zio) 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 (zap_test_flag((&span->channels[j]), ZAP_CHANNEL_CONFIGURED)) { + 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) { @@ -1417,7 +1419,8 @@ zap_status_t zap_global_init(void) modcount = 0; zap_mutex_create(&globals.mutex); -#ifdef ZAP_WANPIPE_SUPPORT +#ifdef Z +AP_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); @@ -1483,18 +1486,20 @@ zap_status_t zap_global_destroy(void) #ifdef ZAP_ZT_SUPPORT if (interfaces.zt_interface) { - zt_destroy(); zap_span_close_all(interfaces.zt_interface); + zt_destroy(); } #endif #ifdef ZAP_WANPIPE_SUPPORT if (interfaces.wanpipe_interface) { - wanpipe_destroy(); zap_span_close_all(interfaces.wanpipe_interface); + wanpipe_destroy(); } #endif - hashtable_destroy(globals.interface_hash, 0); + zap_mutex_lock(globals.mutex); + hashtable_destroy(globals.interface_hash, 0, 0); + zap_mutex_unlock(globals.mutex); zap_mutex_destroy(&globals.mutex); return ZAP_SUCCESS; } diff --git a/libs/freetdm/src/zap_zt.c b/libs/freetdm/src/zap_zt.c index 57d006e8d3..c91c585c70 100644 --- a/libs/freetdm/src/zap_zt.c +++ b/libs/freetdm/src/zap_zt.c @@ -35,45 +35,393 @@ #include "openzap.h" #include "zap_zt.h" + +static struct { + uint32_t codec_ms; + uint32_t wink_ms; + uint32_t flash_ms; +} zt_globals; + +#define ZT_INVALID_SOCKET -1 + +static unsigned zt_open_range(zap_span_t *span, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number) +{ + unsigned configured = 0, x; + char path[128] = ""; + zt_params_t ztp = {0}; + + for(x = start; x < end; x++) { + zap_channel_t *chan; + zap_socket_t sockfd = ZT_INVALID_SOCKET; + int command; + int len = zt_globals.codec_ms * 8; + + snprintf(path, sizeof(path), "/dev/zap/%d", x); + sockfd = open(path, O_RDWR); + + if (sockfd != ZT_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) { + command = ZT_START; +#if 0 + + if (ioctl(sockfd, ZT_HOOK, &command)) { + zap_log(ZAP_LOG_INFO, "failure configuring device %s as OpenZAP device %d:%d fd:%d err:%s\n", + path, chan->span_id, chan->chan_id, sockfd, strerror(errno)); + + continue; + } +#endif + + if (ioctl(chan->sockfd, ZT_SET_BLOCKSIZE, &len)) { + zap_log(ZAP_LOG_INFO, "failure configuring device %s as OpenZAP device %d:%d fd:%d err:%s\n", + path, chan->span_id, chan->chan_id, sockfd, strerror(errno)); + close(sockfd); + continue; + } else { + chan->packet_len = len; + chan->effective_interval = chan->native_interval = chan->packet_len / 8; + + if (chan->effective_codec == ZAP_CODEC_SLIN) { + chan->packet_len *= 2; + } + } + + + if (ioctl(sockfd, ZT_GET_PARAMS, &ztp) < 0) { + close(sockfd); + zap_log(ZAP_LOG_INFO, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", path, chan->span_id, chan->chan_id, sockfd); + continue; + } + zap_log(ZAP_LOG_INFO, "configuring device %s as OpenZAP device %d:%d fd:%d\n", path, chan->span_id, chan->chan_id, sockfd); + + if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) { + if (ztp.g711_type == ZT_G711_ALAW) { + chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW; + } else { + chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW; + } + } + + if (!zap_strlen_zero(name)) { + zap_copy_string(chan->chan_name, name, sizeof(chan->chan_name)); + } + if (!zap_strlen_zero(number)) { + zap_copy_string(chan->chan_number, number, sizeof(chan->chan_number)); + } + configured++; + } else { + zap_log(ZAP_LOG_ERROR, "failure configuring device %s\n", path); + } + } + + return configured; +} + static ZIO_CONFIGURE_SPAN_FUNCTION(zt_configure_span) { - return ZAP_FAIL; + + int items, i; + char *mydata, *item_list[10]; + char *ch, *mx; + int channo; + int top = 0; + unsigned configured = 0; + + assert(str != NULL); + + + mydata = strdup(str); + assert(mydata != NULL); + + + items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0]))); + + for(i = 0; i < items; i++) { + ch = item_list[i]; + + if (!(ch)) { + zap_log(ZAP_LOG_ERROR, "Invalid input\n"); + continue; + } + + channo = atoi(ch); + + if (channo < 0) { + zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo); + continue; + } + + if ((mx = strchr(ch, '-'))) { + mx++; + top = atoi(mx) + 1; + } else { + top = channo + 1; + } + + + if (top < 0) { + zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top); + continue; + } + + configured += zt_open_range(span, channo, top, type, name, number); + + } + + free(mydata); + + return configured; + } static ZIO_CONFIGURE_FUNCTION(zt_configure) { - return ZAP_FAIL; + if (!strcasecmp(category, "defaults")) { + if (!strcasecmp(var, "codec_ms")) { + unsigned codec_ms = atoi(val); + if (codec_ms < 10 || codec_ms > 60) { + zap_log(ZAP_LOG_WARNING, "invalid codec ms at line %d\n", lineno); + } else { + zt_globals.codec_ms = codec_ms; + } + } + } + + return ZAP_SUCCESS; } static ZIO_OPEN_FUNCTION(zt_open) { ZIO_OPEN_MUZZLE; - return ZAP_FAIL; + return ZAP_SUCCESS; } static ZIO_CLOSE_FUNCTION(zt_close) { ZIO_CLOSE_MUZZLE; - return ZAP_FAIL; + return ZAP_SUCCESS; } static ZIO_COMMAND_FUNCTION(zt_command) { - return ZAP_FAIL; + zt_params_t ztp = {0}; + int err = 0; + + ZIO_COMMAND_MUZZLE; + + switch(command) { + case ZAP_COMMAND_GET_INTERVAL: + { + if (!(err = ioctl(zchan->sockfd, ZT_GET_BLOCKSIZE, &zchan->packet_len))) { + zchan->native_interval = zchan->packet_len / 8; + if (zchan->effective_codec == ZAP_CODEC_SLIN) { + zchan->packet_len *= 2; + } + ZAP_COMMAND_OBJ_INT = zchan->native_interval; + } + + } + break; + case ZAP_COMMAND_SET_INTERVAL: + { + int interval = ZAP_COMMAND_OBJ_INT; + int len = interval * 8; + + if (!(err = ioctl(zchan->sockfd, ZT_SET_BLOCKSIZE, &len))) { + zchan->packet_len = len; + zchan->effective_interval = zchan->native_interval = zchan->packet_len / 8; + + if (zchan->effective_codec == ZAP_CODEC_SLIN) { + zchan->packet_len *= 2; + } + + } + } + break; + default: + break; + }; + + if (err) { + snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno)); + return ZAP_FAIL; + } + + + return ZAP_SUCCESS; } static ZIO_WAIT_FUNCTION(zt_wait) { - return ZAP_FAIL; + int32_t inflags = 0; + int result; + struct pollfd pfds[1]; + + if (*flags & ZAP_READ) { + inflags |= POLLIN; + } + + if (*flags & ZAP_WRITE) { + inflags |= POLLOUT; + } + + if (*flags & ZAP_EVENTS) { + inflags |= POLLPRI; + } + + + memset(&pfds[0], 0, sizeof(pfds[0])); + pfds[0].fd = zchan->sockfd; + pfds[0].events = inflags; + result = poll(pfds, 1, to); + *flags = 0; + + if (pfds[0].revents & POLLERR) { + result = -1; + } + + if (result > 0) { + *flags = pfds[0].revents; + } + + + *flags = ZAP_NO_FLAGS; + + if (result < 0){ + snprintf(zchan->last_error, sizeof(zchan->last_error), "Poll failed"); + return ZAP_FAIL; + } + + if (result == 0) { + return ZAP_TIMEOUT; + } + + if (inflags & POLLIN) { + *flags |= ZAP_READ; + } + + if (inflags & POLLOUT) { + *flags |= ZAP_WRITE; + } + + if (inflags & POLLPRI) { + *flags |= ZAP_EVENTS; + } + + return ZAP_SUCCESS; + } +ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event) +{ + struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN]; + int i, j = 0, k = 0, r, e; + + for(i = 1; i <= span->chan_count; i++) { + e = ZT_IOMUX_SIGEVENT; + memset(&pfds[j], 0, sizeof(pfds[j])); + pfds[j].fd = span->channels[i].sockfd; + pfds[j].events = POLLPRI; + ioctl(span->channels[i].sockfd ,ZT_IOMUX, &e); + j++; + } + + r = poll(pfds, j, ms); + + if (r == 0) { + return ZAP_TIMEOUT; + } else if (r < 0 || (pfds[i-1].revents & POLLERR)) { + snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno)); + return ZAP_FAIL; + } + + for(i = 1; i <= span->chan_count; i++) { + if (pfds[i-1].revents & POLLPRI) { + zap_set_flag((&span->channels[i]), ZAP_CHANNEL_EVENT); + span->channels[i].last_event_time = zap_current_time_in_ms(); + k++; + } + } + + return k ? ZAP_SUCCESS : ZAP_FAIL; +} + +ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event) +{ + uint32_t i, event_id; + zap_oob_event_t zt_event_id; + + for(i = 1; i <= span->chan_count; i++) { + if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) { + zap_clear_flag((&span->channels[i]), ZAP_CHANNEL_EVENT); + if (ioctl(span->channels[i].sockfd, ZT_GETEVENT, &zt_event_id) == -1) { + snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno)); + return ZAP_FAIL; + } + + switch(zt_event_id) { + case ZT_EVENT_ONHOOK: + { + event_id = ZAP_OOB_ONHOOK; + } + break; + case ZT_EVENT_RINGOFFHOOK: + { + if (span->channels[i].type == ZAP_CHAN_TYPE_FXS) { + event_id = ZAP_OOB_OFFHOOK; + } else if (span->channels[i].type == ZAP_CHAN_TYPE_FXO) { + event_id = ZAP_OOB_RING_START; + } + } + break; + default: + { + zap_log(ZAP_LOG_WARNING, "Unhandled event %d\n", zt_event_id); + event_id = ZAP_OOB_INVALID; + } + break; + } + + event: + span->channels[i].last_event_time = 0; + span->event_header.e_type = ZAP_EVENT_OOB; + span->event_header.enum_id = event_id; + span->event_header.channel = &span->channels[i]; + *event = &span->event_header; + return ZAP_SUCCESS; + } + } + + return ZAP_FAIL; + +} + + static ZIO_READ_FUNCTION(zt_read) { + zap_ssize_t r = 0; + + *datalen = zchan->packet_len; + r = read(zchan->sockfd, data, *datalen); + + if (r >= 0) { + *datalen = r; + return ZAP_SUCCESS; + } + return ZAP_FAIL; } static ZIO_WRITE_FUNCTION(zt_write) { + zap_ssize_t w = 0; + + w = write(zchan->sockfd, data, *datalen); + + if (w >= 0) { + *datalen = w; + return ZAP_SUCCESS; + } + return ZAP_FAIL; } @@ -83,17 +431,26 @@ zap_status_t zt_init(zap_io_interface_t **zio) { assert(zio != NULL); memset(&zt_interface, 0, sizeof(zt_interface)); + memset(&zt_globals, 0, sizeof(zt_globals)); + + zt_globals.codec_ms = 20; + zt_globals.wink_ms = 150; + zt_globals.flash_ms = 750; zt_interface.name = "zt"; - zt_interface.configure = zt_configure; + zt_interface.configure = zt_configure; + zt_interface.configure_span = zt_configure_span; zt_interface.open = zt_open; zt_interface.close = zt_close; zt_interface.wait = zt_wait; zt_interface.read = zt_read; zt_interface.write = zt_write; + zt_interface.poll_event = zt_poll_event; + zt_interface.next_event = zt_next_event; + *zio = &zt_interface; - return ZAP_FAIL; + return ZAP_SUCCESS; } zap_status_t zt_destroy(void)