2007-05-16 20:36:40 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2007-05-17 04:16:52 +00:00
|
|
|
#define WANPIPE_TDM_API 1
|
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
#include "openzap.h"
|
|
|
|
#include "zap_wanpipe.h"
|
2007-05-17 04:16:52 +00:00
|
|
|
|
2007-05-20 00:11:11 +00:00
|
|
|
#include <sangoma_tdm_api.h>
|
2007-05-18 05:33:19 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
2007-05-17 20:28:38 +00:00
|
|
|
#include <sys/socket.h>
|
2007-05-18 05:33:19 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2007-05-19 00:50:50 +00:00
|
|
|
static struct {
|
|
|
|
unsigned codec_ms;
|
|
|
|
} wp_globals;
|
2007-05-17 03:31:21 +00:00
|
|
|
|
2007-05-17 16:57:26 +00:00
|
|
|
static zap_software_interface_t wanpipe_interface;
|
|
|
|
|
2007-05-19 00:50:50 +00:00
|
|
|
static zap_status_t wp_tdm_cmd_exec(zap_channel_t *zchan, wanpipe_tdm_api_t *tdm_api)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = tdmv_api_ioctl(zchan->sockfd, &tdm_api->wp_tdm_cmd);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2007-05-17 20:28:38 +00:00
|
|
|
static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start, unsigned end, zap_chan_type_t type)
|
|
|
|
{
|
|
|
|
unsigned configured = 0, x;
|
|
|
|
|
|
|
|
for(x = start; x < end; x++) {
|
|
|
|
zap_channel_t *chan;
|
2007-05-18 05:33:19 +00:00
|
|
|
zap_socket_t sockfd = WP_INVALID_SOCKET;
|
2007-05-17 20:28:38 +00:00
|
|
|
|
2007-05-20 00:11:11 +00:00
|
|
|
sockfd = tdmv_api_open_span_chan(spanno, x);
|
2007-05-17 20:28:38 +00:00
|
|
|
|
2007-05-18 05:33:19 +00:00
|
|
|
if (sockfd != WP_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
|
2007-05-17 20:28:38 +00:00
|
|
|
zap_log(ZAP_LOG_INFO, "configuring device s%dc%d as OpenZAP device %d:%d fd:%d\n", spanno, x, chan->span_id, chan->chan_id, sockfd);
|
|
|
|
configured++;
|
2007-05-19 00:50:50 +00:00
|
|
|
|
2007-05-17 20:28:38 +00:00
|
|
|
} else {
|
|
|
|
zap_log(ZAP_LOG_ERROR, "failure configuring device s%dc%d\n", spanno, x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return configured;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned wp_configure_channel(zap_config_t *cfg, const char *str, zap_span_t *span, zap_chan_type_t type)
|
|
|
|
{
|
|
|
|
int items, i;
|
|
|
|
char *mydata, *item_list[10];
|
|
|
|
char *sp, *ch, *mx;
|
|
|
|
int channo;
|
|
|
|
int spanno;
|
|
|
|
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++) {
|
|
|
|
sp = item_list[i];
|
|
|
|
if ((ch = strchr(sp, ':'))) {
|
|
|
|
*ch++ = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(sp && ch)) {
|
|
|
|
zap_log(ZAP_LOG_ERROR, "Invalid input on line %d\n", cfg->lineno);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
channo = atoi(ch);
|
|
|
|
spanno = atoi(sp);
|
|
|
|
|
|
|
|
|
|
|
|
if (channo < 0) {
|
|
|
|
zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spanno < 0) {
|
|
|
|
zap_log(ZAP_LOG_ERROR, "Invalid span 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 += wp_open_range(span, spanno, channo, top, type);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
free(mydata);
|
|
|
|
|
|
|
|
return configured;
|
|
|
|
}
|
|
|
|
|
2007-05-16 21:59:11 +00:00
|
|
|
static ZINT_CONFIGURE_FUNCTION(wanpipe_configure)
|
|
|
|
{
|
2007-05-17 03:31:21 +00:00
|
|
|
zap_config_t cfg;
|
|
|
|
char *var, *val;
|
|
|
|
int catno = -1;
|
2007-05-17 16:57:26 +00:00
|
|
|
zap_span_t *span = NULL;
|
2007-05-17 20:28:38 +00:00
|
|
|
int new_span = 0;
|
|
|
|
unsigned configured = 0, d = 0;
|
2007-05-17 03:31:21 +00:00
|
|
|
|
2007-05-16 21:59:11 +00:00
|
|
|
ZINT_CONFIGURE_MUZZLE;
|
2007-05-17 03:31:21 +00:00
|
|
|
|
2007-05-17 16:57:26 +00:00
|
|
|
zap_log(ZAP_LOG_DEBUG, "configuring wanpipe\n");
|
2007-05-17 03:31:21 +00:00
|
|
|
if (!zap_config_open_file(&cfg, "wanpipe.conf")) {
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
2007-05-17 16:57:26 +00:00
|
|
|
|
2007-05-17 03:31:21 +00:00
|
|
|
while (zap_config_next_pair(&cfg, &var, &val)) {
|
2007-05-19 00:50:50 +00:00
|
|
|
if (!strcasecmp(cfg.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", cfg.lineno);
|
|
|
|
} else {
|
|
|
|
wp_globals.codec_ms = codec_ms;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (!strcasecmp(cfg.category, "span")) {
|
2007-05-17 03:31:21 +00:00
|
|
|
if (cfg.catno != catno) {
|
2007-05-17 20:28:38 +00:00
|
|
|
zap_log(ZAP_LOG_DEBUG, "found config for span\n");
|
2007-05-17 16:57:26 +00:00
|
|
|
catno = cfg.catno;
|
2007-05-17 20:28:38 +00:00
|
|
|
new_span = 1;
|
|
|
|
span = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_span) {
|
|
|
|
if (!strcasecmp(var, "enabled") && ! zap_true(val)) {
|
|
|
|
zap_log(ZAP_LOG_DEBUG, "span (disabled)\n");
|
2007-05-17 16:57:26 +00:00
|
|
|
} else {
|
2007-05-17 20:28:38 +00:00
|
|
|
if (zap_span_create(&wanpipe_interface, &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;
|
|
|
|
}
|
2007-05-17 16:57:26 +00:00
|
|
|
}
|
2007-05-17 20:28:38 +00:00
|
|
|
new_span = 0;
|
2007-05-17 16:57:26 +00:00
|
|
|
continue;
|
|
|
|
}
|
2007-05-17 20:28:38 +00:00
|
|
|
|
2007-05-17 16:57:26 +00:00
|
|
|
if (!span) {
|
|
|
|
continue;
|
2007-05-17 03:31:21 +00:00
|
|
|
}
|
2007-05-17 16:57:26 +00:00
|
|
|
|
|
|
|
zap_log(ZAP_LOG_DEBUG, "span %d [%s]=[%s]\n", span->span_id, var, val);
|
2007-05-17 20:28:38 +00:00
|
|
|
|
|
|
|
if (!strcasecmp(var, "enabled")) {
|
2007-05-18 03:31:09 +00:00
|
|
|
zap_log(ZAP_LOG_WARNING, "'enabled' command ignored when it's not the first command in a [span]\n");
|
2007-05-17 20:28:38 +00:00
|
|
|
} else if (!strcasecmp(var, "b-channel")) {
|
|
|
|
configured += wp_configure_channel(&cfg, val, span, ZAP_CHAN_TYPE_B);
|
|
|
|
} else if (!strcasecmp(var, "d-channel")) {
|
|
|
|
if (d) {
|
|
|
|
zap_log(ZAP_LOG_WARNING, "ignoring extra d-channel\n");
|
|
|
|
} else {
|
2007-05-17 21:58:11 +00:00
|
|
|
zap_chan_type_t qtype;
|
|
|
|
if (!strncasecmp(val, "lapd:", 5)) {
|
|
|
|
qtype = ZAP_CHAN_TYPE_DQ931;
|
|
|
|
val += 5;
|
|
|
|
} else {
|
|
|
|
qtype = ZAP_CHAN_TYPE_DQ921;
|
|
|
|
}
|
|
|
|
configured += wp_configure_channel(&cfg, val, span, qtype);
|
2007-05-17 20:28:38 +00:00
|
|
|
d++;
|
|
|
|
}
|
|
|
|
}
|
2007-05-17 03:31:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
zap_config_close_file(&cfg);
|
|
|
|
|
2007-05-17 20:28:38 +00:00
|
|
|
zap_log(ZAP_LOG_INFO, "wanpipe configured %u channel(s)\n", configured);
|
|
|
|
|
|
|
|
return configured ? ZAP_SUCCESS : ZAP_FAIL;
|
2007-05-16 21:59:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static ZINT_OPEN_FUNCTION(wanpipe_open)
|
|
|
|
{
|
2007-05-19 00:50:50 +00:00
|
|
|
|
|
|
|
wanpipe_tdm_api_t tdm_api;
|
|
|
|
|
|
|
|
if (zchan->type == ZAP_CHAN_TYPE_DQ921 || zchan->type == ZAP_CHAN_TYPE_DQ931) {
|
|
|
|
zchan->native_codec = zchan->effective_codec = ZAP_CODEC_NONE;
|
|
|
|
} else {
|
|
|
|
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_CODEC;
|
|
|
|
tdm_api.wp_tdm_cmd.tdm_codec = WP_NONE;
|
|
|
|
wp_tdm_cmd_exec(zchan, &tdm_api);
|
|
|
|
|
|
|
|
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_USR_PERIOD;
|
|
|
|
tdm_api.wp_tdm_cmd.usr_period = wp_globals.codec_ms;
|
|
|
|
wp_tdm_cmd_exec(zchan, &tdm_api);
|
|
|
|
|
|
|
|
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_GET_HW_CODING;
|
|
|
|
if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
|
|
|
|
zchan->native_codec = zchan->effective_codec = ZAP_CODEC_ULAW;
|
|
|
|
} else {
|
|
|
|
zchan->native_codec = zchan->effective_codec = ZAP_CODEC_ALAW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-18 03:31:09 +00:00
|
|
|
return ZAP_SUCCESS;
|
2007-05-16 21:59:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static ZINT_CLOSE_FUNCTION(wanpipe_close)
|
|
|
|
{
|
|
|
|
ZINT_CLOSE_MUZZLE;
|
2007-05-18 03:31:09 +00:00
|
|
|
return ZAP_SUCCESS;
|
2007-05-16 21:59:11 +00:00
|
|
|
}
|
|
|
|
|
2007-05-18 03:31:09 +00:00
|
|
|
static ZINT_COMMAND_FUNCTION(wanpipe_command)
|
2007-05-16 21:59:11 +00:00
|
|
|
{
|
2007-05-18 03:31:09 +00:00
|
|
|
wanpipe_tdm_api_t tdm_api;
|
2007-05-19 05:05:29 +00:00
|
|
|
int err = 0;
|
2007-05-16 21:59:11 +00:00
|
|
|
|
2007-05-18 03:31:09 +00:00
|
|
|
ZINT_COMMAND_MUZZLE;
|
|
|
|
|
|
|
|
memset(&tdm_api, 0, sizeof(tdm_api));
|
|
|
|
|
|
|
|
switch(command) {
|
|
|
|
case ZAP_COMMAND_GET_INTERVAL:
|
|
|
|
{
|
|
|
|
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_GET_USR_PERIOD;
|
|
|
|
|
2007-05-18 14:08:30 +00:00
|
|
|
if (!(err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
|
2007-05-19 00:50:50 +00:00
|
|
|
ZAP_COMMAND_OBJ_INT = tdm_api.wp_tdm_cmd.usr_period;
|
2007-05-18 03:31:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZAP_COMMAND_SET_INTERVAL:
|
|
|
|
{
|
|
|
|
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_USR_PERIOD;
|
2007-05-19 00:50:50 +00:00
|
|
|
tdm_api.wp_tdm_cmd.usr_period = ZAP_COMMAND_OBJ_INT;
|
2007-05-18 14:08:30 +00:00
|
|
|
err = wp_tdm_cmd_exec(zchan, &tdm_api);
|
2007-05-18 03:31:09 +00:00
|
|
|
}
|
|
|
|
break;
|
2007-05-18 17:50:37 +00:00
|
|
|
default:
|
|
|
|
break;
|
2007-05-18 03:31:09 +00:00
|
|
|
};
|
|
|
|
|
2007-05-18 14:08:30 +00:00
|
|
|
if (err) {
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
2007-05-16 21:59:11 +00:00
|
|
|
}
|
|
|
|
|
2007-05-19 05:05:29 +00:00
|
|
|
#ifdef __WINDOWS__
|
|
|
|
|
|
|
|
static ZINT_WAIT_FUNCTION(wanpipe_wait_windows)
|
|
|
|
{
|
|
|
|
API_POLL_STRUCT api_poll;
|
|
|
|
zap_wait_flag_t inflags = *flags;
|
|
|
|
|
|
|
|
memset(&api_poll, 0x00, sizeof(API_POLL_STRUCT));
|
|
|
|
|
|
|
|
api_poll.user_flags_bitmap = inflags;
|
|
|
|
api_poll.timeout = to;
|
|
|
|
|
|
|
|
if(DoApiPollCommand(zchan->sockfd, &api_poll)){
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "Poll failed");
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*flags = ZAP_NO_FLAGS;
|
|
|
|
|
|
|
|
switch(api_poll.operation_status)
|
|
|
|
{
|
|
|
|
case SANG_STATUS_RX_DATA_AVAILABLE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "Unknown Operation Status: %d\n", api_poll.operation_status);
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(api_poll.poll_events_bitmap == 0){
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid Poll Events bitmap: 0x%X\n", api_poll.poll_events_bitmap);
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (api_poll.poll_events_bitmap & POLL_EVENT_TIMEOUT) {
|
|
|
|
return ZAP_TIMEOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (api_poll.poll_events_bitmap & POLL_EVENT_RX_DATA) {
|
|
|
|
*flags |= ZAP_READ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (api_poll.poll_events_bitmap & POLL_EVENT_TX_READY) {
|
|
|
|
*flags |= ZAP_WRITE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (api_poll.poll_events_bitmap & POLL_EVENT_LINK_STATE) {
|
|
|
|
*flags |= ZAP_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ZINT_READ_FUNCTION(wanpipe_read_windows)
|
|
|
|
{
|
2007-05-19 23:00:58 +00:00
|
|
|
zap_size_t rx_len = 0;
|
|
|
|
zap_status_t status = ZAP_FAIL;
|
|
|
|
|
|
|
|
/* should we just pass in abuffer big enough in the first place instead of having to use rx_data and memcpy here? */
|
|
|
|
static RX_DATA_STRUCT rx_data;
|
|
|
|
|
|
|
|
if(DoReadCommand(zchan->sockfd, &rx_data)) {
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "Error: DoReadCommand() failed! Check messages log.\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(rx_data.api_header.operation_status)
|
|
|
|
{
|
|
|
|
case SANG_STATUS_RX_DATA_AVAILABLE:
|
|
|
|
if(rx_data.api_header.data_length > *datalen){
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "Buffer overrun.\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
memcpy(data, rx_data.data, rx_data.api_header.data_length);
|
|
|
|
rx_len = rx_data.api_header.data_length;
|
|
|
|
status = ZAP_SUCCESS;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SANG_STATUS_TDM_EVENT_AVAILABLE:
|
|
|
|
memcpy(data, rx_data.data, rx_data.api_header.data_length);
|
|
|
|
rx_len = rx_data.api_header.data_length;
|
|
|
|
status = ZAP_SUCCESS;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SANG_STATUS_RX_DATA_TIMEOUT:
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "Error: Timeout on read.\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SANG_STATUS_BUFFER_TOO_SMALL:
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "Error: Received data longer than buffer passed to API.\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SANG_STATUS_LINE_DISCONNECTED:
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "Error: Line disconnected.\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "Rx:Unknown Operation Status: %d\n", rx_data.api_header.operation_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
*datalen = rx_len;
|
|
|
|
return status;
|
2007-05-19 05:05:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static ZINT_WRITE_FUNCTION(wanpipe_write_windows)
|
|
|
|
{
|
2007-05-19 23:00:58 +00:00
|
|
|
static TX_DATA_STRUCT local_tx_data;
|
|
|
|
|
|
|
|
/* why don't we just provide the big enough buffer to start with so we can avoid the memcpy ? */
|
|
|
|
memcpy(local_tx_data.data, data, *datalen);
|
|
|
|
|
|
|
|
/* queue data for transmission */
|
|
|
|
if(DoWriteCommand(zchan->sockfd, &local_tx_data)) {
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "Error: DoWriteCommand() failed!! Check messages log.\n");
|
|
|
|
*datalen = 0;
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (local_tx_data.api_header.operation_status == SANG_STATUS_SUCCESS) {
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
*datalen = 0;
|
|
|
|
|
|
|
|
switch(local_tx_data.api_header.operation_status)
|
|
|
|
{
|
|
|
|
case SANG_STATUS_TX_TIMEOUT:
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "****** Error: SANG_STATUS_TX_TIMEOUT ******\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SANG_STATUS_TX_DATA_TOO_LONG:
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "****** SANG_STATUS_TX_DATA_TOO_LONG ******\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SANG_STATUS_TX_DATA_TOO_SHORT:
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "****** SANG_STATUS_TX_DATA_TOO_SHORT ******\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SANG_STATUS_LINE_DISCONNECTED:
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "****** SANG_STATUS_LINE_DISCONNECTED ******\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "Unknown return code (0x%X) on transmission!\n", local_tx_data.api_header.operation_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-05-19 05:05:29 +00:00
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static ZINT_WAIT_FUNCTION(wanpipe_wait_unix)
|
2007-05-16 21:59:11 +00:00
|
|
|
{
|
2007-05-18 03:31:09 +00:00
|
|
|
fd_set read_fds, write_fds, error_fds, *r = NULL, *w = NULL, *e = NULL;
|
|
|
|
zap_wait_flag_t inflags = *flags;
|
|
|
|
int s;
|
|
|
|
struct timeval tv, *tvp = NULL;
|
|
|
|
|
|
|
|
if (to) {
|
|
|
|
memset(&tv, 0, sizeof(tv));
|
|
|
|
tv.tv_sec = to / 1000;
|
|
|
|
tv.tv_usec = (to % 1000) * 1000;
|
|
|
|
tvp = &tv;
|
|
|
|
}
|
|
|
|
|
|
|
|
FD_ZERO(&read_fds);
|
|
|
|
FD_ZERO(&write_fds);
|
|
|
|
FD_ZERO(&error_fds);
|
|
|
|
|
|
|
|
|
|
|
|
if (inflags & ZAP_READ) {
|
|
|
|
r = &read_fds;
|
|
|
|
FD_SET(zchan->sockfd, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inflags & ZAP_WRITE) {
|
|
|
|
w = &write_fds;
|
|
|
|
FD_SET(zchan->sockfd, w);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inflags & ZAP_ERROR) {
|
|
|
|
e = &error_fds;
|
|
|
|
FD_SET(zchan->sockfd, e);
|
|
|
|
}
|
|
|
|
|
|
|
|
*flags = ZAP_NO_FLAGS;
|
|
|
|
s = select(zchan->sockfd + 1, r, w, e, tvp);
|
2007-05-18 04:46:42 +00:00
|
|
|
|
2007-05-18 03:31:09 +00:00
|
|
|
if (s < 0) {
|
2007-05-19 00:50:50 +00:00
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "select: %s", strerror(errno));
|
2007-05-18 03:31:09 +00:00
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s > 0) {
|
|
|
|
if (r && FD_ISSET(zchan->sockfd, r)) {
|
|
|
|
*flags |= ZAP_READ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (w && FD_ISSET(zchan->sockfd, w)) {
|
|
|
|
*flags |= ZAP_WRITE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e && FD_ISSET(zchan->sockfd, e)) {
|
|
|
|
*flags |= ZAP_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s == 0) {
|
|
|
|
return ZAP_TIMEOUT;
|
|
|
|
}
|
2007-05-19 00:50:50 +00:00
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
2007-05-18 03:31:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static ZINT_READ_FUNCTION(wanpipe_read_unix)
|
|
|
|
{
|
|
|
|
int rx_len = 0;
|
|
|
|
struct msghdr msg;
|
|
|
|
struct iovec iov[2];
|
|
|
|
wp_tdm_api_rx_hdr_t hdrframe;
|
|
|
|
|
2007-05-18 04:18:19 +00:00
|
|
|
memset(&msg, 0, sizeof(msg));
|
|
|
|
memset(&hdrframe, 0, sizeof(hdrframe));
|
|
|
|
memset(iov, 0, sizeof(iov[0])*2);
|
2007-05-18 03:31:09 +00:00
|
|
|
|
|
|
|
iov[0].iov_len = sizeof(hdrframe);
|
|
|
|
iov[0].iov_base = &hdrframe;
|
|
|
|
|
|
|
|
iov[1].iov_len = *datalen;
|
|
|
|
iov[1].iov_base = data;
|
|
|
|
|
|
|
|
msg.msg_iovlen = 2;
|
|
|
|
msg.msg_iov = iov;
|
|
|
|
|
2007-05-18 04:18:19 +00:00
|
|
|
rx_len = read(zchan->sockfd, &msg, iov[1].iov_len + iov[0].iov_len);
|
2007-05-18 03:31:09 +00:00
|
|
|
|
2007-05-18 04:18:19 +00:00
|
|
|
if (rx_len > 0) {
|
|
|
|
rx_len -= sizeof(hdrframe);
|
2007-05-18 03:31:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*datalen = rx_len;
|
|
|
|
|
2007-05-18 04:18:19 +00:00
|
|
|
if (rx_len <= 0) {
|
2007-05-18 14:08:30 +00:00
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
2007-05-18 04:18:19 +00:00
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-05-18 03:31:09 +00:00
|
|
|
return ZAP_SUCCESS;
|
2007-05-16 21:59:11 +00:00
|
|
|
}
|
|
|
|
|
2007-05-18 03:31:09 +00:00
|
|
|
static ZINT_WRITE_FUNCTION(wanpipe_write_unix)
|
|
|
|
{
|
|
|
|
int bsent;
|
|
|
|
struct msghdr msg;
|
|
|
|
struct iovec iov[2];
|
2007-05-18 04:46:42 +00:00
|
|
|
wp_tdm_api_tx_hdr_t hdrframe;
|
2007-05-18 03:31:09 +00:00
|
|
|
|
2007-05-18 04:18:19 +00:00
|
|
|
memset(&msg, 0, sizeof(msg));
|
|
|
|
memset(&hdrframe, 0, sizeof(hdrframe));
|
|
|
|
memset(iov, 0, sizeof(iov[0])*2);
|
2007-05-18 03:31:09 +00:00
|
|
|
|
|
|
|
iov[0].iov_len = sizeof(hdrframe);
|
|
|
|
iov[0].iov_base = &hdrframe;
|
|
|
|
|
|
|
|
iov[1].iov_len = *datalen;
|
|
|
|
iov[1].iov_base = data;
|
|
|
|
|
|
|
|
msg.msg_iovlen = 2;
|
|
|
|
msg.msg_iov = iov;
|
2007-05-18 17:50:37 +00:00
|
|
|
bsent = write(zchan->sockfd, &msg, iov[1].iov_len + iov[0].iov_len);
|
2007-05-18 03:31:09 +00:00
|
|
|
|
|
|
|
if (bsent > 0){
|
|
|
|
bsent -= sizeof(wp_tdm_api_tx_hdr_t);
|
|
|
|
}
|
|
|
|
|
2007-05-18 14:08:30 +00:00
|
|
|
*datalen = bsent;
|
2007-05-18 17:50:37 +00:00
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
2007-05-18 03:31:09 +00:00
|
|
|
}
|
|
|
|
|
2007-05-18 05:33:19 +00:00
|
|
|
#endif
|
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
zap_status_t wanpipe_init(zap_software_interface_t **zint)
|
|
|
|
{
|
|
|
|
assert(zint != NULL);
|
2007-05-16 21:59:11 +00:00
|
|
|
memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
|
|
|
|
|
2007-05-19 00:50:50 +00:00
|
|
|
wp_globals.codec_ms = 20;
|
2007-05-16 21:59:11 +00:00
|
|
|
wanpipe_interface.name = "wanpipe";
|
|
|
|
wanpipe_interface.configure = wanpipe_configure;
|
|
|
|
wanpipe_interface.open = wanpipe_open;
|
|
|
|
wanpipe_interface.close = wanpipe_close;
|
2007-05-18 03:31:09 +00:00
|
|
|
wanpipe_interface.command = wanpipe_command;
|
2007-05-19 23:41:02 +00:00
|
|
|
#ifdef __WINDOWS__
|
|
|
|
wanpipe_interface.wait = wanpipe_wait_windows;
|
|
|
|
wanpipe_interface.read = wanpipe_read_windows;
|
|
|
|
wanpipe_interface.write = wanpipe_write_windows;
|
|
|
|
#else
|
|
|
|
wanpipe_interface.wait = wanpipe_wait_unix;
|
|
|
|
wanpipe_interface.read = wanpipe_read_unix;
|
|
|
|
wanpipe_interface.write = wanpipe_write_unix;
|
|
|
|
#endif
|
2007-05-16 21:59:11 +00:00
|
|
|
*zint = &wanpipe_interface;
|
2007-05-16 20:36:40 +00:00
|
|
|
|
2007-05-17 16:57:26 +00:00
|
|
|
return ZAP_SUCCESS;
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
|
|
|
|
2007-05-19 05:05:29 +00:00
|
|
|
#if defined(__WINDOWS__)
|
|
|
|
#define close(handle) CloseHandle(handle)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define zap_wanpipe_socket_close(it) if (it != WP_INVALID_SOCKET) { close(it); it = WP_INVALID_SOCKET;}
|
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
zap_status_t wanpipe_destroy(void)
|
|
|
|
{
|
2007-05-18 15:17:27 +00:00
|
|
|
unsigned int i,j;
|
2007-05-17 20:28:38 +00:00
|
|
|
|
|
|
|
for(i = 1; i <= wanpipe_interface.span_index; i++) {
|
|
|
|
zap_span_t *cur_span = &wanpipe_interface.spans[i];
|
|
|
|
|
|
|
|
if (zap_test_flag(cur_span, ZAP_SPAN_CONFIGURED)) {
|
|
|
|
for(j = 1; j <= cur_span->chan_count; j++) {
|
|
|
|
zap_channel_t *cur_chan = &cur_span->channels[j];
|
|
|
|
if (zap_test_flag(cur_chan, ZAP_CHANNEL_CONFIGURED)) {
|
|
|
|
zap_log(ZAP_LOG_INFO, "Closing channel %u:%u fd:%d\n", cur_chan->span_id, cur_chan->chan_id, cur_chan->sockfd);
|
2007-05-19 05:05:29 +00:00
|
|
|
zap_wanpipe_socket_close(cur_chan->sockfd);
|
2007-05-17 20:28:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|