Move from local to external osmo* libraries

src/libdebug -> libosmocore
src/libselect -> libosmocore
src/libtimer -> libosmocore
src/libosmocc -> libosmo-cc
src/libg711 -> libosmo-cc
This commit is contained in:
Andreas Eversberg 2024-01-09 12:24:14 +01:00
parent 805ed34740
commit 6ab6a91030
63 changed files with 1091 additions and 9277 deletions

6
.gitignore vendored
View File

@ -33,14 +33,10 @@ Doxyfile
.*.sw?
src/libdebug/libdebug.a
src/libg711/libg711.a
src/liblogging/liblogging.a
src/libjitter/libjitter.a
src/liboptions/liboptions.a
src/libosmocc/libosmocc.a
src/libsample/libsample.a
src/libtimer/libtimer.a
src/libselect/libselect.a
src/libph_socket/libph_socket.a
src/libmisdn/libmisdn.a
src/libmisdnuser/libmisdnuser.a

View File

@ -79,15 +79,14 @@ AM_CONFIG_HEADER(config.h)
AC_CHECK_LIB([m], [main])
AC_CHECK_LIB([pthread], [main])
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOCC, libosmocc >= 1.0.0)
AC_OUTPUT(
src/liboptions/Makefile
src/libdebug/Makefile
src/liblogging/Makefile
src/libsample/Makefile
src/libtimer/Makefile
src/libselect/Makefile
src/libjitter/Makefile
src/libosmocc/Makefile
src/libg711/Makefile
src/libph_socket/Makefile
src/libmisdn/Makefile
src/libmisdnuser/Makefile

View File

@ -2,13 +2,9 @@ AUTOMAKE_OPTIONS = foreign
SUBDIRS = \
liboptions \
libdebug \
liblogging \
libsample \
libtimer \
libselect \
libjitter \
libosmocc \
libg711 \
libph_socket \
libmisdn \
libmisdnuser \

View File

@ -14,17 +14,15 @@ osmo_cc_misdn_endpoint_SOURCES = \
osmo_cc_misdn_endpoint_LDADD = \
$(COMMON_LA) \
../libdebug/libdebug.a \
../liboptions/liboptions.a \
../libsample/libsample.a \
../libtimer/libtimer.a \
../libselect/libselect.a \
../libjitter/libjitter.a \
../libosmocc/libosmocc.a \
../libg711/libg711.a \
../libph_socket/libph_socket.a \
../libmisdn/libmisdn.a \
../libmisdnuser/libmisdnuser.a
../libmisdnuser/libmisdnuser.a \
../liblogging/liblogging.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCC_LIBS)
# -lmisdn

View File

@ -68,7 +68,7 @@
#include <sys/wait.h>
#include <ifaddrs.h>
#include <errno.h>
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include <mISDN/mbuffer.h>
#include "isdn.h"
#include "bridge.h"
@ -139,7 +139,7 @@ struct channel {
};
static struct osmo_fd server_ofd = { .fd = -1 };
static struct timer server_timer;
static struct osmo_timer_list server_timer;
static struct conn *conn_list = NULL;
static struct channel *channel_list = NULL;
@ -190,7 +190,7 @@ static void free_all_connections(void)
c = conn_list;
while (c) {
PDEBUG(DISDN, DEBUG_INFO, "Free pending bridge connection.\n");
LOGP(DISDN, LOGL_INFO, "Free pending bridge connection.\n");
c2 = c;
osmo_fd_unregister(&c->ofd);
close(c->ofd.fd);
@ -214,7 +214,7 @@ static int open_server_socket(int daemon)
rc = socket(PF_UNIX, SOCK_STREAM, 0);
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Failed to create UNIX socket.\n");
LOGP(DISDN, LOGL_ERROR, "Failed to create UNIX socket.\n");
return rc;
}
server_ofd.fd = rc;
@ -226,7 +226,7 @@ static int open_server_socket(int daemon)
rc = bind(server_ofd.fd, (struct sockaddr *)(&sock_address), sizeof(struct sockaddr_un));
if (rc < 0) {
if (!daemon || errno != EADDRINUSE)
PDEBUG(DISDN, DEBUG_INFO, "Failed to bind UNIX socket with path '%s' (errno = %d (%s)).\n", SOCKET_NAME, errno, strerror(errno));
LOGP(DISDN, LOGL_INFO, "Failed to bind UNIX socket with path '%s' (errno = %d (%s)).\n", SOCKET_NAME, errno, strerror(errno));
osmo_fd_unregister(&server_ofd);
close(server_ofd.fd);
return -EADDRINUSE;
@ -234,7 +234,7 @@ static int open_server_socket(int daemon)
rc = listen(server_ofd.fd, 10);
if (rc < 0) {
PDEBUG(DISDN, DEBUG_INFO, "Failed to listen to UNIX socket with path '%s' (errno = %d (%s)).\n", SOCKET_NAME, errno, strerror(errno));
LOGP(DISDN, LOGL_INFO, "Failed to listen to UNIX socket with path '%s' (errno = %d (%s)).\n", SOCKET_NAME, errno, strerror(errno));
osmo_fd_unregister(&server_ofd);
close(server_ofd.fd);
return rc;
@ -255,11 +255,11 @@ static int bridge_socket_server_cb(struct osmo_fd __attribute__((unused)) *ofd,
if ((when & OSMO_FD_READ)) {
rc = accept(server_ofd.fd, (struct sockaddr *)&sock_address, &sock_len);
if (rc > 0) {
PDEBUG(DISDN, DEBUG_INFO, "Connection from bridge socket client.\n");
LOGP(DISDN, LOGL_INFO, "Connection from bridge socket client.\n");
/* create connection */
c = calloc(1, sizeof(*c));
if (!c) {
PDEBUG(DISDN, DEBUG_ERROR, "No mem!\n");
LOGP(DISDN, LOGL_ERROR, "No mem!\n");
abort();
}
c->next = conn_list;
@ -313,10 +313,10 @@ static int bridge_socket_conn_cb(struct osmo_fd *ofd, unsigned int when)
if (rc > 0) {
c->rx_index += rc;
if (c->rx_index == sizeof(c->rx_msg)) {
PDEBUG(DISDN, DEBUG_DEBUG, "Message from bridge socket client.\n");
LOGP(DISDN, LOGL_DEBUG, "Message from bridge socket client.\n");
/* different version ? */
if (c->rx_msg.version != SOCKET_VERSION) {
PDEBUG(DISDN, DEBUG_ERROR, "Bridge client uses different version than bridge server. Please update all applications to use same server version\n");
LOGP(DISDN, LOGL_ERROR, "Bridge client uses different version than bridge server. Please update all applications to use same server version\n");
return 0;
}
/* process message and reset buffer index */
@ -325,7 +325,7 @@ static int bridge_socket_conn_cb(struct osmo_fd *ofd, unsigned int when)
return 0;
}
} else if (rc == 0 || errno != EAGAIN) {
PDEBUG(DISDN, DEBUG_DEBUG, "Close from bridge socket client.\n");
LOGP(DISDN, LOGL_DEBUG, "Close from bridge socket client.\n");
close_server_connection(&c->ofd);
/* destroy connection */
free_connection(c);
@ -337,7 +337,7 @@ static int bridge_socket_conn_cb(struct osmo_fd *ofd, unsigned int when)
static void sighandler(int sigset)
{
PDEBUG(DISDN, DEBUG_DEBUG, "Signal %d received.\n", sigset);
LOGP(DISDN, LOGL_DEBUG, "Signal %d received.\n", sigset);
}
static int quit = 0;
@ -345,11 +345,11 @@ static int quit = 0;
static void server_exit_timeout(void __attribute__((unused)) *data)
{
if (!conn_list) {
PDEBUG(DISDN, DEBUG_DEBUG, "All clients gone, exitting.\n");
LOGP(DISDN, LOGL_DEBUG, "All clients gone, exitting.\n");
quit = 1;
return;
}
timer_start(&server_timer, 0.3);
osmo_timer_schedule(&server_timer, 0,300000);
}
static void server_show_timeout(void __attribute__((unused)) *data)
@ -362,7 +362,7 @@ static void server_show_timeout(void __attribute__((unused)) *data)
printf("Card=%d Port=%d Channel=%d Bridge=%d\n", ch->card, ch->port, ch->channel, ch->pcm_bridge);
ch = ch->next;
}
timer_start(&server_timer, 1.0);
osmo_timer_schedule(&server_timer, 1,0);
}
/* open socket, wait for connections and read incoming messages */
@ -375,10 +375,10 @@ void bridge_socket_server_child(int slots, int daemon)
rc = open_server_socket(daemon);
if (rc < 0) {
if (rc == -EADDRINUSE)
PDEBUG(DISDN, DEBUG_INFO, "Bridging socket is already running by a different instance.\n");
LOGP(DISDN, LOGL_INFO, "Bridging socket is already running by a different instance.\n");
return;
}
PDEBUG(DISDN, DEBUG_DEBUG, "Created bridging socket server.\n");
LOGP(DISDN, LOGL_DEBUG, "Created bridging socket server.\n");
if (daemon) {
signal(SIGINT, sighandler);
@ -388,21 +388,18 @@ void bridge_socket_server_child(int slots, int daemon)
}
if (daemon) {
timer_init(&server_timer, server_exit_timeout, NULL);
timer_start(&server_timer, 0.3);
osmo_timer_setup(&server_timer, server_exit_timeout, NULL);
osmo_timer_schedule(&server_timer, 0,300000);
} else {
timer_init(&server_timer, server_show_timeout, NULL);
timer_start(&server_timer, 1.0);
osmo_timer_setup(&server_timer, server_show_timeout, NULL);
osmo_timer_schedule(&server_timer, 1,0);
}
while(!quit) {
double timeout;
timeout = process_timer();
osmo_fd_select(timeout);
osmo_select_main(0);
}
timer_exit(&server_timer);
osmo_timer_del(&server_timer);
free_all_channels();
free_all_connections();
@ -417,14 +414,14 @@ int bridge_socket_server(int slots)
pid = fork();
if (pid < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "fork() failed: errno=%d\n", errno);
LOGP(DISDN, LOGL_ERROR, "fork() failed: errno=%d\n", errno);
return -EINVAL;
}
if (pid == 0) {
/* child */
pid = fork();
if (pid < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "fork() failed: errno=%d\n", errno);
LOGP(DISDN, LOGL_ERROR, "fork() failed: errno=%d\n", errno);
exit(0);
}
if (pid == 0) {
@ -458,7 +455,7 @@ static void rx_channel_info(int socket, int card, int port, int channel, uint16_
if (c) {
/* we are already can bridge */
if (can_bridge) {
PDEBUG(DISDN, DEBUG_DEBUG, "There is no change in bridge, do nothing.\n");
LOGP(DISDN, LOGL_DEBUG, "There is no change in bridge, do nothing.\n");
return;
}
/* we must remove bridge, if remote channel exists */
@ -471,34 +468,34 @@ static void rx_channel_info(int socket, int card, int port, int channel, uint16_
/* remote channel exists, so remove bridge */
if (o) {
if (o->pcm_bridge && o->socket > 0) {
PDEBUG(DISDN, DEBUG_DEBUG, "We cannot bridge anymore, remove remote channel's bridge.\n");
LOGP(DISDN, LOGL_DEBUG, "We cannot bridge anymore, remove remote channel's bridge.\n");
tx_bridge_order(o->socket, o->card, o->port, o->channel, 0, 0, 0, 0, 0);
o->pcm_bridge = 0;
}
}
/* now we remove our channel */
if (c->pcm_bridge && c->socket > 0) {
PDEBUG(DISDN, DEBUG_DEBUG, "We cannot bridge anymore, remove our bridge.\n");
LOGP(DISDN, LOGL_DEBUG, "We cannot bridge anymore, remove our bridge.\n");
tx_bridge_order(c->socket, c->card, c->port, c->channel, 0, 0, 0, 0, 0);
c->pcm_bridge = 0;
}
PDEBUG(DISDN, DEBUG_DEBUG, "Freeing our channel.\n");
LOGP(DISDN, LOGL_DEBUG, "Freeing our channel.\n");
free_channel(c);
return;
}
/* if channel does not exists and we cannot bridge, do nothing */
if (!can_bridge) {
PDEBUG(DISDN, DEBUG_DEBUG, "There is no change in bridge, do nothing.\n");
LOGP(DISDN, LOGL_DEBUG, "There is no change in bridge, do nothing.\n");
return;
}
/* channel does not exist, so we create it */
/* create connection */
PDEBUG(DISDN, DEBUG_DEBUG, "Creating our channel.\n");
LOGP(DISDN, LOGL_DEBUG, "Creating our channel.\n");
c = calloc(1, sizeof(*c));
if (!c) {
PDEBUG(DISDN, DEBUG_ERROR, "No mem!\n");
LOGP(DISDN, LOGL_ERROR, "No mem!\n");
abort();
}
c->next = channel_list;
@ -519,11 +516,11 @@ static void rx_channel_info(int socket, int card, int port, int channel, uint16_
}
/* no other channel, so we do not need to send a bridge order */
if (!o) {
PDEBUG(DISDN, DEBUG_DEBUG, "We can bridge, but there is no remote that can bridge (yet)..\n");
LOGP(DISDN, LOGL_DEBUG, "We can bridge, but there is no remote that can bridge (yet)..\n");
return;
}
PDEBUG(DISDN, DEBUG_DEBUG, "We can bridge, and remote can bridge, so we assign time slots.\n");
LOGP(DISDN, LOGL_DEBUG, "We can bridge, and remote can bridge, so we assign time slots.\n");
/* make a list of allocated time slots */
uint8_t pcm_slot[num_slots];
@ -558,7 +555,7 @@ static void rx_channel_info(int socket, int card, int port, int channel, uint16_
o->rx_bank = 1;
o->tx_bank = 0;
} else {
PDEBUG(DISDN, DEBUG_NOTICE, "No single free slots, cannot set bridge.\n");
LOGP(DISDN, LOGL_NOTICE, "No single free slots, cannot set bridge.\n");
return;
}
} else {
@ -588,7 +585,7 @@ static void rx_channel_info(int socket, int card, int port, int channel, uint16_
o->rx_bank = 0;
o->tx_bank = 0;
} else {
PDEBUG(DISDN, DEBUG_NOTICE, "No two free slots, cannot set bridge.\n");
LOGP(DISDN, LOGL_NOTICE, "No two free slots, cannot set bridge.\n");
return;
}
}
@ -640,7 +637,7 @@ int bridge_socket_client(isdn_t *isdn_ep)
rc = socket(PF_UNIX, SOCK_STREAM, 0);
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Failed to create UNIX socket.\n");
LOGP(DISDN, LOGL_ERROR, "Failed to create UNIX socket.\n");
return rc;
}
client_ofd.fd = rc;
@ -651,14 +648,14 @@ int bridge_socket_client(isdn_t *isdn_ep)
rc = connect(client_ofd.fd, (struct sockaddr *)(&sock_address), sizeof(struct sockaddr_un));
if (rc < 0) {
PDEBUG(DISDN, DEBUG_DEBUG, "Failed to connect to UNIX socket with path '%s' (errno = %d (%s)).\n", SOCKET_NAME, errno, strerror(errno));
LOGP(DISDN, LOGL_DEBUG, "Failed to connect to UNIX socket with path '%s' (errno = %d (%s)).\n", SOCKET_NAME, errno, strerror(errno));
osmo_fd_unregister(&client_ofd);
close(client_ofd.fd);
client_ofd.fd = -1;
return -errno;
}
PDEBUG(DISDN, DEBUG_DEBUG, "Created bridging socket client.\n");
LOGP(DISDN, LOGL_DEBUG, "Created bridging socket client.\n");
return 0;
}
@ -677,10 +674,10 @@ static int bridge_socket_client_cb(struct osmo_fd *ofd, unsigned int when)
if (rc > 0) {
client_rx_index += rc;
if (client_rx_index == sizeof(client_rx_msg)) {
PDEBUG(DISDN, DEBUG_DEBUG, "Message from bridge socket server.\n");
LOGP(DISDN, LOGL_DEBUG, "Message from bridge socket server.\n");
/* different version ? */
if (client_rx_msg.version != SOCKET_VERSION) {
PDEBUG(DISDN, DEBUG_ERROR, "Bridge server uses different version than bridge client. Please update all applications to use same server version\n");
LOGP(DISDN, LOGL_ERROR, "Bridge server uses different version than bridge client. Please update all applications to use same server version\n");
return 0;
}
/* process message and reset buffer index */
@ -688,7 +685,7 @@ static int bridge_socket_client_cb(struct osmo_fd *ofd, unsigned int when)
client_rx_index = 0;
}
} else if (rc == 0 || errno != EAGAIN) {
PDEBUG(DISDN, DEBUG_DEBUG, "Close from bridge socket client.\n");
LOGP(DISDN, LOGL_DEBUG, "Close from bridge socket client.\n");
osmo_fd_unregister(&client_ofd);
close(client_ofd.fd);
client_ofd.fd = -1;
@ -707,7 +704,7 @@ int check_local_address(sa_family_t family, struct sockaddr *addr)
rc = getifaddrs(&ifaddr);
if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Failed to read list of interface addresses.\n");
LOGP(DISDN, LOGL_ERROR, "Failed to read list of interface addresses.\n");
return 0;
}
@ -744,7 +741,7 @@ void rx_bridge_order(isdn_t *isdn_ep, int card, int port, int channel, int pcm_b
call_t *call;
if (!isdn_ep->bridge_possible || isdn_ep->bridge_cardnum != card || isdn_ep->bridge_portnum != port) {
PDEBUG(DISDN, DEBUG_ERROR, "Client received bridge order that does not match our port/port, please fix!\n");
LOGP(DISDN, LOGL_ERROR, "Client received bridge order that does not match our port/port, please fix!\n");
}
/* hunt for call */
@ -755,14 +752,14 @@ void rx_bridge_order(isdn_t *isdn_ep, int card, int port, int channel, int pcm_b
call = call->next;
}
if (!call) {
PDEBUG(DISDN, DEBUG_DEBUG, "Client received bridge order that does not belong to an active call, ignoring!\n");
LOGP(DISDN, LOGL_DEBUG, "Client received bridge order that does not belong to an active call, ignoring!\n");
return;
}
if (pcm_bridge)
PDEBUG(DISDN, DEBUG_DEBUG, "Client received bridge connect order to connect to PCM slots (%d,%d,%d,%d).\n", rx_slot, tx_slot, rx_bank, tx_bank);
LOGP(DISDN, LOGL_DEBUG, "Client received bridge connect order to connect to PCM slots (%d,%d,%d,%d).\n", rx_slot, tx_slot, rx_bank, tx_bank);
else
PDEBUG(DISDN, DEBUG_DEBUG, "Client received bridge disconnect order to disconnect to PCM slots.\n");
LOGP(DISDN, LOGL_DEBUG, "Client received bridge disconnect order to disconnect to PCM slots.\n");
bchannel_bridge(call, pcm_bridge, rx_slot, tx_slot, rx_bank, tx_bank);
}
@ -784,29 +781,29 @@ void bridge_socket_client_update(call_t *call, int enable)
if (client_ofd.fd <= 0)
return;
PDEBUG(DISDN, DEBUG_INFO, "We got called with enable=%d\n", enable);
LOGP(DISDN, LOGL_INFO, "We got called with enable=%d\n", enable);
/* do we have HFC card ? */
if (!call->isdn_ep->bridge_possible && enable) {
PDEBUG(DISDN, DEBUG_INFO, "Our card is not an HFC card, cannot use hardware bridging.\n");
LOGP(DISDN, LOGL_INFO, "Our card is not an HFC card, cannot use hardware bridging.\n");
return;
}
if (!call->b_channel) {
PDEBUG(DISDN, DEBUG_DEBUG, "Cannot check bridge, no bchannel currently assigned.\n");
LOGP(DISDN, LOGL_DEBUG, "Cannot check bridge, no bchannel currently assigned.\n");
return;
}
/* check if essential structures are set */
if (!call->cc_session || !call->cc_session->media_list) {
PDEBUG(DISDN, DEBUG_DEBUG, "Codec/media not set, not ready for bridging.\n");
LOGP(DISDN, LOGL_DEBUG, "Codec/media not set, not ready for bridging.\n");
return;
}
media = call->cc_session->media_list;
/* check if codec negotiation is complete */
if (!media->description.port_local || (call->direction == DIRECTION_TERMINATOR && !media->description.port_remote)) {
PDEBUG(DISDN, DEBUG_DEBUG, "Codec negotiation is not complete, cannot bridge yet.\n");
LOGP(DISDN, LOGL_DEBUG, "Codec negotiation is not complete, cannot bridge yet.\n");
return;
}
@ -820,7 +817,7 @@ void bridge_socket_client_update(call_t *call, int enable)
sa4->sin_family = family;
rc = inet_pton(AF_INET, media->connection_data_remote.address, &sa4->sin_addr);
if (rc < 1) {
PDEBUG(DISDN, DEBUG_ERROR, "inet_pton failed, please fix!\n");
LOGP(DISDN, LOGL_ERROR, "inet_pton failed, please fix!\n");
return;
}
break;
@ -831,26 +828,26 @@ void bridge_socket_client_update(call_t *call, int enable)
sa6->sin6_family = family;
rc = inet_pton(AF_INET6, media->connection_data_remote.address, &sa6->sin6_addr);
if (rc < 1) {
PDEBUG(DISDN, DEBUG_ERROR, "inet_pton failed, please fix!\n");
LOGP(DISDN, LOGL_ERROR, "inet_pton failed, please fix!\n");
return;
}
break;
case osmo_cc_session_addrtype_unknown:
PDEBUG(DISDN, DEBUG_DEBUG, "Unsupported address type '%s'.\n", media->connection_data_remote.addrtype_name);
LOGP(DISDN, LOGL_DEBUG, "Unsupported address type '%s'.\n", media->connection_data_remote.addrtype_name);
return;
}
rc = check_local_address(family, (struct sockaddr *)&sa);
if (rc < 1) {
PDEBUG(DISDN, DEBUG_DEBUG, "Remote RTP peer is not on this machine, cannot use hardware bridging.\n");
LOGP(DISDN, LOGL_DEBUG, "Remote RTP peer is not on this machine, cannot use hardware bridging.\n");
return;
}
} else {
PDEBUG(DISDN, DEBUG_DEBUG, "We are originator, we may use hardware bridging.\n");
LOGP(DISDN, LOGL_DEBUG, "We are originator, we may use hardware bridging.\n");
}
/* check if 3PTY */
if (call->conference_3pty) {
PDEBUG(DISDN, DEBUG_DEBUG, "Whe have 3PTY conference, cannot bridge while this is going on.\n");
LOGP(DISDN, LOGL_DEBUG, "Whe have 3PTY conference, cannot bridge while this is going on.\n");
goto send;
}
@ -859,10 +856,10 @@ void bridge_socket_client_update(call_t *call, int enable)
send:
/* only send on change */
if (can_bridge && !call->can_bridge) {
PDEBUG(DISDN, DEBUG_INFO, "We tell the server we can do hardware bridging.\n");
LOGP(DISDN, LOGL_INFO, "We tell the server we can do hardware bridging.\n");
} else
if (!can_bridge && call->can_bridge) {
PDEBUG(DISDN, DEBUG_INFO, "We tell the server we cannot do hardware bridging anymore.\n");
LOGP(DISDN, LOGL_INFO, "We tell the server we cannot do hardware bridging anymore.\n");
} else
return;
call->can_bridge = can_bridge;

View File

@ -25,8 +25,8 @@
#include <stdint.h>
#include <stdlib.h>
#include <mISDN/mbuffer.h>
#include "../libdebug/debug.h"
#include "../libg711/g711.h"
#include "../liblogging/logging.h"
#include <osmocom/cc/g711.h>
#include "isdn.h"
#include "dss1.h"
#include "bridge.h"
@ -75,7 +75,7 @@ static struct l3_msg *create_l3msg(void)
l3m = alloc_l3_msg();
if (!l3m) {
PDEBUG(DDSS1, DEBUG_ERROR, "No MEM!\n");
LOGP(DDSS1, LOGL_ERROR, "No MEM!\n");
abort();
}
return l3m;
@ -109,7 +109,7 @@ static void new_state(call_t *call, enum isdn_state state)
{
if (call->state == state)
return;
PDEBUG(DDSS1, DEBUG_DEBUG, "Changing state %s -> %s\n", state_names[call->state], state_names[state]);
LOGP(DDSS1, LOGL_DEBUG, "Changing state %s -> %s\n", state_names[call->state], state_names[state]);
call->state = state;
}
@ -134,7 +134,7 @@ static void release_and_destroy(call_t *call, uint8_t cc_isdn_cause, uint16_t cc
}
if (isdn_cause) {
PDEBUG(DDSS1, DEBUG_INFO, "REJECT REQUEST (pid = 0x%x callref = %d)\n", call->l3_pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "REJECT REQUEST (pid = 0x%x callref = %d)\n", call->l3_pid, call->cc_callref);
/* creating release complete */
l3m = create_l3msg();
@ -206,10 +206,10 @@ void setup_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
struct osmo_cc_helper_audio_codecs *codecs;
int clearmode = 0;
PDEBUG(DDSS1, DEBUG_INFO, "SETUP INDICATION (pid = 0x%x)\n", pid);
LOGP(DDSS1, LOGL_INFO, "SETUP INDICATION (pid = 0x%x)\n", pid);
/* assign pid */
PDEBUG(DDSS1, DEBUG_DEBUG, " -> new L3ID assigned (l3id = 0x%x)\n", pid);
LOGP(DDSS1, LOGL_DEBUG, " -> new L3ID assigned (l3id = 0x%x)\n", pid);
call->l3_pid = pid;
call->l3_ces = pid >> 16;
@ -332,7 +332,7 @@ void setup_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
no_channel:
osmo_cc_free_msg(msg);
/* send MT_RELEASE_COMPLETE to "REJECT" the channel */
PDEBUG(DDSS1, DEBUG_INFO, "RELEASE-COMPLETE REQUEST (pid = 0x%x)\n", pid);
LOGP(DDSS1, LOGL_INFO, "RELEASE-COMPLETE REQUEST (pid = 0x%x)\n", pid);
l3m = create_l3msg();
enc_ie_cause(l3m, call->isdn_ep->serving_location, -rc);
call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_RELEASE_COMPLETE, call->l3_pid, l3m);
@ -352,7 +352,7 @@ void setup_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
/* create endpoint */
osmo_cc_call_t *cc_call = osmo_cc_call_new(&call->isdn_ep->cc_ep);
call->cc_callref = cc_call->callref;
PDEBUG(DDSS1, DEBUG_DEBUG, " -> new callref assigned (callref = %d)\n", call->cc_callref);
LOGP(DDSS1, LOGL_DEBUG, " -> new callref assigned (callref = %d)\n", call->cc_callref);
new_state(call, ISDN_STATE_IN_SETUP);
@ -369,7 +369,7 @@ void setup_ack_ind(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "SETUP-ACKNOWLEDGE INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "SETUP-ACKNOWLEDGE INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_ACK_IND);
@ -392,7 +392,7 @@ void setup_ack_ind(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
rc = dec_ie_channel_id(l3m, call->isdn_ep->pri, &exclusive, &channel);
rc = open_bchannel_out(call, cmd, (rc < 0) ? -1 : channel, (rc < 0) ? -1 : exclusive);
if (rc < 0) {
PDEBUG(DDSS1, DEBUG_NOTICE, "Channel negotiation failed.\n");
LOGP(DDSS1, LOGL_NOTICE, "Channel negotiation failed.\n");
osmo_cc_free_msg(msg);
release_and_destroy(call, OSMO_CC_ISDN_CAUSE_RESOURCE_UNAVAIL, 0, -rc);
return;
@ -431,7 +431,7 @@ void proc_ind(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "PREOCEEDING INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "PREOCEEDING INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_PROC_IND);
@ -467,7 +467,7 @@ void proc_ind(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
rc = dec_ie_channel_id(l3m, call->isdn_ep->pri, &exclusive, &channel);
rc = open_bchannel_out(call, cmd, (rc < 0) ? -1 : channel, (rc < 0) ? -1 : exclusive);
if (rc < 0) {
PDEBUG(DDSS1, DEBUG_NOTICE, "Channel negotiation failed.\n");
LOGP(DDSS1, LOGL_NOTICE, "Channel negotiation failed.\n");
osmo_cc_free_msg(msg);
release_and_destroy(call, OSMO_CC_ISDN_CAUSE_RESOURCE_UNAVAIL, 0, -rc);
return;
@ -506,7 +506,7 @@ void alert_ind(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "ALERTING INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "ALERTING INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_ALERT_IND);
@ -542,7 +542,7 @@ void alert_ind(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
rc = dec_ie_channel_id(l3m, call->isdn_ep->pri, &exclusive, &channel);
rc = open_bchannel_out(call, cmd, (rc < 0) ? -1 : channel, (rc < 0) ? -1 : exclusive);
if (rc < 0) {
PDEBUG(DDSS1, DEBUG_NOTICE, "Channel negotiation failed.\n");
LOGP(DDSS1, LOGL_NOTICE, "Channel negotiation failed.\n");
osmo_cc_free_msg(msg);
release_and_destroy(call, OSMO_CC_ISDN_CAUSE_RESOURCE_UNAVAIL, 0, -rc);
return;
@ -581,7 +581,7 @@ void setup_cnf(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "CONNECT INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "CONNECT INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_CNF);
@ -626,7 +626,7 @@ void setup_cnf(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
/* complete channel negotiation */
rc = open_bchannel_out(call, cmd, channel, exclusive); /* channel and exclusive may be -1 */
if (rc < 0) {
PDEBUG(DDSS1, DEBUG_NOTICE, "Channel negotiation failed.\n");
LOGP(DDSS1, LOGL_NOTICE, "Channel negotiation failed.\n");
osmo_cc_free_msg(msg);
release_and_destroy(call, OSMO_CC_ISDN_CAUSE_RESOURCE_UNAVAIL, 0, -rc);
return;
@ -659,7 +659,7 @@ void setup_comp_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "CONNECT-ACKNOWLEDGE INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "CONNECT-ACKNOWLEDGE INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* only send in TE mode, because we automatically reply in NT mode */
if (call->isdn_ep->ntmode)
@ -690,7 +690,7 @@ void info_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "INFO INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "INFO INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_INFO_IND);
@ -725,7 +725,7 @@ void info_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
/* stop tone, if something has been dialled */
if (call->send_local_tones && call->any_dialing && call->state == ISDN_STATE_IN_OVERLAP) {
PDEBUG(DDSS1, DEBUG_DEBUG, "Stop sending locally generated dial tone. (if not already)\n");
LOGP(DDSS1, LOGL_DEBUG, "Stop sending locally generated dial tone. (if not already)\n");
bchannel_tone(call, 0);
}
@ -741,7 +741,7 @@ void disconnect_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "DISCONNECT INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "DISCONNECT INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_DISC_IND);
@ -774,7 +774,7 @@ void disconnect_ind_i(call_t *call, uint32_t pid, struct l3_msg *l3m)
uint8_t location, cause;
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "DISCONNECT INDICATION of child (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "DISCONNECT INDICATION of child (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* collect cause */
rc = dec_ie_cause(l3m, &location, &cause);
@ -792,7 +792,7 @@ void release_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "RELEASE INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "RELEASE INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_REL_IND);
@ -825,7 +825,7 @@ void release_complete_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
uint8_t location, cause;
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "RELEASE-COMPLETE INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "RELEASE-COMPLETE INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* create osmo-cc message */
switch (call->state) {
@ -865,7 +865,7 @@ void release_complete_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
/* CC-RESTART INDICATION */
void restart_ind(uint32_t pid)
{
PDEBUG(DDSS1, DEBUG_INFO, "RESTART INDICATION (pid = 0x%x)\n", pid);
LOGP(DDSS1, LOGL_INFO, "RESTART INDICATION (pid = 0x%x)\n", pid);
// L3 process is not touched. (not even by network stack)
}
@ -886,7 +886,7 @@ void notify_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "NOTIFY INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "NOTIFY INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_NOTIFY_IND);
@ -923,11 +923,11 @@ void hold_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
{
osmo_cc_msg_t *msg;
PDEBUG(DDSS1, DEBUG_INFO, "HOLD INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "HOLD INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* reject, if we are on hold */
if (call->hold) {
PDEBUG(DDSS1, DEBUG_INFO, "HOLD-REJECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "HOLD-REJECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
l3m = create_l3msg();
enc_ie_cause(l3m, call->isdn_ep->serving_location, call->hold?101:31); /* normal unspecified / incompatible state */
call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_HOLD_REJECT, call->l3_pid, l3m);
@ -959,7 +959,7 @@ void hold_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
enable_hold_clock(call->isdn_ep);
/* acknowledge hold */
PDEBUG(DDSS1, DEBUG_INFO, "HOLD-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "HOLD-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
l3m = create_l3msg();
call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_HOLD_ACKNOWLEDGE, call->l3_pid, l3m);
}
@ -972,13 +972,13 @@ void retrieve_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
int channel, exclusive;
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "RETRIEVE INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "RETRIEVE INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
if (!call->hold) {
rc = -101; /* incompatible state */
no_channel:
/* reject retrieve */
PDEBUG(DDSS1, DEBUG_INFO, "RETRIEVE-REJECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "RETRIEVE-REJECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
l3m = create_l3msg();
enc_ie_cause(l3m, call->isdn_ep->serving_location, rc);
call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_RETRIEVE_REJECT, call->l3_pid, l3m);
@ -1015,7 +1015,7 @@ void retrieve_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
jitter_reset(&call->tx_dejitter);
/* acknowledge retrieve */
PDEBUG(DDSS1, DEBUG_INFO, "RETRIEVE-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "RETRIEVE-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
l3m = create_l3msg();
enc_ie_channel_id(l3m, call->isdn_ep->pri, 1, call->b_channel);
call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_RETRIEVE_ACKNOWLEDGE, call->l3_pid, l3m);
@ -1030,11 +1030,11 @@ void suspend_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
int rc = -31; /* normal, unspecified */
call_t *check;
PDEBUG(DDSS1, DEBUG_INFO, "SUSPEND INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "SUSPEND INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
if (0) {
reject:
PDEBUG(DDSS1, DEBUG_INFO, "SUSPEND-REJECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "SUSPEND-REJECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
l3m = create_l3msg();
enc_ie_cause(l3m, call->isdn_ep->serving_location, -rc);
call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_SUSPEND_REJECT, call->l3_pid, l3m);
@ -1052,7 +1052,7 @@ void suspend_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
if (check->state == ISDN_STATE_SUSPENDED
&& check->park_len == len
&& !memcmp(check->park_callid, callid, len)) {
PDEBUG(DDSS1, DEBUG_INFO, "Given Park ID is already in use, rejecting!\n");
LOGP(DDSS1, LOGL_INFO, "Given Park ID is already in use, rejecting!\n");
rc = -84; /* call id in use */
goto reject;
}
@ -1085,7 +1085,7 @@ void suspend_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
enable_hold_clock(call->isdn_ep);
/* sending SUSPEND_ACKNOWLEDGE */
PDEBUG(DDSS1, DEBUG_INFO, "SUSPEND-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "SUSPEND-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
l3m = create_l3msg();
call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_SUSPEND_ACKNOWLEDGE, call->l3_pid, l3m);
}
@ -1100,7 +1100,7 @@ void resume_ind(isdn_t *isdn_ep, uint32_t pid, struct l3_msg *l3m)
int channel, exclusive;
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "RESUME INDICATION (pid = 0x%x)\n", pid);
LOGP(DDSS1, LOGL_INFO, "RESUME INDICATION (pid = 0x%x)\n", pid);
/* call id */
rc = dec_ie_call_id(l3m, callid, &len);
@ -1119,10 +1119,10 @@ void resume_ind(isdn_t *isdn_ep, uint32_t pid, struct l3_msg *l3m)
/* process given callref */
if (!call) {
PDEBUG(DDSS1, DEBUG_NOTICE, "No parked call found with given park ID, rejecting.\n");
LOGP(DDSS1, LOGL_NOTICE, "No parked call found with given park ID, rejecting.\n");
rc = -85;
no_channel:
PDEBUG(DDSS1, DEBUG_INFO, "RESUME-REJECT REQUEST (pid = 0x%x)\n", pid);
LOGP(DDSS1, LOGL_INFO, "RESUME-REJECT REQUEST (pid = 0x%x)\n", pid);
l3m = create_l3msg();
enc_ie_cause(l3m, isdn_ep->serving_location, -rc);
isdn_ep->ml3->to_layer3(isdn_ep->ml3, MT_RESUME_REJECT, pid, l3m);
@ -1130,7 +1130,7 @@ void resume_ind(isdn_t *isdn_ep, uint32_t pid, struct l3_msg *l3m)
}
/* assign pid */
PDEBUG(DDSS1, DEBUG_DEBUG, "new L3ID assigned (l3id = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_DEBUG, "new L3ID assigned (l3id = 0x%x callref = %d)\n", pid, call->cc_callref);
call->l3_pid = pid;
call->l3_ces = pid >> 16;
@ -1166,7 +1166,7 @@ void resume_ind(isdn_t *isdn_ep, uint32_t pid, struct l3_msg *l3m)
osmo_cc_ll_msg(&call->isdn_ep->cc_ep, call->cc_callref, msg);
/* sending RESUME_ACKNOWLEDGE */
PDEBUG(DDSS1, DEBUG_INFO, "RESUME-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "RESUME-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
l3m = create_l3msg();
enc_ie_channel_id(l3m, call->isdn_ep->pri, 1, call->b_channel);
call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_RESUME_ACKNOWLEDGE, call->l3_pid, l3m);
@ -1185,7 +1185,7 @@ void facility_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
call_t *other;
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "FACILITY INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "FACILITY INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* facility */
rc = dec_ie_facility(l3m, fac_ie + 1, &fac_len);
@ -1243,7 +1243,7 @@ void facility_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
jitter_reset(&other->conf_dejitter);
jitter_reset(&other->tx_dejitter);
} else {
PDEBUG(DDSS1, DEBUG_NOTICE, "Phone requests conference, but no call on hold!\n");
LOGP(DDSS1, LOGL_NOTICE, "Phone requests conference, but no call on hold!\n");
notify = 0;
}
@ -1295,7 +1295,7 @@ void progress_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
uint8_t coding, location, progress;
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "PROGRESS INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "PROGRESS INDICATION (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_PROGRESS_IND);
@ -1333,7 +1333,7 @@ void mt_free(call_t *call)
{
osmo_cc_msg_t *msg;
PDEBUG(DDSS1, DEBUG_DEBUG, "Got MT_FREE (release from stack) (old pid 0x%x)\n", call->l3_pid);
LOGP(DDSS1, LOGL_DEBUG, "Got MT_FREE (release from stack) (old pid 0x%x)\n", call->l3_pid);
/* create osmo-cc message */
switch (call->state) {
@ -1365,17 +1365,17 @@ void dss1_message(isdn_t *isdn_ep, call_t *call, uint32_t cmd, uint32_t pid, str
switch (cmd) {
case MT_TIMEOUT:
if (!l3m->cause) {
PDEBUG(DDSS1, DEBUG_ERROR, "timeout without cause.\n");
LOGP(DDSS1, LOGL_ERROR, "timeout without cause.\n");
break;
}
if (l3m->cause[0] != 5) {
PDEBUG(DDSS1, DEBUG_ERROR, "expecting timeout with timer diagnostic. (got len=%d)\n", l3m->cause[0]);
LOGP(DDSS1, LOGL_ERROR, "expecting timeout with timer diagnostic. (got len=%d)\n", l3m->cause[0]);
break;
}
timer = (l3m->cause[3]-'0')*100;
timer += (l3m->cause[4]-'0')*10;
timer += (l3m->cause[5]-'0');
PDEBUG(DDSS1, DEBUG_DEBUG, "isdn timer T%d timeout\n", timer);
LOGP(DDSS1, LOGL_DEBUG, "isdn timer T%d timeout\n", timer);
if (timer == 312)
t312_timeout_ind();
break;
@ -1459,7 +1459,7 @@ void dss1_message(isdn_t *isdn_ep, call_t *call, uint32_t cmd, uint32_t pid, str
break;
default:
PDEBUG(DDSS1, DEBUG_ERROR, "unhandled message: cmd(0x%x) pid(0x%x)\n", cmd, pid);
LOGP(DDSS1, LOGL_ERROR, "unhandled message: cmd(0x%x) pid(0x%x)\n", cmd, pid);
}
}
@ -1468,7 +1468,7 @@ int dss1_receive(isdn_t *isdn_ep, uint32_t cmd, uint32_t pid, struct l3_msg *l3m
{
call_t *call;
PDEBUG(DDSS1, DEBUG_DEBUG, "message from L3 stack: cmd(0x%x) pid(0x%x)\n", cmd, pid);
LOGP(DDSS1, LOGL_DEBUG, "message from L3 stack: cmd(0x%x) pid(0x%x)\n", cmd, pid);
/* find call that is associated with the pid */
call = isdn_ep->call_list;
@ -1491,9 +1491,9 @@ int dss1_receive(isdn_t *isdn_ep, uint32_t cmd, uint32_t pid, struct l3_msg *l3m
if (call) {
/* after answering the phone, the PID will be completed and CES will be assigned */
if (cmd == MT_ASSIGN) {
PDEBUG(DDSS1, DEBUG_DEBUG, "Got assignment (old pid 0x%x, new pid 0x%x)\n", call->l3_pid, pid);
LOGP(DDSS1, LOGL_DEBUG, "Got assignment (old pid 0x%x, new pid 0x%x)\n", call->l3_pid, pid);
if ((call->l3_pid & MISDN_PID_CRTYPE_MASK) != MISDN_PID_MASTER)
PDEBUG(DDSS1, DEBUG_ERROR, "strange setup-procid 0x%x\n", call->l3_pid);
LOGP(DDSS1, LOGL_ERROR, "strange setup-procid 0x%x\n", call->l3_pid);
call->l3_pid = pid;
if (call->state == ISDN_STATE_OUT_CONNECTING || call->state == ISDN_STATE_CONNECT)
call->l3_ces = pid >> 16;
@ -1528,7 +1528,7 @@ int dss1_receive(isdn_t *isdn_ep, uint32_t cmd, uint32_t pid, struct l3_msg *l3m
/* creating call instance, transparent until setup with hdlc */
call = call_create(isdn_ep, DIRECTION_ORIGINATOR, 0, 0, B_MODE_TRANSPARENT);
if (!call) {
PDEBUG(DDSS1, DEBUG_ERROR, "Cannot create call instance.\n");
LOGP(DDSS1, LOGL_ERROR, "Cannot create call instance.\n");
abort();
}
dss1_message(isdn_ep, call, cmd, pid, l3m);
@ -1540,11 +1540,11 @@ int dss1_receive(isdn_t *isdn_ep, uint32_t cmd, uint32_t pid, struct l3_msg *l3m
break;
case MT_FREE:
PDEBUG(DDSS1, DEBUG_DEBUG, "unused L3ID released (pid = 0x%x, call->cc_callref)\n", pid);
LOGP(DDSS1, LOGL_DEBUG, "unused L3ID released (pid = 0x%x, call->cc_callref)\n", pid);
break;
case MT_RELEASE_COMPLETE:
PDEBUG(DDSS1, DEBUG_ERROR, "MT_RELEASE_COMPLETE must be ignored by stack, not sent to app\n");
LOGP(DDSS1, LOGL_ERROR, "MT_RELEASE_COMPLETE must be ignored by stack, not sent to app\n");
break;
case MT_FACILITY:
@ -1553,11 +1553,11 @@ int dss1_receive(isdn_t *isdn_ep, uint32_t cmd, uint32_t pid, struct l3_msg *l3m
case MT_L2IDLE:
// L2 became idle - we could sent a MT_L2RELEASE if we are the L2 master
PDEBUG(DDSS1, DEBUG_DEBUG, "Got L2 idle\n");
LOGP(DDSS1, LOGL_DEBUG, "Got L2 idle\n");
break;
default:
PDEBUG(DDSS1, DEBUG_ERROR, "unhandled message: cmd(0x%x) pid(0x%x)\n", cmd, pid);
LOGP(DDSS1, LOGL_ERROR, "unhandled message: cmd(0x%x) pid(0x%x)\n", cmd, pid);
return -EINVAL;
}
@ -1586,7 +1586,7 @@ void setup_req(call_t *call, osmo_cc_msg_t *msg)
int rc;
struct osmo_cc_helper_audio_codecs *codecs;
PDEBUG(DDSS1, DEBUG_INFO, "SETUP REQUEST\n");
LOGP(DDSS1, LOGL_INFO, "SETUP REQUEST\n");
/* select codec */
if (call->isdn_ep->law == 'a')
@ -1601,12 +1601,12 @@ void setup_req(call_t *call, osmo_cc_msg_t *msg)
return;
}
call->sdp = strdup(sdp);
PDEBUG(DDSS1, DEBUG_INFO, "Codec %s selected for transmission.\n", call->codec->payload_name);
LOGP(DDSS1, LOGL_INFO, "Codec %s selected for transmission.\n", call->codec->payload_name);
/* get channel */
rc = hunt_bchannel_out(call->isdn_ep, &channel, &exclusive);
if (rc < 0) {
PDEBUG(DDSS1, DEBUG_NOTICE, "There is no channel available on the interface.\n");
LOGP(DDSS1, LOGL_NOTICE, "There is no channel available on the interface.\n");
release_and_destroy(call, -rc, 0, 0);
return;
}
@ -1617,11 +1617,11 @@ void setup_req(call_t *call, osmo_cc_msg_t *msg)
/* creating pid */
call->l3_pid = request_new_pid(call->isdn_ep->ml3);
if (call->l3_pid == MISDN_PID_NONE) {
PDEBUG(DDSS1, DEBUG_NOTICE, "There is no free L3ID on the mISDN stack, please restart!\n");
LOGP(DDSS1, LOGL_NOTICE, "There is no free L3ID on the mISDN stack, please restart!\n");
release_and_destroy(call, OSMO_CC_ISDN_CAUSE_RESOURCE_UNAVAIL, 0, 0);
return;
}
PDEBUG(DDSS1, DEBUG_DEBUG, "new L3ID assigned (pid = 0x%x)\n", call->l3_pid);
LOGP(DDSS1, LOGL_DEBUG, "new L3ID assigned (pid = 0x%x)\n", call->l3_pid);
/* creating setup */
l3m = create_l3msg();
@ -1629,7 +1629,7 @@ void setup_req(call_t *call, osmo_cc_msg_t *msg)
/* bearer capability */
rc = osmo_cc_get_ie_bearer(msg, 0, &coding, &capability, &mode);
if (rc < 0) {
PDEBUG(DDSS1, DEBUG_DEBUG, "No bearer capability given, generating from selected codec.\n");
LOGP(DDSS1, LOGL_DEBUG, "No bearer capability given, generating from selected codec.\n");
coding = OSMO_CC_CODING_ITU_T;
if (!strcmp(call->codec->payload_name, "CLEARMODE")) {
capability = OSMO_CC_CAPABILITY_DATA;
@ -1639,7 +1639,7 @@ void setup_req(call_t *call, osmo_cc_msg_t *msg)
mode = OSMO_CC_MODE_CIRCUIT;
}
} else
PDEBUG(DDSS1, DEBUG_DEBUG, "Bearer capability given, override what is defined by selected codec.\n");
LOGP(DDSS1, LOGL_DEBUG, "Bearer capability given, override what is defined by selected codec.\n");
rate = (mode == OSMO_CC_MODE_PACKET) ? 0x00 : 0x10;
if (capability == OSMO_CC_CAPABILITY_AUDIO || capability == OSMO_CC_CAPABILITY_SPEECH) {
has_user = 1;
@ -1760,18 +1760,18 @@ int process_progress(call_t *call, osmo_cc_msg_t *msg, struct l3_msg *l3m, int c
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8)) {
/* if we are sending local tones, we stop them */
if (call->send_local_tones) {
PDEBUG(DDSS1, DEBUG_DEBUG, "Stop sending locally generated tones.\n");
LOGP(DDSS1, LOGL_DEBUG, "Stop sending locally generated tones.\n");
call->send_local_tones = 0;
bchannel_tone(call, 0);
}
PDEBUG(DDSS1, DEBUG_DEBUG, "Using remote tones.\n");
LOGP(DDSS1, LOGL_DEBUG, "Using remote tones.\n");
call->send_remote_tones = 1;
goto finish;
}
/* if we have local tones the first time, send progress indicator */
if (!call->send_local_tones) {
PDEBUG(DDSS1, DEBUG_DEBUG, "Start sending locally generated tones.\n");
LOGP(DDSS1, LOGL_DEBUG, "Start sending locally generated tones.\n");
call->send_local_tones = 1;
coding = OSMO_CC_CODING_ITU_T;
location = call->isdn_ep->serving_location;
@ -1899,7 +1899,7 @@ void setup_ack_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
return;
}
PDEBUG(DDSS1, DEBUG_INFO, "SETUP-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "SETUP-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* creating setup acknowledge */
l3m = create_l3msg();
@ -1943,7 +1943,7 @@ void proc_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg, int with_ies)
return;
call->proceeding_sent = 1;
PDEBUG(DDSS1, DEBUG_INFO, "PROCEEDING REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "PROCEEDING REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* creating proceeding */
l3m = create_l3msg();
@ -2003,7 +2003,7 @@ void alert_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
proc_req(call, pid, msg, 0);
}
PDEBUG(DDSS1, DEBUG_INFO, "ALERTING REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "ALERTING REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* creating alerting */
l3m = create_l3msg();
@ -2060,11 +2060,11 @@ void setup_rsp(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
proc_req(call, pid, msg, 0);
}
PDEBUG(DDSS1, DEBUG_INFO, "CONNECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "CONNECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* stop local tones, if sending until now */
if (call->send_local_tones) {
PDEBUG(DDSS1, DEBUG_INFO, "Stop sending locally generated tones.\n");
LOGP(DDSS1, LOGL_INFO, "Stop sending locally generated tones.\n");
call->send_local_tones = 0;
bchannel_tone(call, 0);
}
@ -2136,7 +2136,7 @@ void setup_comp_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "CONNECT ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "CONNECT ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
new_state(call, ISDN_STATE_CONNECT);
@ -2172,7 +2172,7 @@ void info_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
char dialing[33];
int rc_called, rc_kp;
PDEBUG(DDSS1, DEBUG_INFO, "INFORMATION REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "INFORMATION REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* keypad */
rc_kp = osmo_cc_get_ie_keypad(msg, 0, keypad, sizeof(keypad));
@ -2201,7 +2201,7 @@ void progress_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
struct l3_msg *l3m;
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "PROGRESS REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "PROGRESS REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* creating progress */
l3m = create_l3msg();
@ -2226,7 +2226,7 @@ void notify_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
char display[128];
int rc_notify, rc_redir, rc_display;
PDEBUG(DDSS1, DEBUG_INFO, "NOTIFY REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "NOTIFY REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* notify */
rc_notify = osmo_cc_get_ie_notify(msg, 0, &notify);
@ -2250,7 +2250,7 @@ void notify_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
/* send message to ISDN */
call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_NOTIFY, call->l3_pid, l3m);
} else {
PDEBUG(DDSS1, DEBUG_ERROR, "NOTIFY REQUEST without notification indicator, ignoring.\n");
LOGP(DDSS1, LOGL_ERROR, "NOTIFY REQUEST without notification indicator, ignoring.\n");
}
}
@ -2263,7 +2263,7 @@ void rej_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "REJECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "REJECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* creating release complete */
l3m = create_l3msg();
@ -2306,7 +2306,7 @@ void disc_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
proc_req(call, pid, msg, 0);
}
PDEBUG(DDSS1, DEBUG_INFO, "DISCONNECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "DISCONNECT REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* creating disconnect */
l3m = create_l3msg();
@ -2321,7 +2321,7 @@ void disc_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
/* reset states and handle progress information */
if (call->send_local_tones) {
PDEBUG(DDSS1, DEBUG_DEBUG, "Stop sending locally generated tones.\n");
LOGP(DDSS1, LOGL_DEBUG, "Stop sending locally generated tones.\n");
call->send_local_tones = 0;
bchannel_tone(call, 0);
}
@ -2352,7 +2352,7 @@ void rel_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg)
char display[128];
int rc;
PDEBUG(DDSS1, DEBUG_INFO, "RELEASE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
LOGP(DDSS1, LOGL_INFO, "RELEASE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
/* creating release */
l3m = create_l3msg();
@ -2419,14 +2419,14 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
/* process SETUP */
if (!call) {
if (msg->type != OSMO_CC_MSG_SETUP_REQ) {
PDEBUG(DDSS1, DEBUG_ERROR, "received message without call instance, please fix!\n");
LOGP(DDSS1, LOGL_ERROR, "received message without call instance, please fix!\n");
osmo_cc_free_msg(msg);
return;
}
/* creating call instance, transparent until setup with hdlc */
call = call_create(isdn_ep, DIRECTION_TERMINATOR, 0, 0, B_MODE_TRANSPARENT);
if (!call) {
PDEBUG(DDSS1, DEBUG_ERROR, "Cannot create call instance.\n");
LOGP(DDSS1, LOGL_ERROR, "Cannot create call instance.\n");
abort();
}
/* link with cc */
@ -2540,7 +2540,7 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
rel_req(call, call->l3_pid, msg);
break;
default:
PDEBUG(DDSS1, DEBUG_ERROR, "received an unsupported CC message: %d\n", msg->type);
LOGP(DDSS1, LOGL_ERROR, "received an unsupported CC message: %d\n", msg->type);
}
osmo_cc_free_msg(msg);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
#include <pthread.h>
#include "../libtimer/timer.h"
#include "../libselect/select.h"
#include "../libosmocc/endpoint.h"
#include "../libosmocc/helper.h"
#include <osmocom/core/timer.h>
#include <osmocom/core/select.h>
#include <osmocom/cc/endpoint.h>
#include <osmocom/cc/helper.h>
#include "../libsample/sample.h"
#include "../libjitter/jitter.h"
#include "../libph_socket/ph_socket.h"
@ -113,14 +113,14 @@ typedef struct isdn {
int los, ais, rdi, slip_rx, slip_tx;
int l1link; /* current state */
int l2link; /* current state */
struct timer l2establish_timer;
struct osmo_timer_list l2establish_timer;
int b_num;
int b_reserved;
int b_mode[128];
int b_state[128];
struct isdn_b_sock b_sock[128];
struct call_list *b_call[128];
struct timer b_timer[128];
struct osmo_timer_list b_timer[128];
struct b_timer_inst b_timer_inst[128];
uint8_t b_buffer[128][160];
int b_buffer_pos[128];
@ -132,7 +132,7 @@ typedef struct isdn {
int bridge_portnum;
/* clock for tone on hold */
struct timer clock_timer;
struct osmo_timer_list clock_timer;
double last_time_clock;
} isdn_t;

View File

@ -25,9 +25,10 @@
#include <stdint.h>
#include <stdlib.h>
#include <sched.h>
#include "../libdebug/debug.h"
#include <math.h>
#include "../liblogging/logging.h"
#include "../liboptions/options.h"
#include "../libg711/g711.h"
#include <osmocom/cc/g711.h>
#include <mISDN/mbuffer.h>
#include "isdn.h"
#include "dss1.h"
@ -73,7 +74,7 @@ static void print_help()
printf(" --config [~/]<path to config file>\n");
printf(" Give a config file to use. If it starts with '~/', path is at home dir.\n");
printf(" Each line in config file is one option, '-' or '--' must not be given!\n");
debug_print_help();
logging_print_help();
printf(" --ulaw\n");
printf(" Use U-LAW for b-channel coding instead of alaw.\n");
printf(" -p --port <portnr> | <portname>\n");
@ -190,11 +191,9 @@ static int handle_options(int short_option, int argi, char **argv)
print_help();
return 0;
case 'v':
if (!strcasecmp(argv[argi], "list")) {
debug_list_cat();
rc = parse_logging_opt(argv[argi]);
if (rc > 0)
return 0;
}
rc = parse_debug_opt(argv[argi]);
if (rc < 0) {
fprintf(stderr, "Failed to parse debug option, please use -h for help.\n");
return rc;
@ -298,13 +297,9 @@ void sighandler(int sigset)
static struct mi_ext_fn_s mi_fn;
static int mISDNlib_debug(const char *file, int line, const char *func, int __attribute__((unused)) level, const char *fmt, va_list va)
static int mISDNlib_debug(const char *file, int line, const char __attribute__((unused)) *func, int __attribute__((unused)) level, const char *fmt, va_list va)
{
char text[256];
vsnprintf(text, sizeof(text) - 1, fmt, va);
text[sizeof(text) - 1] = '\0';
// PDEBUG(DDSS1, DEBUG_NOTICE, "libmisdn (file %s, line %d, func %s(), level %d): %s\n", file, line, func, level, text);
_printdebug(file, func, line, DMISDN, DEBUG_NOTICE, NULL, "%s", text);
LOGPSRC(DMISDN, LOGL_NOTICE, file, line, fmt, va);
return 0;
}
@ -317,6 +312,9 @@ int main(int argc, char *argv[])
int layer3_initialized = 0;
struct ph_socket_driver ph_drv;
const char *p;
struct osmo_timer_list mISDN_timer;
logging_init();
g711_init();
@ -380,13 +378,13 @@ int main(int argc, char *argv[])
/* init instance */
rc = isdn_initialize(isdn_ep, (misdn_user) ? &ph_drv.ph_socket : NULL, law, portname, ntmode, ptp, layer1hold, layer2hold, channel_out, channel_in, timeouts, tx_delay, local_tones, serving_location);
if (rc) {
PDEBUG(DISDN, DEBUG_ERROR, "mISDN initializing failed!\n");
LOGP(DISDN, LOGL_ERROR, "mISDN initializing failed!\n");
goto error;
}
rc = isdn_open(isdn_ep);
if (rc) {
PDEBUG(DISDN, DEBUG_ERROR, "mISDN open failed!\n");
LOGP(DISDN, LOGL_ERROR, "mISDN open failed!\n");
goto error;
}
@ -397,6 +395,9 @@ int main(int argc, char *argv[])
if (rc < 0)
goto error;
/* Dummy timer to interrupt osmo_select_main when mISDN timer fires before anything else. */
osmo_timer_setup(&mISDN_timer, NULL, NULL);
/* real time priority */
if (rt_prio > 0) {
struct sched_param schedp;
@ -416,7 +417,7 @@ int main(int argc, char *argv[])
while (!quit) {
int work;
double timeout, misdn_timeout = 0.0;
double misdn_timeout = 0.0;
do {
work = 0;
@ -427,18 +428,11 @@ int main(int argc, char *argv[])
work |= work_layer3(isdn_ep->ml3, &misdn_timeout);
}
} while (work);
/* handle all timers
* timeout is 0, if there was an event
* -> handle FDs without waiting, continue this loop
* timeout is not 0, if there was no event
* -> wait until FD or timeout
*/
timeout = process_timer();
/* reduce timer, if mISDN timer hits earlier */
if (misdn_timeout > 0.0 && misdn_timeout < timeout)
timeout = misdn_timeout;
/* wait for FD event until given timeout */
osmo_fd_select(timeout);
/* wait for event or stop, if mISDN_timer fires */
if (misdn_timeout)
osmo_timer_schedule(&mISDN_timer, floor(misdn_timeout), (misdn_timeout - floor(misdn_timeout)) * 1000000);
osmo_select_main(0);
osmo_timer_del(&mISDN_timer);
}
signal(SIGINT, SIG_DFL);

View File

@ -21,8 +21,8 @@
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include "../libtimer/timer.h"
#include "../libselect/select.h"
#include <osmocom/core/timer.h>
#include <osmocom/core/select.h>
#include "../libph_socket/ph_socket.h"
#include "ph_driver.h"
#define __MISDNL1L2__

View File

@ -17,8 +17,8 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stddef.h>
#include "../libdebug/debug.h"
#include "../libg711/g711.h"
#include "../liblogging/logging.h"
#include <osmocom/cc/g711.h>
#include <mISDN/mbuffer.h>
#include "tones.h"
@ -452,10 +452,10 @@ int isdn_tone_set(struct isdn_tone *t, int tone)
i++;
}
if (!pat) {
PDEBUG(DISDN, DEBUG_ERROR, "given tone 0x%x is invalid\n", tone);
LOGP(DISDN, LOGL_ERROR, "given tone 0x%x is invalid\n", tone);
return -EINVAL;
}
PDEBUG(DISDN, DEBUG_DEBUG, "playing given tone 0x%x\n", tone);
LOGP(DISDN, LOGL_DEBUG, "playing given tone 0x%x\n", tone);
t->tone = tone;
t->pattern = pat;
t->index = 0;

View File

@ -1,7 +0,0 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
noinst_LIBRARIES = libdebug.a
libdebug_a_SOURCES = \
debug.c

View File

@ -1,331 +0,0 @@
/* Simple debug functions for level and category filtering
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <math.h>
#include <time.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include "debug.h"
const char *debug_level[] = {
"debug ",
"info ",
"notice ",
"error ",
NULL,
};
struct debug_cat {
const char *name;
const char *color;
} debug_cat[] = {
{ "options", "\033[0;33m" },
{ "sender", "\033[1;33m" },
{ "sound", "\033[0;35m" },
{ "dsp", "\033[0;31m" },
{ "anetz", "\033[1;34m" },
{ "bnetz", "\033[1;34m" },
{ "cnetz", "\033[1;34m" },
{ "nmt", "\033[1;34m" },
{ "amps", "\033[1;34m" },
{ "r2000", "\033[1;34m" },
{ "imts", "\033[1;34m" },
{ "mpt1327", "\033[1;34m" },
{ "jollycom", "\033[1;34m" },
{ "eurosignal", "\033[1;34m" },
{ "pocsag", "\033[1;34m" },
{ "golay", "\033[1;34m" },
{ "5-ton-folge", "\033[1;34m" },
{ "frame", "\033[0;36m" },
{ "call", "\033[0;37m" },
{ "cc", "\033[1;32m" },
{ "database", "\033[0;33m" },
{ "transaction", "\033[0;32m" },
{ "dms", "\033[0;33m" },
{ "sms", "\033[1;37m" },
{ "sdr", "\033[1;31m" },
{ "uhd", "\033[1;35m" },
{ "soapy", "\033[1;35m" },
{ "wave", "\033[1;33m" },
{ "radio", "\033[1;34m" },
{ "am791x", "\033[0;31m" },
{ "uart", "\033[0;32m" },
{ "device", "\033[0;33m" },
{ "datenklo", "\033[1;34m" },
{ "zeit", "\033[1;34m" },
{ "sim layer 1", "\033[0;31m" },
{ "sim layer 2", "\033[0;33m" },
{ "sim ICL layer", "\033[0;36m" },
{ "sim layer 7", "\033[0;37m" },
{ "mtp layer 2", "\033[1;33m" },
{ "mtp layer 3", "\033[1;36m" },
{ "MuP", "\033[1;37m" },
{ "router", "\033[1;35m" },
{ "stderr", "\033[1;37m" },
{ "ss5", "\033[1;34m" },
{ "r1", "\033[1;34m" },
{ "isdn", "\033[1;35m" },
{ "misdn", "\033[0;34m" },
{ "dss1", "\033[1;34m" },
{ "sip", "\033[1;35m" },
{ "telephone", "\033[1;34m" },
{ "uk0", "\033[1;34m" },
{ "ph", "\033[0;33m" },
{ "dcf77", "\033[1;34m" },
{ "jitter", "\033[0;36m" },
{ NULL, NULL }
};
int debuglevel = DEBUG_INFO;
int debug_date = 0;
uint64_t debug_mask[2] = { ~0, ~0 };
extern int num_kanal;
void (*clear_console_text)(void) = NULL;
void (*print_console_text)(void) = NULL;
int debug_limit_scroll = 0;
static int lock_initialized = 0;
static pthread_mutex_t debug_mutex;
void lock_debug(void)
{
int rc;
if (!lock_initialized) {
rc = pthread_mutex_init(&debug_mutex, NULL);
if (rc == 0)
lock_initialized = 1;
}
if (lock_initialized)
pthread_mutex_lock(&debug_mutex);
}
void unlock_debug(void)
{
if (lock_initialized)
pthread_mutex_unlock(&debug_mutex);
}
void get_win_size(int *w, int *h)
{
struct winsize win;
int rc;
rc = ioctl(0, TIOCGWINSZ, &win);
if (rc) {
*w = 80;
*h = 25;
return;
}
*h = win.ws_row;
*w = win.ws_col;
}
void _printdebug(const char *file, const char __attribute__((unused)) *function, int line, int cat, int level, const char *kanal, const char *fmt, ...)
{
char buffer[4096], *b = buffer;
int s = sizeof(buffer) - 1;
const char *p;
va_list args;
int w, h = 0; // make GCC happy
if (debuglevel > level)
return;
if (!(debug_mask[cat >> 6] & ((uint64_t)1 << (cat & 63))))
return;
lock_debug();
buffer[sizeof(buffer) - 1] = '\0';
/* if kanal is used, prefix the channel number */
if (num_kanal > 1 && kanal) {
sprintf(buffer, "(chan %s) ", kanal);
b = strchr(buffer, '\0');
s -= strlen(buffer);
}
va_start(args, fmt);
vsnprintf(b, s, fmt, args);
va_end(args);
while ((p = strchr(file, '/')))
file = p + 1;
if (clear_console_text)
clear_console_text();
if (debug_limit_scroll) {
get_win_size(&w, &h);
printf("\0337\033[%d;%dr\0338", debug_limit_scroll + 1, h);
}
if (debug_date) {
struct timeval tv;
struct tm *tm;
gettimeofday(&tv, NULL);
tm = localtime(&tv.tv_sec);
printf("%04d-%02d-%02d %02d:%02d:%02d.%03d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 10000.0));
}
printf("%s%s %4d %s-%s: %s\033[0;39m", debug_cat[cat].color, file, line, debug_cat[cat].name, debug_level[level], buffer);
if (debug_limit_scroll)
printf("\0337\033[%d;%dr\0338", 1, h);
if (print_console_text)
print_console_text();
fflush(stdout);
unlock_debug();
}
const char *debug_amplitude(double level)
{
static char text[42];
strcpy(text, " : ");
if (level > 1.0)
level = 1.0;
if (level < -1.0)
level = -1.0;
text[20 + (int)(level * 20)] = '*';
return text;
}
#define level2db(level) (20 * log10(level))
const char *debug_db(double level_db)
{
static char text[128];
int l;
strcpy(text, ": . : . : . : . : . : . : . : . | . : . : . : . : . : . : . : . :");
if (level_db <= 0.0)
return text;
l = (int)round(level2db(level_db));
if (l > 48)
return text;
if (l < -48)
return text;
text[l + 48] = '*';
return text;
}
void debug_print_help(void)
{
printf(" -v --verbose <level> | <level>,<category>[,<category>[,...]] | list\n");
printf(" Use 'list' to get a list of all levels and categories\n");
printf(" Verbose level: digit of debug level (default = '%d')\n", debuglevel);
printf(" Verbose level+category: level digit followed by one or more categories\n");
printf(" -> If no category is specified, all categories are selected\n");
printf(" -v --verbose date\n");
printf(" Show date with debug output\n");
}
void debug_list_cat(void)
{
int i;
printf("Give number of debug level:\n");
for (i = 0; debug_level[i]; i++)
printf(" %d = %s\n", i, debug_level[i]);
printf("\n");
printf("Give name(s) of debug category:\n");
for (i = 0; debug_cat[i].name; i++)
printf(" %s%s\033[0;39m\n", debug_cat[i].color, debug_cat[i].name);
printf("\n");
}
int parse_debug_opt(const char *optarg)
{
int i, max_level = 0;
char *dup, *dstring, *p;
if (!strcasecmp(optarg, "date")) {
debug_date = 1;
return 0;
}
for (i = 0; debug_level[i]; i++)
max_level = i;
dup = dstring = strdup(optarg);
p = strsep(&dstring, ",");
for (i = 0; i < p[i]; i++) {
if (p[i] < '0' || p[i] > '9') {
fprintf(stderr, "Only digits are allowed for debug level!\n");
free(dup);
return -EINVAL;
}
}
debuglevel = atoi(p);
if (debuglevel > max_level) {
fprintf(stderr, "Debug level too high, use 'list' to show available levels!\n");
free(dup);
return -EINVAL;
}
if (dstring)
memset(debug_mask, 0, sizeof(debug_mask));
while((p = strsep(&dstring, ","))) {
for (i = 0; debug_cat[i].name; i++) {
if (!strcasecmp(p, debug_cat[i].name))
break;
}
if (!debug_cat[i].name) {
fprintf(stderr, "Given debug category '%s' unknown, use 'list' to show available categories!\n", p);
free(dup);
return -EINVAL;
}
debug_mask[i >> 6] |= ((uint64_t)1 << (i & 63));
}
free(dup);
return 0;
}
const char *debug_hex(const uint8_t *data, int len)
{
static char *text = NULL;
char *p;
int i;
if (text)
free(text);
p = text = calloc(1, len * 3 + 1);
for (i = 0; i < len; i++) {
sprintf(p, "%02x ", *data++);
p += 3;
}
if (text[0])
p[-1] = '\0';
return text;
}

View File

@ -1,94 +0,0 @@
#define DEBUG_DEBUG 0 /* debug info, not for normal use */
#define DEBUG_INFO 1 /* all info about process */
#define DEBUG_NOTICE 2 /* something unexpected happens */
#define DEBUG_ERROR 3 /* there is an error with this software */
#define DOPTIONS 0
#define DSENDER 1
#define DSOUND 2
#define DDSP 3
#define DANETZ 4
#define DBNETZ 5
#define DCNETZ 6
#define DNMT 7
#define DAMPS 8
#define DR2000 9
#define DIMTS 10
#define DMPT1327 11
#define DJOLLY 12
#define DEURO 13
#define DPOCSAG 14
#define DGOLAY 15
#define DFUENF 16
#define DFRAME 17
#define DCALL 18
#define DCC 19
#define DDB 20
#define DTRANS 21
#define DDMS 22
#define DSMS 23
#define DSDR 24
#define DUHD 25
#define DSOAPY 26
#define DWAVE 27
#define DRADIO 28
#define DAM791X 29
#define DUART 30
#define DDEVICE 31
#define DDATENKLO 32
#define DZEIT 33
#define DSIM1 34
#define DSIM2 35
#define DSIMI 36
#define DSIM7 37
#define DMTP2 38
#define DMTP3 39
#define DMUP 40
#define DROUTER 41
#define DSTDERR 42
#define DSS5 43
#define DR1 44
#define DISDN 45
#define DMISDN 46
#define DDSS1 47
#define DSIP 48
#define DTEL 49
#define DUK0 50
#define DPH 51
#define DDCF77 52
#define DJITTER 53
//NOTE: increment mask array, if 127 is exceeded
void lock_debug(void);
void unlock_debug(void);
void get_win_size(int *w, int *h);
#define PDEBUG(cat, level, fmt, arg...) _printdebug(__FILE__, __FUNCTION__, __LINE__, cat, level, NULL, fmt, ## arg)
#define PDEBUG_CHAN(cat, level, fmt, arg...) _printdebug(__FILE__, __FUNCTION__, __LINE__, cat, level, CHAN, fmt, ## arg)
void _printdebug(const char *file, const char *function, int line, int cat, int level, const char *chan_str, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 7, 8)));
const char *debug_amplitude(double level);
const char *debug_db(double level_db);
void debug_print_help(void);
void debug_list_cat(void);
int parse_debug_opt(const char *opt);
extern int debuglevel;
extern void (*clear_console_text)(void);
extern void (*print_console_text)(void);
extern int debug_limit_scroll;
const char *debug_hex(const uint8_t *data, int len);
#define LOGP PDEBUG
#define LOGL_DEBUG DEBUG_DEBUG
#define LOGL_INFO DEBUG_INFO
#define LOGL_NOTICE DEBUG_NOTICE
#define LOGL_ERROR DEBUG_ERROR
#define osmo_hexdump debug_hex

View File

@ -1,7 +0,0 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
noinst_LIBRARIES = libg711.a
libg711_a_SOURCES = \
g711.c

View File

@ -1,537 +0,0 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg (GPL) **
** **
** audio conversions for alaw and ulaw **
** **
\*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
/* ulaw -> signed 16-bit */
static int16_t g711_ulaw_to_linear[256] =
{
0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0xffff,
0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
};
/* alaw -> signed 16-bit */
static int16_t g711_alaw_flipped_to_linear[256] =
{
0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
};
/* Xlaw -> signed 16-bit */
static int16_t g711_alaw_to_linear[256];
static int16_t g711_ulaw_flipped_to_linear[256];
/* signed 16-bit -> Xlaw */
static uint8_t g711_linear_to_alaw_flipped[65536];
static uint8_t g711_linear_to_ulaw_flipped[65536];
static uint8_t g711_linear_to_alaw[65536];
static uint8_t g711_linear_to_ulaw[65536];
/* transcode */
static uint8_t g711_alaw_to_ulaw[256];
static uint8_t g711_ulaw_to_alaw[256];
static uint8_t g711_alaw_flipped_to_ulaw[256];
static uint8_t g711_ulaw_flipped_to_alaw[256];
static uint8_t g711_alaw_to_ulaw_flipped[256];
static uint8_t g711_ulaw_to_alaw_flipped[256];
/* table is used to generate linear_to_alaw */
static int16_t g711_alaw_relations[] =
{
0x8684, 0x55, 0x8a84, 0xd5, 0x8e84, 0x15, 0x9284, 0x95,
0x9684, 0x75, 0x9a84, 0xf5, 0x9e84, 0x35, 0xa284, 0xb5,
0xa684, 0x45, 0xaa84, 0xc5, 0xae84, 0x05, 0xb284, 0x85,
0xb684, 0x65, 0xba84, 0xe5, 0xbe84, 0x25, 0xc184, 0xa5,
0xc384, 0x5d, 0xc584, 0xdd, 0xc784, 0x1d, 0xc984, 0x9d,
0xcb84, 0x7d, 0xcd84, 0xfd, 0xcf84, 0x3d, 0xd184, 0xbd,
0xd384, 0x4d, 0xd584, 0xcd, 0xd784, 0x0d, 0xd984, 0x8d,
0xdb84, 0x6d, 0xdd84, 0xed, 0xdf84, 0x2d, 0xe104, 0xad,
0xe204, 0x51, 0xe304, 0xd1, 0xe404, 0x11, 0xe504, 0x91,
0xe604, 0x71, 0xe704, 0xf1, 0xe804, 0x31, 0xe904, 0xb1,
0xea04, 0x41, 0xeb04, 0xc1, 0xec04, 0x01, 0xed04, 0x81,
0xee04, 0x61, 0xef04, 0xe1, 0xf004, 0x21, 0xf0c4, 0x59,
0xf0c4, 0xa1, 0xf144, 0xd9, 0xf1c4, 0x19, 0xf244, 0x99,
0xf2c4, 0x79, 0xf344, 0xf9, 0xf3c4, 0x39, 0xf444, 0xb9,
0xf4c4, 0x49, 0xf544, 0xc9, 0xf5c4, 0x09, 0xf644, 0x89,
0xf6c4, 0x69, 0xf744, 0xe9, 0xf7c4, 0x29, 0xf844, 0x57,
0xf844, 0xa9, 0xf8a4, 0xd7, 0xf8e4, 0x17, 0xf924, 0x97,
0xf964, 0x77, 0xf9a4, 0xf7, 0xf9e4, 0x37, 0xfa24, 0xb7,
0xfa64, 0x47, 0xfaa4, 0xc7, 0xfae4, 0x07, 0xfb24, 0x87,
0xfb64, 0x67, 0xfba4, 0xe7, 0xfbe4, 0x27, 0xfc24, 0x5f,
0xfc24, 0xa7, 0xfc64, 0x1f, 0xfc64, 0xdf, 0xfc94, 0x9f,
0xfcb4, 0x7f, 0xfcd4, 0xff, 0xfcf4, 0x3f, 0xfd14, 0xbf,
0xfd34, 0x4f, 0xfd54, 0xcf, 0xfd74, 0x0f, 0xfd94, 0x8f,
0xfdb4, 0x6f, 0xfdd4, 0xef, 0xfdf4, 0x2f, 0xfe14, 0x53,
0xfe14, 0xaf, 0xfe34, 0x13, 0xfe34, 0xd3, 0xfe54, 0x73,
0xfe54, 0x93, 0xfe74, 0x33, 0xfe74, 0xf3, 0xfe8c, 0xb3,
0xfe9c, 0x43, 0xfeac, 0xc3, 0xfebc, 0x03, 0xfecc, 0x83,
0xfedc, 0x63, 0xfeec, 0xe3, 0xfefc, 0x23, 0xff0c, 0xa3,
0xff1c, 0x5b, 0xff2c, 0xdb, 0xff3c, 0x1b, 0xff4c, 0x9b,
0xff5c, 0x7b, 0xff6c, 0xfb, 0xff7c, 0x3b, 0xff88, 0xbb,
0xff98, 0x4b, 0xffa8, 0xcb, 0xffb8, 0x0b, 0xffc8, 0x8b,
0xffd8, 0x6b, 0xffe8, 0xeb, 0xfff8, 0x2b, 0xfff8, 0xab,
0x0008, 0x2a, 0x0008, 0xaa, 0x0018, 0xea, 0x0028, 0x6a,
0x0038, 0x8a, 0x0048, 0x0a, 0x0058, 0xca, 0x0068, 0x4a,
0x0078, 0xba, 0x0084, 0x3a, 0x0094, 0xfa, 0x00a4, 0x7a,
0x00b4, 0x9a, 0x00c4, 0x1a, 0x00d4, 0xda, 0x00e4, 0x5a,
0x00f4, 0xa2, 0x0104, 0x22, 0x0114, 0xe2, 0x0124, 0x62,
0x0134, 0x82, 0x0144, 0x02, 0x0154, 0xc2, 0x0164, 0x42,
0x0174, 0xb2, 0x018c, 0x32, 0x018c, 0xf2, 0x01ac, 0x72,
0x01ac, 0x92, 0x01cc, 0x12, 0x01cc, 0xd2, 0x01ec, 0x52,
0x01ec, 0xae, 0x020c, 0x2e, 0x022c, 0xee, 0x024c, 0x6e,
0x026c, 0x8e, 0x028c, 0x0e, 0x02ac, 0xce, 0x02cc, 0x4e,
0x02ec, 0xbe, 0x030c, 0x3e, 0x032c, 0xfe, 0x034c, 0x7e,
0x036c, 0x9e, 0x039c, 0x1e, 0x039c, 0xde, 0x03dc, 0x5e,
0x03dc, 0xa6, 0x041c, 0x26, 0x045c, 0xe6, 0x049c, 0x66,
0x04dc, 0x86, 0x051c, 0x06, 0x055c, 0xc6, 0x059c, 0x46,
0x05dc, 0xb6, 0x061c, 0x36, 0x065c, 0xf6, 0x069c, 0x76,
0x06dc, 0x96, 0x071c, 0x16, 0x075c, 0xd6, 0x07bc, 0x56,
0x07bc, 0xa8, 0x083c, 0x28, 0x08bc, 0xe8, 0x093c, 0x68,
0x09bc, 0x88, 0x0a3c, 0x08, 0x0abc, 0xc8, 0x0b3c, 0x48,
0x0bbc, 0xb8, 0x0c3c, 0x38, 0x0cbc, 0xf8, 0x0d3c, 0x78,
0x0dbc, 0x98, 0x0e3c, 0x18, 0x0ebc, 0xd8, 0x0f3c, 0x58,
0x0f3c, 0xa0, 0x0ffc, 0x20, 0x10fc, 0xe0, 0x11fc, 0x60,
0x12fc, 0x80, 0x13fc, 0x00, 0x14fc, 0xc0, 0x15fc, 0x40,
0x16fc, 0xb0, 0x17fc, 0x30, 0x18fc, 0xf0, 0x19fc, 0x70,
0x1afc, 0x90, 0x1bfc, 0x10, 0x1cfc, 0xd0, 0x1dfc, 0x50,
0x1efc, 0xac, 0x207c, 0x2c, 0x227c, 0xec, 0x247c, 0x6c,
0x267c, 0x8c, 0x287c, 0x0c, 0x2a7c, 0xcc, 0x2c7c, 0x4c,
0x2e7c, 0xbc, 0x307c, 0x3c, 0x327c, 0xfc, 0x347c, 0x7c,
0x367c, 0x9c, 0x387c, 0x1c, 0x3a7c, 0xdc, 0x3c7c, 0x5c,
0x3e7c, 0xa4, 0x417c, 0x24, 0x457c, 0xe4, 0x497c, 0x64,
0x4d7c, 0x84, 0x517c, 0x04, 0x557c, 0xc4, 0x597c, 0x44,
0x5d7c, 0xb4, 0x617c, 0x34, 0x657c, 0xf4, 0x697c, 0x74,
0x6d7c, 0x94, 0x717c, 0x14, 0x757c, 0xd4, 0x797c, 0x54
};
uint8_t g711_flip[256];
static int g711_initialized = 0;
/* generate tables
*/
void g711_init(void)
{
int i, j;
/* flip tables */
for (i = 0; i < 256; i++) {
g711_flip[i]
= ((i & 1) << 7)
+ ((i & 2) << 5)
+ ((i & 4) << 3)
+ ((i & 8) << 1)
+ ((i & 16) >> 1)
+ ((i & 32) >> 3)
+ ((i & 64) >> 5)
+ ((i & 128) >> 7);
g711_alaw_to_linear[i] = g711_alaw_flipped_to_linear[g711_flip[i]];
g711_ulaw_flipped_to_linear[i] = g711_ulaw_to_linear[g711_flip[i]];
}
/* linear to alaw tables */
i = j = 0;
while(i < 65536) {
if (i - 32768 > g711_alaw_relations[j << 1])
j++;
if (j > 255)
j = 255;
g711_linear_to_alaw_flipped[(i - 32768) & 0xffff] = g711_alaw_relations[(j << 1) | 1];
g711_linear_to_alaw[(i - 32768) & 0xffff] = g711_flip[g711_alaw_relations[(j << 1) | 1]];
i++;
}
/* linear to ulaw tables */
i = j = 0;
while(i < 32768) {
if (i - 32768 > g711_ulaw_to_linear[j])
j++;
g711_linear_to_ulaw[(i - 32768) & 0xffff] = j;
g711_linear_to_ulaw_flipped[(i - 32768) & 0xffff] = g711_flip[j];
i++;
}
j = 255;
while(i < 65536) {
if (i - 32768 > g711_ulaw_to_linear[j])
j--;
g711_linear_to_ulaw[(i - 32768) & 0xffff] = j;
g711_linear_to_ulaw_flipped[(i - 32768) & 0xffff] = g711_flip[j];
i++;
}
/* transcode */
for (i = 0; i < 256; i++) {
g711_alaw_to_ulaw[i] = g711_linear_to_ulaw[(uint16_t)g711_alaw_to_linear[i]];
g711_ulaw_to_alaw[i] = g711_linear_to_alaw[(uint16_t)g711_ulaw_to_linear[i]];
g711_alaw_flipped_to_ulaw[i] = g711_linear_to_ulaw[(uint16_t)g711_alaw_to_linear[g711_flip[i]]];
g711_ulaw_flipped_to_alaw[i] = g711_linear_to_alaw[(uint16_t)g711_ulaw_to_linear[g711_flip[i]]];
g711_alaw_to_ulaw_flipped[i] = g711_flip[g711_linear_to_ulaw[(uint16_t)g711_alaw_to_linear[i]]];
g711_ulaw_to_alaw_flipped[i] = g711_flip[g711_linear_to_alaw[(uint16_t)g711_ulaw_to_linear[i]]];
}
g711_initialized = 1;
}
void g711_encode_alaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
int16_t *src = (int16_t *)src_data;
uint8_t *dst;
int len = src_len / 2, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_linear_to_alaw_flipped[(uint16_t)src[i]];
*dst_data = dst;
*dst_len = len;
}
void g711_encode_ulaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
int16_t *src = (int16_t *)src_data;
uint8_t *dst;
int len = src_len / 2, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_linear_to_ulaw_flipped[(uint16_t)src[i]];
*dst_data = dst;
*dst_len = len;
}
void g711_decode_alaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
uint8_t *src = src_data;
int16_t *dst;
int len = src_len, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len * 2);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_alaw_flipped_to_linear[src[i]];
*dst_data = (uint8_t *)dst;
*dst_len = len * 2;
}
void g711_decode_ulaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
uint8_t *src = src_data;
int16_t *dst;
int len = src_len, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len * 2);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_ulaw_flipped_to_linear[src[i]];
*dst_data = (uint8_t *)dst;
*dst_len = len * 2;
}
void g711_encode_alaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
int16_t *src = (int16_t *)src_data;
uint8_t *dst;
int len = src_len / 2, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_linear_to_alaw[(uint16_t)src[i]];
*dst_data = dst;
*dst_len = len;
}
void g711_encode_ulaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
int16_t *src = (int16_t *)src_data;
uint8_t *dst;
int len = src_len / 2, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_linear_to_ulaw[(uint16_t)src[i]];
*dst_data = dst;
*dst_len = len;
}
void g711_decode_alaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
uint8_t *src = src_data;
int16_t *dst;
int len = src_len, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len * 2);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_alaw_to_linear[src[i]];
*dst_data = (uint8_t *)dst;
*dst_len = len * 2;
}
void g711_decode_ulaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
uint8_t *src = src_data;
int16_t *dst;
int len = src_len, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len * 2);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_ulaw_to_linear[src[i]];
*dst_data = (uint8_t *)dst;
*dst_len = len * 2;
}
void g711_transcode_alaw_to_ulaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
uint8_t *src = src_data, *dst;
int len = src_len, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_alaw_to_ulaw[src[i]];
*dst_data = dst;
*dst_len = len;
}
void g711_transcode_alaw_flipped_to_ulaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
uint8_t *src = src_data, *dst;
int len = src_len, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_alaw_flipped_to_ulaw[src[i]];
*dst_data = dst;
*dst_len = len;
}
void g711_transcode_alaw_to_ulaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
uint8_t *src = src_data, *dst;
int len = src_len, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_alaw_to_ulaw_flipped[src[i]];
*dst_data = dst;
*dst_len = len;
}
void g711_transcode_ulaw_to_alaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
uint8_t *src = src_data, *dst;
int len = src_len, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_ulaw_to_alaw[src[i]];
*dst_data = dst;
*dst_len = len;
}
void g711_transcode_ulaw_flipped_to_alaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
uint8_t *src = src_data, *dst;
int len = src_len, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_ulaw_flipped_to_alaw[src[i]];
*dst_data = dst;
*dst_len = len;
}
void g711_transcode_ulaw_to_alaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
uint8_t *src = src_data, *dst;
int len = src_len, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_ulaw_to_alaw_flipped[src[i]];
*dst_data = dst;
*dst_len = len;
}
void g711_transcode_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
{
uint8_t *src = src_data, *dst;
int len = src_len, i;
if (!g711_initialized) {
fprintf(stderr, "G711 codec not initialized! Please fix!\n");
abort();
}
dst = malloc(len);
if (!dst)
return;
for (i = 0; i < len; i++)
dst[i] = g711_flip[src[i]];
*dst_data = dst;
*dst_len = len;
}

View File

@ -1,17 +0,0 @@
void g711_init(void);
void g711_encode_alaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_encode_ulaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_decode_alaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_decode_ulaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_encode_alaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_encode_ulaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_decode_alaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_decode_ulaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_transcode_alaw_to_ulaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_transcode_alaw_flipped_to_ulaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_transcode_alaw_to_ulaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_transcode_ulaw_to_alaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_transcode_ulaw_flipped_to_alaw(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_transcode_ulaw_to_alaw_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void g711_transcode_flipped(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);

View File

@ -77,7 +77,7 @@
#include <errno.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#include "jitter.h"
#define INITIAL_DELAY_INTERVAL 0.5
@ -104,7 +104,7 @@ int jitter_create(jitter_t *jb, const char *name, double samplerate, int sample_
jb->extra_size = (int)(EXTRA_BUFFER * samplerate);
jb->extra_samples = calloc(sample_size, jb->extra_size);
if (!jb->extra_samples) {
PDEBUG(DJITTER, DEBUG_ERROR, "No memory for frame.\n");
LOGP(DJITTER, LOGL_ERROR, "No memory for frame.\n");
rc = -ENOMEM;
goto error;
}
@ -118,7 +118,7 @@ int jitter_create(jitter_t *jb, const char *name, double samplerate, int sample_
jitter_reset(jb);
PDEBUG(DJITTER, DEBUG_INFO, "%sCreated jitter buffer. (samplerate=%.0f, target_window=%.0fms, max_window=%.0fms, flag:latency=%s flag:repeat=%s)\n", jb->name, samplerate, target_window_duration * 1000.0, max_window_duration * 1000.0, (window_flags & JITTER_FLAG_LATENCY) ? "true" : "false", (window_flags & JITTER_FLAG_REPEAT) ? "true" : "false");
LOGP(DJITTER, LOGL_INFO, "%sCreated jitter buffer. (samplerate=%.0f, target_window=%.0fms, max_window=%.0fms, flag:latency=%s flag:repeat=%s)\n", jb->name, samplerate, target_window_duration * 1000.0, max_window_duration * 1000.0, (window_flags & JITTER_FLAG_LATENCY) ? "true" : "false", (window_flags & JITTER_FLAG_REPEAT) ? "true" : "false");
error:
if (rc)
@ -139,7 +139,7 @@ void jitter_reset(jitter_t *jb)
{
jitter_frame_t *jf, *temp;
PDEBUG(DJITTER, DEBUG_INFO, "%sReset jitter buffer.\n", jb->name);
LOGP(DJITTER, LOGL_INFO, "%sReset jitter buffer.\n", jb->name);
/* jitter buffer locked */
jb->unlocked = 0;
@ -172,7 +172,7 @@ void jitter_destroy(jitter_t *jb)
{
jitter_reset(jb);
PDEBUG(DJITTER, DEBUG_INFO, "%sDestroying jitter buffer.\n", jb->name);
LOGP(DJITTER, LOGL_INFO, "%sDestroying jitter buffer.\n", jb->name);
if (jb->extra_samples) {
free(jb->extra_samples);
@ -201,7 +201,7 @@ void jitter_save(jitter_t *jb, void *samples, int length, int has_sequence, uint
/* generate sequence and timestamp automatically, if enabled */
if (!has_sequence) {
#ifdef DEBUG_JITTER
PDEBUG(DJITTER, DEBUG_DEBUG, "%sSave frame of %d samples (no seqence).\n", jb->name, length);
LOGP(DJITTER, LOGL_DEBUG, "%sSave frame of %d samples (no seqence).\n", jb->name, length);
#endif
sequence = jb->next_sequence;
jb->next_sequence++;
@ -210,7 +210,7 @@ void jitter_save(jitter_t *jb, void *samples, int length, int has_sequence, uint
ssrc = jb->window_ssrc;
} else {
#ifdef HEAVY_DEBUG
PDEBUG(DJITTER, DEBUG_DEBUG, "%sSave frame of %d samples (seqence=%u timestamp=%u ssrc=0x%02x).\n", jb->name, length, sequence, timestamp, ssrc);
LOGP(DJITTER, LOGL_DEBUG, "%sSave frame of %d samples (seqence=%u timestamp=%u ssrc=0x%02x).\n", jb->name, length, sequence, timestamp, ssrc);
#endif
jb->next_sequence = sequence + 1;
jb->next_timestamp = timestamp + length;
@ -219,9 +219,9 @@ void jitter_save(jitter_t *jb, void *samples, int length, int has_sequence, uint
/* first packet (with this ssrc) sets window size to target_window_size */
if (!jb->window_valid || jb->window_ssrc != ssrc) {
if (!jb->window_valid)
PDEBUG(DJITTER, DEBUG_DEBUG, "%s Initial frame after init or reset.\n", jb->name);
LOGP(DJITTER, LOGL_DEBUG, "%s Initial frame after init or reset.\n", jb->name);
else
PDEBUG(DJITTER, DEBUG_DEBUG, "%s SSRC changed.\n", jb->name);
LOGP(DJITTER, LOGL_DEBUG, "%s SSRC changed.\n", jb->name);
// NOTE: Reset must be called before finding the frame location below, because there will be no frame in list anymore!
jitter_reset(jb);
jb->unlocked = 1;
@ -241,7 +241,7 @@ void jitter_save(jitter_t *jb, void *samples, int length, int has_sequence, uint
offset_sequence = (int16_t)(sequence - (*jfp)->sequence);
/* found double entry */
if (offset_sequence == 0) {
PDEBUG(DJITTER, DEBUG_DEBUG, "%s Dropping double packet (sequence = %d)\n", jb->name, sequence);
LOGP(DJITTER, LOGL_DEBUG, "%s Dropping double packet (sequence = %d)\n", jb->name, sequence);
return;
}
/* offset is negative, so we found the position to insert frame */
@ -252,7 +252,7 @@ void jitter_save(jitter_t *jb, void *samples, int length, int has_sequence, uint
offset_timestamp = timestamp - jb->window_timestamp;
#ifdef HEAVY_DEBUG
PDEBUG(DJITTER, DEBUG_DEBUG, "%sFrame has offset of %.0fms in jitter buffer.\n", jb->name, (double)offset_timestamp * jb->sample_duration * 1000.0);
LOGP(DJITTER, LOGL_DEBUG, "%sFrame has offset of %.0fms in jitter buffer.\n", jb->name, (double)offset_timestamp * jb->sample_duration * 1000.0);
#endif
/* measure delay */
@ -262,11 +262,11 @@ void jitter_save(jitter_t *jb, void *samples, int length, int has_sequence, uint
/* if frame is too early (delay ceases), shift window to the future */
if (offset_timestamp > jb->max_window_size) {
if ((jb->window_flags & JITTER_FLAG_LATENCY)) {
PDEBUG(DJITTER, DEBUG_DEBUG, "%s Frame too early: Shift jitter buffer to the future, to make the frame fit to the end. (offset_timestamp(%d) > max_window_size(%d))\n", jb->name, offset_timestamp, jb->max_window_size);
LOGP(DJITTER, LOGL_DEBUG, "%s Frame too early: Shift jitter buffer to the future, to make the frame fit to the end. (offset_timestamp(%d) > max_window_size(%d))\n", jb->name, offset_timestamp, jb->max_window_size);
/* shift window so it fits to the end of window */
jb->window_timestamp = timestamp - jb->max_window_size;
} else {
PDEBUG(DJITTER, DEBUG_DEBUG, "%s Frame too early: Shift jitter buffer to the future, to make the frame fit to the target delay. (offset_timestamp(%d) > max_window_size(%d))\n", jb->name, offset_timestamp, jb->max_window_size);
LOGP(DJITTER, LOGL_DEBUG, "%s Frame too early: Shift jitter buffer to the future, to make the frame fit to the target delay. (offset_timestamp(%d) > max_window_size(%d))\n", jb->name, offset_timestamp, jb->max_window_size);
/* shift window so frame fits to the start of window + target delay */
jb->window_timestamp = timestamp - (uint32_t)(jb->target_window_size);
}
@ -275,11 +275,11 @@ void jitter_save(jitter_t *jb, void *samples, int length, int has_sequence, uint
/* is frame is too late, shift window to the past. */
if (offset_timestamp < 0) {
if ((jb->window_flags & JITTER_FLAG_LATENCY)) {
PDEBUG(DJITTER, DEBUG_DEBUG, "%s Frame too late: Shift jitter buffer to the past, and add target window size. (offset_timestamp(%d) < 0)\n", jb->name, offset_timestamp);
LOGP(DJITTER, LOGL_DEBUG, "%s Frame too late: Shift jitter buffer to the past, and add target window size. (offset_timestamp(%d) < 0)\n", jb->name, offset_timestamp);
/* shift window so frame fits to the start of window + half of target delay */
jb->window_timestamp = timestamp - (uint32_t)(jb->target_window_size) / 2;
} else {
PDEBUG(DJITTER, DEBUG_DEBUG, "%s Frame too late: Shift jitter buffer to the past, and add half target window size. (offset_timestamp(%d) < 0)\n", jb->name, offset_timestamp);
LOGP(DJITTER, LOGL_DEBUG, "%s Frame too late: Shift jitter buffer to the past, and add half target window size. (offset_timestamp(%d) < 0)\n", jb->name, offset_timestamp);
/* shift window so frame fits to the start of window + target delay */
jb->window_timestamp = timestamp - (uint32_t)(jb->target_window_size);
}
@ -287,11 +287,11 @@ void jitter_save(jitter_t *jb, void *samples, int length, int has_sequence, uint
/* insert or append frame */
#ifdef HEAVY_DEBUG
PDEBUG(DJITTER, DEBUG_DEBUG, "%s Store frame\n", jb->name);
LOGP(DJITTER, LOGL_DEBUG, "%s Store frame\n", jb->name);
#endif
jf = malloc(sizeof(*jf) + length * jb->sample_size);
if (!jf) {
PDEBUG(DJITTER, DEBUG_ERROR, "No memory for frame.\n");
LOGP(DJITTER, LOGL_ERROR, "No memory for frame.\n");
return;
}
memset(jf, 0, sizeof(*jf)); // note: clear header only
@ -311,7 +311,7 @@ void jitter_load(jitter_t *jb, void *samples, int length)
int32_t count, count2, index;
#ifdef HEAVY_DEBUG
PDEBUG(DJITTER, DEBUG_DEBUG, "%sLoad chunk of %d samples.\n", jb->name, length);
LOGP(DJITTER, LOGL_DEBUG, "%sLoad chunk of %d samples.\n", jb->name, length);
#endif
/* now unlock jitter buffer */
@ -321,10 +321,10 @@ void jitter_load(jitter_t *jb, void *samples, int length)
jb->delay_counter += jb->sample_duration * (double)length;
if (jb->delay_counter >= jb->delay_interval) {
if (jb->min_delay_value >= 0)
PDEBUG(DJITTER, DEBUG_DEBUG, "%s Statistics: target_window_delay=%.0fms max_window_delay=%.0fms current min_delay=%.0fms\n", jb->name, (double)jb->target_window_size * jb->sample_duration * 1000.0, (double)jb->max_window_size * jb->sample_duration * 1000.0, (double)jb->min_delay_value * jb->sample_duration * 1000.0);
LOGP(DJITTER, LOGL_DEBUG, "%s Statistics: target_window_delay=%.0fms max_window_delay=%.0fms current min_delay=%.0fms\n", jb->name, (double)jb->target_window_size * jb->sample_duration * 1000.0, (double)jb->max_window_size * jb->sample_duration * 1000.0, (double)jb->min_delay_value * jb->sample_duration * 1000.0);
/* delay reduction, if maximum delay is greater than target jitter window size */
if ((jb->window_flags & JITTER_FLAG_LATENCY) && jb->min_delay_value > jb->target_window_size) {
PDEBUG(DJITTER, DEBUG_DEBUG, "%s Reducing current minimum delay of %.0fms, because maximum delay is greater than target window size of %.0fms.\n", jb->name, (double)jb->min_delay_value * jb->sample_duration * 1000.0, (double)jb->target_window_size * jb->sample_duration * 1000.0);
LOGP(DJITTER, LOGL_DEBUG, "%s Reducing current minimum delay of %.0fms, because maximum delay is greater than target window size of %.0fms.\n", jb->name, (double)jb->min_delay_value * jb->sample_duration * 1000.0, (double)jb->target_window_size * jb->sample_duration * 1000.0);
/* only reduce delay to half of the target window size */
jb->window_timestamp += jb->min_delay_value - jb->target_window_size / 2;
@ -349,9 +349,9 @@ void jitter_load(jitter_t *jb, void *samples, int length)
if (count > 0) {
#ifdef HEAVY_DEBUG
if (jf)
PDEBUG(DJITTER, DEBUG_DEBUG, "%s There is a frame ahead in buffer after %d samples. Interpolating gap.\n", jb->name, jf->timestamp - jb->window_timestamp);
LOGP(DJITTER, LOGL_DEBUG, "%s There is a frame ahead in buffer after %d samples. Interpolating gap.\n", jb->name, jf->timestamp - jb->window_timestamp);
else
PDEBUG(DJITTER, DEBUG_DEBUG, "%s There is no frame ahead in buffer. Interpolating gap.\n", jb->name);
LOGP(DJITTER, LOGL_DEBUG, "%s There is no frame ahead in buffer. Interpolating gap.\n", jb->name);
#endif
/* extrapolate by playing the extrapolation buffer */
while (count) {
@ -366,7 +366,7 @@ void jitter_load(jitter_t *jb, void *samples, int length)
jb->extra_timeout_count++;
if (jb->extra_timeout_count == jb->extra_timeout_max) {
#ifdef HEAVY_DEBUG
PDEBUG(DJITTER, DEBUG_DEBUG, "%s Repeated jitter buffer enough, clearing to silence.\n", jb->name);
LOGP(DJITTER, LOGL_DEBUG, "%s Repeated jitter buffer enough, clearing to silence.\n", jb->name);
#endif
clear_extra_buffer(jb);
}
@ -393,7 +393,7 @@ void jitter_load(jitter_t *jb, void *samples, int length)
count = jb->extra_size - jb->extra_index;
/* copy samples from packet to play out, increment sample pointer and decrement length */
#ifdef HEAVY_DEBUG
PDEBUG(DJITTER, DEBUG_DEBUG, "%s Copy data (offset=%u count=%u) from frame (sequence=%u timestamp=%u length=%u).\n", jb->name, index, count, jf->sequence, jf->timestamp, jf->length);
LOGP(DJITTER, LOGL_DEBUG, "%s Copy data (offset=%u count=%u) from frame (sequence=%u timestamp=%u length=%u).\n", jb->name, index, count, jf->sequence, jf->timestamp, jf->length);
#endif
memcpy(samples, (uint8_t *)jf->samples + index * jb->sample_size, count * jb->sample_size);
samples = (uint8_t *)samples + count * jb->sample_size;

View File

@ -0,0 +1,8 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
noinst_LIBRARIES = liblogging.a
liblogging_a_SOURCES = \
logging.c \
categories.c

View File

@ -0,0 +1,47 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
#include "categories.h"
/* All logging categories used by this project. */
struct log_info_cat log_categories[] = {
[DLCC] = {
.name = "DLCC",
.description = "libosmo-cc CC Layer",
.color = "\033[0;37m",
},
[DOPTIONS] = {
.name = "DOPTIONS",
.description = "config options",
.color = "\033[0;33m",
},
[DJITTER] = {
.name = "DJITTER",
.description = "jitter buffer handling",
.color = "\033[0;36m",
},
[DISDN] = {
.name = "DISDN",
.description = "ISDN control",
.color = "\033[1;35m",
},
[DMISDN] = {
.name = "DMISDN",
.description = "mISDN stack",
.color = "\033[0;34m",
},
[DDSS1] = {
.name = "DDSS1",
.description = "ISDN DSS1 protocol",
.color = "\033[1;34m",
},
[DPH] = {
.name = "DPH",
.description = "PH SAP socket interface",
.color = "\033[0;33m",
},
};
size_t log_categories_size = ARRAY_SIZE(log_categories);

View File

@ -0,0 +1,14 @@
enum {
DLCC,
DOPTIONS,
DJITTER,
DISDN,
DMISDN,
DDSS1,
DPH,
};
extern struct log_info_cat log_categories[];
extern size_t log_categories_size;

264
src/liblogging/logging.c Normal file
View File

@ -0,0 +1,264 @@
/* Logging (on segmented part of the window)
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/ioctl.h>
#include <math.h>
#include <errno.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/application.h>
#include <osmocom/cc/misc.h>
#include "logging.h"
int loglevel = LOGL_INFO;
static int scroll_window_start = 0;
static int scroll_window_end = 0;
static int scroll_window_height = 0;
void lock_logging(void)
{
log_tgt_mutex_lock();
}
void unlock_logging(void)
{
log_tgt_mutex_unlock();
}
void get_win_size(int *w, int *h)
{
struct winsize win;
int rc;
rc = ioctl(0, TIOCGWINSZ, &win);
if (rc) {
*w = 80;
*h = 25;
return;
}
if (h)
*h = win.ws_row;
if (w)
*w = win.ws_col;
}
void enable_limit_scroll(bool enable)
{
/* Before the window is set, keep scrolling everything. */
if (scroll_window_height == 0)
return;
/* If window is too small. */
if (scroll_window_end - scroll_window_start <= 0)
return;
if (enable) {
printf("\0337\033[%d;%dr\0338", scroll_window_start, scroll_window_end);
} else
printf("\0337\033[%d;%dr\0338", 1, scroll_window_height);
fflush(stdout);
}
void logging_limit_scroll_top(int lines)
{
lock_logging();
get_win_size(NULL, &scroll_window_height);
scroll_window_start = lines + 1;
if (scroll_window_end == 0)
scroll_window_end = scroll_window_height;
enable_limit_scroll(true);
unlock_logging();
}
void logging_limit_scroll_bottom(int lines)
{
int i;
lock_logging();
get_win_size(NULL, &scroll_window_height);
scroll_window_end = scroll_window_height - lines;
if (scroll_window_start == 0)
scroll_window_start = 1;
/* Make space by adding empty lines. */
for (i = scroll_window_end; i < scroll_window_height; i++)
printf("\n");
/* Go up by number of lines to be in window. */
printf("\033[%dA", scroll_window_height - scroll_window_end);
/* Enable window. */
enable_limit_scroll(true);
unlock_logging();
}
const char *debug_amplitude(double level)
{
static char text[42];
strcpy(text, " : ");
if (level > 1.0)
level = 1.0;
if (level < -1.0)
level = -1.0;
text[20 + (int)(level * 20)] = '*';
return text;
}
#define level2db(level) (20 * log10(level))
const char *debug_db(double level_db)
{
static char text[128];
int l;
strcpy(text, ": . : . : . : . : . : . : . : . | . : . : . : . : . : . : . : . :");
if (level_db <= 0.0)
return text;
l = (int)round(level2db(level_db));
if (l > 48)
return text;
if (l < -48)
return text;
text[l + 48] = '*';
return text;
}
void logging_print_help(void)
{
printf(" -v --verbose <level> | <level>,<category>[,<category>[,...]] | list\n");
printf(" Use 'list' to get a list of all levels and categories.\n");
printf(" Verbose level: digit of debug level (default = '%d')\n", loglevel);
printf(" Verbose level+category: level digit followed by one or more categories\n");
printf(" -> If no category is specified, all categories are selected\n");
printf(" -v --verbose date\n");
printf(" Show date with debug output\n");
}
static unsigned char log_levels[] = { LOGL_DEBUG, LOGL_INFO, LOGL_NOTICE, LOGL_ERROR };
static char *log_level_names[] = { "debug", "info", "notice", "error" };
static void list_cat(void)
{
int i;
printf("Give number of debug level:\n");
for (i = 0; i < (int)sizeof(log_levels); i++)
printf(" %d = %s\n", log_levels[i], log_level_names[i]);
printf("\n");
printf("Give name(s) of debug category:\n");
for (i = 0; i < (int)log_categories_size; i++) {
if (!log_categories[i].name)
continue;
printf(" ");
if (log_categories[i].color)
printf("%s", log_categories[i].color);
if (log_categories[i].name)
printf("%s\033[0;39m = %s\n", log_categories[i].name, log_categories[i].description);
}
printf("\n");
}
int parse_logging_opt(const char *optarg)
{
int i;
char *dup, *dstring, *p;
if (!strcasecmp(optarg, "list")) {
list_cat();
return 1;
}
if (!strcasecmp(optarg, "date")) {
log_set_print_timestamp(osmo_stderr_target, 1);
return 0;
}
dup = dstring = strdup(optarg);
p = strsep(&dstring, ",");
for (i = 0; i < p[i]; i++) {
if (p[i] < '0' || p[i] > '9') {
fprintf(stderr, "Only digits are allowed for debug level!\n");
free(dup);
return -EINVAL;
}
}
loglevel = atoi(p);
for (i = 0; i < (int)sizeof(log_levels); i++) {
if (log_levels[i] == loglevel)
break;
}
if (i == (int)sizeof(log_levels)) {
fprintf(stderr, "Logging level does not exist, use '-v list' to show available levels!\n");
free(dup);
return -EINVAL;
}
/* Set loglevel and enable all categories, if dstring is not set. Else set loglevel and disable all categories. */
for (i = 0; i < (int)log_categories_size; i++)
log_set_category_filter(osmo_stderr_target, i, (!dstring), loglevel);
/* Enable each given category. */
while((p = strsep(&dstring, ","))) {
for (i = 0; i < (int)log_categories_size; i++) {
if (!log_category_name(i))
continue;
if (!strcasecmp(p, log_category_name(i)))
break;
}
if (i == (int)log_categories_size) {
fprintf(stderr, "Given logging category '%s' unknown, use '-v list' to show available categories!\n", p);
free(dup);
return -EINVAL;
}
log_set_category_filter(osmo_stderr_target, i, 1, loglevel);
}
free(dup);
return 0;
}
/* Call after configuation above. */
void logging_init(void)
{
int i;
struct log_info log_info = {
.cat = log_categories,
.num_cat = log_categories_size,
};
osmo_cc_set_log_cat(DLCC);
osmo_init_logging2(NULL, &log_info);
log_set_print_timestamp(osmo_stderr_target, 0);
log_set_print_level(osmo_stderr_target, 1);
log_set_print_category_hex(osmo_stderr_target, 0);
log_set_print_category(osmo_stderr_target, 1);
/* Set loglevel and enable all categories. */
for (i = 0; i < (int)log_categories_size; i++)
log_set_category_filter(osmo_stderr_target, i, 1, loglevel);
}

21
src/liblogging/logging.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <osmocom/core/logging.h>
#include "categories.h"
extern int loglevel;
#define LOGP_CHAN(cat, level, fmt, arg...) LOGP(cat, level, "(chan %s) " fmt, CHAN, ## arg)
void get_win_size(int *w, int *h);
void lock_logging(void);
void unlock_logging(void);
void enable_limit_scroll(bool enable);
void logging_limit_scroll_top(int lines);
void logging_limit_scroll_bottom(int lines);
const char *debug_amplitude(double level);
const char *debug_db(double level_db);
void logging_print_help(void);
int parse_logging_opt(const char *optarg);
void logging_init(void);

View File

@ -176,7 +176,7 @@ struct mISDNdevice
{
struct mISDNdevice *dev;
hlist_for_each_entry(dev, &dev_list.head, list) {
m_hlist_for_each_entry(dev, &dev_list.head, list) {
if (dev->id == id)
return dev;
}
@ -188,7 +188,7 @@ get_mdevice_count(void)
{
int cnt = 0;
struct mISDNdevice *dev;
hlist_for_each_entry(dev, &dev_list.head, list) {
m_hlist_for_each_entry(dev, &dev_list.head, list) {
cnt++;
}
return cnt;
@ -235,7 +235,7 @@ mISDN_register_device(struct mISDNdevice *dev,
// dev->dev.parent = parent;
// dev_set_drvdata(&dev->dev, dev);
hlist_add_head(&dev->list, &dev_list.head);
m_hlist_add_head(&dev->list, &dev_list.head);
// err = device_add(&dev->dev);
// if (err)
// goto error3;
@ -256,7 +256,7 @@ mISDN_unregister_device(struct mISDNdevice *dev) {
printk(KERN_DEBUG "mISDN_unregister %s %d\n",
dev_name(dev), dev->id);
/* sysfs_remove_link(&dev->dev.kobj, "device"); */
hlist_del(&dev->list);
m_hlist_del(&dev->list);
// device_del(&dev->dev);
// dev_set_drvdata(&dev->dev, NULL);
@ -421,7 +421,7 @@ int mISDN_work(void)
struct mISDNdevice *dev;
int work = 0;
hlist_for_each_entry(dev, &dev_list.head, list) {
m_hlist_for_each_entry(dev, &dev_list.head, list) {
work |= work_stack(dev);
}

View File

@ -99,7 +99,7 @@ FsmExpireTimer(void *data)
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
#endif
timer_exit(&ft->tl);
osmo_timer_del(&ft->tl);
mISDN_FsmEvent(ft->fi, ft->event, ft->arg);
}
@ -124,7 +124,7 @@ mISDN_FsmDelTimer(struct FsmTimer *ft, int __attribute__((unused)) where)
ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d",
(long) ft, where);
#endif
timer_exit(&ft->tl);
osmo_timer_del(&ft->tl);
}
EXPORT_SYMBOL(mISDN_FsmDelTimer);
@ -139,7 +139,7 @@ mISDN_FsmAddTimer(struct FsmTimer *ft,
(long) ft, millisec, where);
#endif
if (ft->tl.linked) {
// if (ft->tl.linked) {
if (ft->fi->debug) {
printk(KERN_WARNING
"mISDN_FsmAddTimer: timer already active!\n");
@ -147,11 +147,11 @@ mISDN_FsmAddTimer(struct FsmTimer *ft,
"mISDN_FsmAddTimer already active!");
}
return -1;
}
// }
ft->event = event;
ft->arg = arg;
timer_init(&ft->tl, ft->func, ft);
timer_start(&ft->tl, (double)millisec / 1000);
osmo_timer_setup(&ft->tl, ft->func, ft);
osmo_timer_schedule(&ft->tl, millisec / 1000, (millisec % 1000) * 1000);
return 0;
}
EXPORT_SYMBOL(mISDN_FsmAddTimer);
@ -167,11 +167,11 @@ mISDN_FsmRestartTimer(struct FsmTimer *ft,
(long) ft, millisec, where);
#endif
if (ft->tl.linked)
timer_exit(&ft->tl);
// if (ft->tl.linked)
osmo_timer_del(&ft->tl);
ft->event = event;
ft->arg = arg;
timer_init(&ft->tl, ft->func, ft);
timer_start(&ft->tl, (double)millisec / 1000.0);
osmo_timer_setup(&ft->tl, ft->func, ft);
osmo_timer_schedule(&ft->tl, millisec / 1000, (millisec % 1000) * 1000);
}
EXPORT_SYMBOL(mISDN_FsmRestartTimer);

View File

@ -41,7 +41,7 @@ struct FsmNode {
struct FsmTimer {
struct FsmInst *fi;
struct timer tl;
struct osmo_timer_list tl;
void *func;
int event;
void *arg;

View File

@ -84,7 +84,7 @@ struct dchannel {
void *l1;
void *hw;
int slot; /* multiport card channel slot */
// struct timer_list timer;
// struct osmo_timer_list_list timer;
/* receive data */
struct sk_buff *rx_skb;
int maxlen;
@ -145,7 +145,7 @@ struct bchannel {
u_int state;
void *hw;
int slot; /* multiport card channel slot */
// struct timer_list timer;
// struct osmo_timer_list_list timer;
/* receive data */
uint8_t fill[MISDN_BCH_FILL_SIZE];
struct sk_buff *rx_skb;

View File

@ -415,7 +415,7 @@ struct mISDN_ctrl_req {
#include "skbuff.h"
#include "printk.h"
#include "bitops.h"
#include "container_of.h"
//#include "container_of.h"
#include <linux/net.h>
//#include <linux/completion.h>
@ -518,12 +518,12 @@ struct mISDNchannel {
};
struct mISDN_sock_list {
struct hlist_head head;
struct m_hlist_head head;
rwlock_t lock;
};
struct mISDN_sock {
struct hlist_node list;
struct m_hlist_node list;
int sk_protocol;
int sk_state;
struct sk_buff_head sk_receive_queue;
@ -534,12 +534,12 @@ struct mISDN_sock {
struct mISDN_dev_list {
struct hlist_head head;
struct m_hlist_head head;
rwlock_t lock;
};
struct mISDNdevice {
struct hlist_node list;
struct m_hlist_node list;
struct mISDNchannel D;
u_int id;
u_int Dprotocols;

View File

@ -11,12 +11,12 @@ struct list_head {
struct list_head *next, *prev;
};
struct hlist_head {
struct hlist_node *first;
struct m_hlist_head {
struct m_hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
struct m_hlist_node {
struct m_hlist_node *next, **pprev;
};
@ -31,7 +31,7 @@ static inline void INIT_LIST_HEAD(struct list_head *list)
list->prev = list;
}
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
#define INIT_M_HLIST_HEAD(ptr) ((ptr)->first = NULL)
/*
* list_add_head - add a new entry on the top
@ -48,16 +48,16 @@ static inline void list_add_head(struct list_head *new, struct list_head *head)
}
/**
* hlist_add_head - add a new entry at the beginning of the hlist
* m_hlist_add_head - add a new entry at the beginning of the m_hlist
* @n: new entry to be added
* @h: hlist head to add it after
* @h: m_hlist head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
static inline void m_hlist_add_head(struct m_hlist_node *n, struct m_hlist_head *h)
{
struct hlist_node *first = h->first;
struct m_hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
@ -94,10 +94,10 @@ static inline void list_del(struct list_head *entry)
entry->prev = (void *)LIST_POISON2;
}
static inline void hlist_del(struct hlist_node *n)
static inline void m_hlist_del(struct m_hlist_node *n)
{
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
struct m_hlist_node *next = n->next;
struct m_hlist_node **pprev = n->pprev;
*pprev = next;
if (next)
@ -126,10 +126,10 @@ static inline int list_empty(const struct list_head *head)
}
/**
* hlist_empty - Is the specified hlist_head structure an empty hlist?
* m_hlist_empty - Is the specified m_hlist_head structure an empty m_hlist?
* @h: Structure to check.
*/
static inline int hlist_empty(const struct hlist_head *h)
static inline int m_hlist_empty(const struct m_hlist_head *h)
{
return !h->first;
}
@ -178,21 +178,21 @@ static inline int hlist_empty(const struct hlist_head *h)
#endif
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define m_hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_entry_safe(ptr, type, member) \
#define m_hlist_entry_safe(ptr, type, member) \
({ typeof(ptr) ____ptr = (ptr); \
____ptr ? hlist_entry(____ptr, type, member) : NULL; \
____ptr ? m_hlist_entry(____ptr, type, member) : NULL; \
})
/**
* hlist_for_each_entry - iterate over list of given type
* m_hlist_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
* @member: the name of the m_hlist_node within the struct.
*/
#define hlist_for_each_entry(pos, head, member) \
for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
#define m_hlist_for_each_entry(pos, head, member) \
for (pos = m_hlist_entry_safe((head)->first, typeof(*(pos)), member);\
pos; \
pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
pos = m_hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))

View File

@ -3,25 +3,37 @@
#include <stdarg.h>
#include "printk.h"
void _printk(const char *file, const char *function, int line, const char *fmt, ...)
void _printk(const char *file, __attribute__((unused)) const char *function, int line, const char *fmt, ...)
{
char buffer[4096], *b = buffer;
int s = sizeof(buffer) - 1;
int level = 1;
int level = LOGL_INFO;
va_list args;
buffer[sizeof(buffer) - 1] = '\0';
/* remove debug level from format */
if (fmt[0] >= '0' && fmt[0] <= '9') {
level = fmt[0] - '0';
switch (fmt[0]) {
case '0':
case '1':
case '2':
case '3':
level = LOGL_ERROR;
break;
case '4':
case '5':
level = LOGL_NOTICE;
break;
case '6':
level = LOGL_INFO;
break;
case '7':
case '8':
case '9':
level = LOGL_DEBUG;
break;
}
fmt++;
}
va_start(args, fmt);
vsnprintf(b, s, fmt, args);
LOGPSRC(DMISDN, level, file, line, fmt, args);
va_end(args);
_printdebug(file, function, line, DMISDN, level, NULL, "%s", b);
}

View File

@ -3,13 +3,16 @@
#define MISDN_PRINTK_H
#include <stdint.h>
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
#define KERN_DEBUG "0"
#define KERN_INFO "1"
#define KERN_NOTICE "2"
#define KERN_WARNING "2"
#define KERN_ERR "3"
#define KERN_EMERG "0" /* system is unusable */
#define KERN_ALERT "1" /* action must be taken immediately */
#define KERN_CRIT "2" /* critical conditions */
#define KERN_ERR "3" /* error conditions */
#define KERN_WARNING "4" /* warning conditions */
#define KERN_NOTICE "5" /* normal but significant condition */
#define KERN_INFO "6" /* informational */
#define KERN_DEBUG "7" /* debug-level messages */
#define printk(fmt, arg...) _printk(__FILE__, __FUNCTION__, __LINE__, fmt, ## arg)
void _printk(const char *file, const char *function, int line, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 4, 5)));

View File

@ -40,14 +40,14 @@ static void
mISDN_sock_link(struct mISDN_sock_list *l, struct mISDN_sock *msk)
{
write_lock_bh(&l->lock);
hlist_add_head(&msk->list, &l->head);
m_hlist_add_head(&msk->list, &l->head);
write_unlock_bh(&l->lock);
}
static void mISDN_sock_unlink(struct mISDN_sock_list __attribute__((unused)) *l, struct mISDN_sock *msk)
{
write_lock_bh(&l->lock);
hlist_del(&msk->list);
m_hlist_del(&msk->list);
write_unlock_bh(&l->lock);
}
@ -425,7 +425,7 @@ int mISDN_data_bind(void *inst, struct sockaddr *addr, int addr_len)
if (msk->sk_protocol < ISDN_P_B_START) {
read_lock_bh(&data_sockets.lock);
hlist_for_each_entry(cmsk, &data_sockets.head, list) {
m_hlist_for_each_entry(cmsk, &data_sockets.head, list) {
if (msk == cmsk)
continue;
if (cmsk->dev != msk->dev)

View File

@ -58,7 +58,7 @@ send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb)
struct sk_buff *cskb = NULL;
read_lock(&sl->lock);
hlist_for_each_entry(msk, &sl->head, list) {
m_hlist_for_each_entry(msk, &sl->head, list) {
if (msk->sk_state != MISDN_BOUND)
continue;
if (!cskb)
@ -144,13 +144,13 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb)
printk(KERN_DEBUG "%s prim(%x) id(%x) lm(%x) %p\n",
__func__, hh->prim, hh->id, lm, skb);
if (lm == 0x1) {
if (!hlist_empty(&st->l1sock.head)) {
if (!m_hlist_empty(&st->l1sock.head)) {
__net_timestamp(skb);
send_socklist(&st->l1sock, skb);
}
return st->layer1->send(st->layer1, skb);
} else if (lm == 0x2) {
if (!hlist_empty(&st->l1sock.head))
if (!m_hlist_empty(&st->l1sock.head))
send_socklist(&st->l1sock, skb);
send_layer2(st, skb);
return 0;
@ -379,7 +379,7 @@ create_stack(struct mISDNdevice *dev)
}
newst->dev = dev;
INIT_LIST_HEAD(&newst->layer2);
INIT_HLIST_HEAD(&newst->l1sock.head);
INIT_M_HLIST_HEAD(&newst->l1sock.head);
rwlock_init(&newst->l1sock.lock);
// init_waitqueue_head(&newst->workq);
skb_queue_head_init(&newst->msgq);
@ -450,7 +450,7 @@ connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch,
if (err)
return err;
write_lock_bh(&dev->D.st->l1sock.lock);
hlist_add_head(&msk->list, &dev->D.st->l1sock.head);
m_hlist_add_head(&msk->list, &dev->D.st->l1sock.head);
write_unlock_bh(&dev->D.st->l1sock.lock);
break;
default:
@ -592,7 +592,7 @@ delete_channel(struct mISDNchannel *ch)
case ISDN_P_NT_E1:
case ISDN_P_TE_E1:
write_lock_bh(&ch->st->l1sock.lock);
hlist_del(&msk->list);
m_hlist_del(&msk->list);
write_unlock_bh(&ch->st->l1sock.lock);
ch->st->dev->D.ctrl(&ch->st->dev->D, CLOSE_CHANNEL, NULL);
break;
@ -649,7 +649,7 @@ delete_stack(struct mISDNdevice *dev)
if (!list_empty(&st->layer2))
printk(KERN_WARNING "%s: layer2 list not empty\n",
__func__);
if (!hlist_empty(&st->l1sock.head))
if (!m_hlist_empty(&st->l1sock.head))
printk(KERN_WARNING "%s: layer1 list not empty\n",
__func__);
kfree(st);

View File

@ -2,14 +2,14 @@
#ifndef _MISDN_TIMER_H
#define _MISDN_TIMER_H
#include "../libtimer/timer.h"
#include <osmocom/core/timer.h>
#if 0
#define timer_list timer
#define timer_setup(ti, fu, flags) timer_init(ti, fu, NULL)
#define add_timer timer_start
#define del_timer timer_stop
#define timer_pending timer_running
#define add_timer osmo_timer_schedule
#define del_timer osmo_timer_del
#define timer_pending osmo_timer_pending
#endif
#define from_timer(var, callback_timer, timer_fieldname) \

View File

@ -23,7 +23,7 @@
#include <stdlib.h>
#include <errno.h>
#include "options.h"
#include "../libdebug/debug.h"
#include "../liblogging/logging.h"
typedef struct option {
struct option *next;
@ -47,7 +47,7 @@ char *options_strdup(const char *s)
o = malloc(sizeof(struct options_strdup_entry) + strlen(s));
if (!o) {
PDEBUG(DOPTIONS, DEBUG_ERROR, "No mem!\n");
LOGP(DOPTIONS, LOGL_ERROR, "No mem!\n");
abort();
}
o->next = options_strdup_list;
@ -64,19 +64,19 @@ void option_add(int short_option, const char *long_option, int parameter_count)
/* check if option already exists or is not allowed */
for (option = option_head; option; option = option->next) {
if (!strcmp(option->long_option, "config")) {
PDEBUG(DOPTIONS, DEBUG_ERROR, "Option '%s' is not allowed to add, please fix!\n", option->long_option);
LOGP(DOPTIONS, LOGL_ERROR, "Option '%s' is not allowed to add, please fix!\n", option->long_option);
abort();
}
if (option->short_option == short_option
|| !strcmp(option->long_option, long_option)) {
PDEBUG(DOPTIONS, DEBUG_ERROR, "Option '%s' added twice, please fix!\n", option->long_option);
LOGP(DOPTIONS, LOGL_ERROR, "Option '%s' added twice, please fix!\n", option->long_option);
abort();
}
}
option = calloc(1, sizeof(*option));
if (!option) {
PDEBUG(DOPTIONS, DEBUG_ERROR, "No mem!\n");
LOGP(DOPTIONS, LOGL_ERROR, "No mem!\n");
abort();
}
@ -115,7 +115,7 @@ int options_config_file(int argc, char *argv[], const char *config_file, int (*h
/* open config file */
fp = fopen(config, "r");
if (!fp) {
PDEBUG(DOPTIONS, DEBUG_INFO, "Config file '%s' seems not to exist, using command line options only.\n", config);
LOGP(DOPTIONS, LOGL_INFO, "Config file '%s' seems not to exist, using command line options only.\n", config);
return 1;
}
@ -201,21 +201,21 @@ int options_config_file(int argc, char *argv[], const char *config_file, int (*h
/* search option */
for (option = option_head; option; option = option->next) {
if (opt[0] == option->short_option && opt[1] == '\0') {
PDEBUG(DOPTIONS, DEBUG_INFO, "Config file option '%s' ('%s'), parameter%s\n", opt, option->long_option, params);
LOGP(DOPTIONS, LOGL_INFO, "Config file option '%s' ('%s'), parameter%s\n", opt, option->long_option, params);
break;
}
if (!strcmp(opt, option->long_option)) {
PDEBUG(DOPTIONS, DEBUG_INFO, "Config file option '%s', parameter%s\n", opt, params);
LOGP(DOPTIONS, LOGL_INFO, "Config file option '%s', parameter%s\n", opt, params);
break;
}
}
if (!option) {
PDEBUG(DOPTIONS, DEBUG_ERROR, "Given option '%s' in config file '%s' at line %d is not a valid option, use '-h' for help!\n", opt, config_file, line);
LOGP(DOPTIONS, LOGL_ERROR, "Given option '%s' in config file '%s' at line %d is not a valid option, use '-h' for help!\n", opt, config_file, line);
rc = -EINVAL;
goto done;
}
if (option->parameter_count != i) {
PDEBUG(DOPTIONS, DEBUG_ERROR, "Given option '%s' in config file '%s' at line %d requires %d parameter(s), use '-h' for help!\n", opt, config_file, line, option->parameter_count);
LOGP(DOPTIONS, LOGL_ERROR, "Given option '%s' in config file '%s' at line %d requires %d parameter(s), use '-h' for help!\n", opt, config_file, line, option->parameter_count);
return -EINVAL;
}
rc = handle_options(option->short_option, 0, args);
@ -242,11 +242,11 @@ int options_command_line(int argc, char *argv[], int (*handle_options)(int short
/* --config */
if (!strcmp(argv[argi], "--config")) {
if (argi > 1) {
PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' must be the first option specified, use '-h' for help!\n", argv[argi]);
LOGP(DOPTIONS, LOGL_ERROR, "Given command line option '%s' must be the first option specified, use '-h' for help!\n", argv[argi]);
return -EINVAL;
}
if (argc <= 2) {
PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' requires 1 parameter, use '-h' for help!\n", argv[argi]);
LOGP(DOPTIONS, LOGL_ERROR, "Given command line option '%s' requires 1 parameter, use '-h' for help!\n", argv[argi]);
return -EINVAL;
}
argi += 1;
@ -255,7 +255,7 @@ int options_command_line(int argc, char *argv[], int (*handle_options)(int short
if (argv[argi][0] == '-') {
if (argv[argi][1] != '-') {
if (strlen(argv[argi]) != 2) {
PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' exceeds one character, use '-h' for help!\n", argv[argi]);
LOGP(DOPTIONS, LOGL_ERROR, "Given command line option '%s' exceeds one character, use '-h' for help!\n", argv[argi]);
return -EINVAL;
}
/* -x */
@ -265,9 +265,9 @@ int options_command_line(int argc, char *argv[], int (*handle_options)(int short
params[0] = '\0';
for (i = 0; i < option->parameter_count; i++)
sprintf(strchr(params, '\0'), " '%s'", argv[argi + 1 + i]);
PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s' ('--%s'), parameter%s\n", argv[argi], option->long_option, params);
LOGP(DOPTIONS, LOGL_INFO, "Command line option '%s' ('--%s'), parameter%s\n", argv[argi], option->long_option, params);
} else
PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s' ('--%s')\n", argv[argi], option->long_option);
LOGP(DOPTIONS, LOGL_INFO, "Command line option '%s' ('--%s')\n", argv[argi], option->long_option);
break;
}
}
@ -279,19 +279,19 @@ int options_command_line(int argc, char *argv[], int (*handle_options)(int short
params[0] = '\0';
for (i = 0; i < option->parameter_count; i++)
sprintf(strchr(params, '\0'), " '%s'", argv[argi + 1 + i]);
PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s', parameter%s\n", argv[argi], params);
LOGP(DOPTIONS, LOGL_INFO, "Command line option '%s', parameter%s\n", argv[argi], params);
} else
PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s'\n", argv[argi]);
LOGP(DOPTIONS, LOGL_INFO, "Command line option '%s'\n", argv[argi]);
break;
}
}
}
if (!option) {
PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' is not a valid option, use '-h' for help!\n", argv[argi]);
LOGP(DOPTIONS, LOGL_ERROR, "Given command line option '%s' is not a valid option, use '-h' for help!\n", argv[argi]);
return -EINVAL;
}
if (argi + option->parameter_count >= argc) {
PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' requires %d parameter(s), use '-h' for help!\n", argv[argi], option->parameter_count);
LOGP(DOPTIONS, LOGL_ERROR, "Given command line option '%s' requires %d parameter(s), use '-h' for help!\n", argv[argi], option->parameter_count);
return -EINVAL;
}
rc = handle_options(option->short_option, argi + 1, argv);
@ -306,7 +306,7 @@ int options_command_line(int argc, char *argv[], int (*handle_options)(int short
/* no more options, so we check if there is an option after a non-option parameter */
for (i = argi; i < argc; i++) {
if (argv[i][0] == '-') {
PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' behind command line parameter '%s' not allowed! Please put all command line options before command line parameter(s).\n", argv[i], argv[argi]);
LOGP(DOPTIONS, LOGL_ERROR, "Given command line option '%s' behind command line parameter '%s' not allowed! Please put all command line options before command line parameter(s).\n", argv[i], argv[argi]);
return -EINVAL;
}
}

View File

@ -1,15 +0,0 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
noinst_LIBRARIES = libosmocc.a
libosmocc_a_SOURCES = \
message.c \
socket.c \
cause.c \
screen.c \
endpoint.c \
session.c \
sdp.c \
rtp.c \
helper.c

View File

@ -1,251 +0,0 @@
/* OSMO-CC Processing: convert causes
*
* (C) 2019 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <arpa/inet.h>
#include "message.h"
#include "cause.h"
/* stolen from freeswitch, did some corrections */
/* map sip responses to QSIG cause codes ala RFC4497 section 8.4.4 */
static uint8_t status2isdn_cause(uint16_t status)
{
switch (status) {
case 200:
return 16; //SWITCH_CAUSE_NORMAL_CLEARING;
case 401:
case 402:
case 403:
case 407:
case 603:
return 21; //SWITCH_CAUSE_CALL_REJECTED;
case 404:
case 485:
case 604:
return 1; //SWITCH_CAUSE_UNALLOCATED_NUMBER;
case 408:
case 504:
return 102; //SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
case 410:
return 22; //SWITCH_CAUSE_NUMBER_CHANGED;
case 413:
case 414:
case 416:
case 420:
case 421:
case 423:
case 505:
case 513:
return 127; //SWITCH_CAUSE_INTERWORKING;
case 480:
return 18; //SWITCH_CAUSE_NO_USER_RESPONSE;
case 400:
case 481:
case 500:
case 503:
return 41; //SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE;
case 486:
case 600:
return 17; //SWITCH_CAUSE_USER_BUSY;
case 484:
return 28; //SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
case 488:
case 606:
return 65; //SWITCH_CAUSE_BERER_CAPABILITY_NOT_IMPLEMENTED;
case 502:
return 38; //SWITCH_CAUSE_NETWORK_OUT_OF_ORDER;
case 405:
return 63; //SWITCH_CAUSE_SERVICE_UNAVAILABLE;
case 406:
case 415:
case 501:
return 79; //SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED;
case 482:
case 483:
return 25; //SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR;
case 487:
return 31; //??? SWITCH_CAUSE_ORIGINATOR_CANCEL; (not specified)
default:
return 31; //SWITCH_CAUSE_NORMAL_UNSPECIFIED;
}
}
static uint16_t isdn2status_cause(uint8_t cause, uint8_t location)
{
switch (cause) {
case 1:
return 404;
case 2:
return 404;
case 3:
return 404;
case 17:
return 486;
case 18:
return 408;
case 19:
return 480;
case 20:
return 480;
case 21:
if (location == OSMO_CC_LOCATION_USER)
return 603;
return 403;
case 22:
//return 301;
return 410;
case 23:
return 410;
case 26:
return 404;
case 27:
return 502;
case 28:
return 484;
case 29:
return 501;
case 31:
return 480;
case 34:
return 503;
case 38:
return 503;
case 41:
return 503;
case 42:
return 503;
case 47:
return 503;
case 55:
return 403;
case 57:
return 403;
case 58:
return 503;
case 65:
return 488;
case 69:
return 501;
case 70:
return 488;
case 79:
return 501;
case 87:
return 403;
case 88:
return 503;
case 102:
return 504;
case 111:
return 500;
case 127:
return 500;
default:
return 468;
}
}
static uint8_t socket2isdn_cause(uint8_t sock)
{
switch (sock) {
case OSMO_CC_SOCKET_CAUSE_FAILED:
return 47;
case OSMO_CC_SOCKET_CAUSE_BROKEN_PIPE:
return 41;
case OSMO_CC_SOCKET_CAUSE_VERSION_MISMATCH:
return 38;
case OSMO_CC_SOCKET_CAUSE_TIMEOUT:
return 41;
default:
return 31;
}
}
void osmo_cc_convert_cause(struct osmo_cc_ie_cause *cause)
{
/* complete cause, from socket cause */
if (cause->socket_cause && cause->isdn_cause == 0 && ntohs(cause->sip_cause_networkorder) == 0)
cause->isdn_cause = socket2isdn_cause(cause->socket_cause);
/* convert ISDN cause to SIP cause */
if (cause->isdn_cause && ntohs(cause->sip_cause_networkorder) == 0) {
cause->sip_cause_networkorder = htons(isdn2status_cause(cause->isdn_cause, cause->location));
}
/* convert SIP cause to ISDN cause */
if (ntohs(cause->sip_cause_networkorder) && cause->isdn_cause == 0) {
cause->isdn_cause = status2isdn_cause(ntohs(cause->sip_cause_networkorder));
}
/* no cause at all: use Normal Call Clearing */
if (cause->isdn_cause == 0 && ntohs(cause->sip_cause_networkorder) == 0) {
cause->isdn_cause = OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR;
cause->sip_cause_networkorder = htons(486);
}
}
void osmo_cc_convert_cause_msg(osmo_cc_msg_t *msg)
{
void *ie;
uint8_t type;
uint16_t length;
void *value;
/* search for (all) cause IE and convert the values, if needed */
ie = msg->data;
while ((value = osmo_cc_msg_sep_ie(msg, &ie, &type, &length))) {
if (type == OSMO_CC_IE_CAUSE && length >= sizeof(struct osmo_cc_ie_cause)) {
osmo_cc_convert_cause(value);
}
}
}
uint8_t osmo_cc_collect_cause(uint8_t old_cause, uint8_t new_cause)
{
/* first cause */
if (old_cause == 0)
return new_cause;
/* first prio: return 17 */
if (old_cause == OSMO_CC_ISDN_CAUSE_USER_BUSY
|| new_cause == OSMO_CC_ISDN_CAUSE_USER_BUSY)
return OSMO_CC_ISDN_CAUSE_USER_BUSY;
/* second prio: return 21 */
if (old_cause == OSMO_CC_ISDN_CAUSE_CALL_REJECTED
|| new_cause == OSMO_CC_ISDN_CAUSE_CALL_REJECTED)
return OSMO_CC_ISDN_CAUSE_CALL_REJECTED;
/* third prio: return other than 88 and 18 (what ever was first) */
if (old_cause != OSMO_CC_ISDN_CAUSE_INCOMPAT_DEST
&& old_cause != OSMO_CC_ISDN_CAUSE_USER_NOTRESPOND)
return old_cause;
if (new_cause != OSMO_CC_ISDN_CAUSE_INCOMPAT_DEST
&& new_cause != OSMO_CC_ISDN_CAUSE_USER_NOTRESPOND)
return new_cause;
/* fourth prio: return 88 */
if (old_cause == OSMO_CC_ISDN_CAUSE_INCOMPAT_DEST
|| new_cause == OSMO_CC_ISDN_CAUSE_INCOMPAT_DEST)
return OSMO_CC_ISDN_CAUSE_INCOMPAT_DEST;
/* fith prio: return 18 */
return OSMO_CC_ISDN_CAUSE_USER_NOTRESPOND;
}

View File

@ -1,5 +0,0 @@
void osmo_cc_convert_cause(struct osmo_cc_ie_cause *cause);
void osmo_cc_convert_cause_msg(osmo_cc_msg_t *msg);
uint8_t osmo_cc_collect_cause(uint8_t old_cause, uint8_t new_cause);

File diff suppressed because it is too large Load Diff

View File

@ -1,131 +0,0 @@
#ifndef OSMO_CC_ENDPOINT_H
#define OSMO_CC_ENDPOINT_H
#include "message.h"
#include "socket.h"
#include "cause.h"
/* special osmo-cc error codes */
#define OSMO_CC_RC_SEE_ERRNO -1
#define OSMO_CC_RC_VERSION_MISMATCH 1
#define OSMO_CC_ATTACH_TIMER 2
/* call control state */
enum osmo_cc_state {
OSMO_CC_STATE_IDLE = 0,
/* call states */
OSMO_CC_STATE_INIT_OUT, /* outgoing CC-SETUP-REQ sent */
OSMO_CC_STATE_INIT_IN, /* incoming CC-SETUP-IND received */
OSMO_CC_STATE_OVERLAP_OUT, /* received CC-SETUP-ACK-IND on outgoing call */
OSMO_CC_STATE_OVERLAP_IN, /* sent CC-SETUP-ACK-REQ on incoming call */
OSMO_CC_STATE_PROCEEDING_OUT, /* received CC-PROC-IND on outgoing call */
OSMO_CC_STATE_PROCEEDING_IN, /* sent CC-PROC-REQ on incoming call */
OSMO_CC_STATE_ALERTING_OUT, /* received CC-ALERT-IND on outgoing call */
OSMO_CC_STATE_ALERTING_IN, /* sent CC-ALERT-REQ on incoming call */
OSMO_CC_STATE_CONNECTING_OUT, /* received CC-SETUP-CNF on outgoing call */
OSMO_CC_STATE_CONNECTING_IN, /* sent CC-SETUP-RSP on incoming call */
OSMO_CC_STATE_ACTIVE, /* received or sent CC-SETUP-COMPL-* */
OSMO_CC_STATE_DISCONNECTING_OUT, /* sent CC-DISC-REQ */
OSMO_CC_STATE_DISCONNECTING_IN, /* received CC-DISC-IND */
OSMO_CC_STATE_DISC_COLLISION, /* received CC-DISC-IND after sending CC-DISC_REQ */
OSMO_CC_STATE_RELEASING_OUT, /* sent CC-REL-REQ */
/* attachment states */
OSMO_CC_STATE_ATTACH_SENT, /* outgoing CC-ATT-REQ sent to socket */
OSMO_CC_STATE_ATTACH_OUT, /* received CC-ATT-RSP on outgoing socket */
OSMO_CC_STATE_ATTACH_WAIT, /* wait for outgoing attachment after failure */
OSMO_CC_STATE_ATTACH_IN, /* incoming CC-ATT-REQ received from socket*/
};
/* sample type */
typedef int16_t osmo_cc_sample_t;
#define OSMO_CC_SAMPLE_MILLIWATT 23170 /* peak sine at -3 dB of full sample range */
#define OSMO_CC_SAMPLE_SPEECH 3672 /* peak speech at -16 dB of milliwatt */
#define OSMO_CC_SAMPLE_MIN -32768 /* lowest level */
#define OSMO_CC_SAMPLE_MAX 32767 /* highest level */
#include "session.h"
struct osmo_cc_call;
typedef struct osmo_cc_screen_list {
struct osmo_cc_screen_list *next;
int has_from_type;
uint8_t from_type;
int has_from_present;
uint8_t from_present;
char from[128];
int has_to_type;
uint8_t to_type;
int has_to_present;
uint8_t to_present;
char to[128];
} osmo_cc_screen_list_t;
/* endpoint instance */
typedef struct osmo_cc_endpoint {
struct osmo_cc_endpoint *next;
void *priv;
void (*ll_msg_cb)(struct osmo_cc_endpoint *ep, uint32_t callref, osmo_cc_msg_t *msg);
void (*ul_msg_cb)(struct osmo_cc_call *call, osmo_cc_msg_t *msg);
osmo_cc_msg_list_t *ll_queue; /* messages towards lower layer */
struct osmo_cc_call *call_list;
const char *local_name; /* name of interface */
const char *local_address; /* host+port */
const char *local_host;
uint16_t local_port;
const char *remote_address; /* host+port */
const char *remote_host;
uint16_t remote_port;
uint8_t serving_location;
osmo_cc_socket_t os;
osmo_cc_screen_list_t *screen_calling_in;
osmo_cc_screen_list_t *screen_called_in;
osmo_cc_screen_list_t *screen_calling_out;
osmo_cc_screen_list_t *screen_called_out;
int remote_auto; /* automatic remote address */
struct timer attach_timer; /* timer to retry attachment */
osmo_cc_session_config_t session_config; /* SDP/RTP default configuration */
} osmo_cc_endpoint_t;
extern osmo_cc_endpoint_t *osmo_cc_endpoint_list;
/* call process */
typedef struct osmo_cc_call {
struct osmo_cc_call *next;
osmo_cc_endpoint_t *ep;
enum osmo_cc_state state;
int lower_layer_released; /* when lower layer sent release, while upper layer gets a disconnect */
int upper_layer_released; /* when upper layer sent release, while lower layer gets a disconnect */
uint32_t callref;
osmo_cc_msg_list_t *sock_queue; /* messages from socket */
const char *attached_host; /* host and port from remote peer that attached to us */
uint16_t attached_port;
const char *attached_name; /* interface name from remote peer that attached to us */
} osmo_cc_call_t;
/* returns 0 if ok
* returns <0 for error as indicated
* returns >=1 to indicate osmo-cc error code
*/
void osmo_cc_help(void);
int osmo_cc_new(osmo_cc_endpoint_t *ep, const char *version, const char *name, uint8_t serving_location, void (*ll_msg_cb)(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg), void (*ul_msg_cb)(osmo_cc_call_t *call, osmo_cc_msg_t *msg), void *priv, int argc, const char *argv[]);
void osmo_cc_delete(struct osmo_cc_endpoint *ep);
int osmo_cc_handle(void);
osmo_cc_call_t *osmo_cc_call_by_callref(osmo_cc_endpoint_t *ep, uint32_t callref);
osmo_cc_call_t *osmo_cc_get_attached_interface(osmo_cc_endpoint_t *ep, const char *interface);
void osmo_cc_ll_msg(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg);
void osmo_cc_ul_msg(void *priv, uint32_t callref, osmo_cc_msg_t *msg);
osmo_cc_call_t *osmo_cc_call_new(osmo_cc_endpoint_t *ep);
void osmo_cc_call_delete(struct osmo_cc_call *call);
enum osmo_cc_session_addrtype osmo_cc_address_type(const char *address);
const char *osmo_cc_host_of_address(const char *address);
const char *osmo_cc_port_of_address(const char *address);
#include "rtp.h"
#include "sdp.h"
#include "screen.h"
#endif /* OSMO_CC_ENDPOINT_H */

View File

@ -1,194 +0,0 @@
/* Osmo-CC: helpers to simplify Osmo-CC usage
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include <inttypes.h>
#include "../libtimer/timer.h"
#include "../libselect/select.h"
#include "../libdebug/debug.h"
#include "endpoint.h"
#include "helper.h"
osmo_cc_session_t *osmo_cc_helper_audio_offer(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), osmo_cc_msg_t *msg, int debug)
{
osmo_cc_session_t *session;
osmo_cc_session_media_t *media;
const char *sdp;
int i;
session = osmo_cc_new_session(conf, priv, NULL, NULL, NULL, 0, 0, NULL, NULL, debug);
if (!session)
return NULL;
media = osmo_cc_add_media(session, 0, 0, NULL, osmo_cc_session_media_type_audio, 0, osmo_cc_session_media_proto_rtp, 1, 1, receiver, debug);
osmo_cc_rtp_open(media);
for (i = 0; codecs[i].payload_name; i++)
osmo_cc_add_codec(media, codecs[i].payload_name, codecs[i].payload_rate, codecs[i].payload_channels, codecs[i].encoder, codecs[i].decoder, debug);
sdp = osmo_cc_session_send_offer(session);
osmo_cc_add_ie_sdp(msg, sdp);
return session;
}
const char *osmo_cc_helper_audio_accept(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), osmo_cc_msg_t *msg, osmo_cc_session_t **session_p, osmo_cc_session_codec_t **codec_p, int force_our_codec)
{
char offer_sdp[65536];
const char *accept_sdp;
osmo_cc_session_media_t *media, *selected_media;
osmo_cc_session_codec_t *codec, *selected_codec, *telephone_event;
int rc;
int i, selected_codec_i, telephone_event_i;
if (*session_p) {
LOGP(DCC, LOGL_ERROR, "Session already set, please fix!\n");
abort();
}
if (*codec_p) {
LOGP(DCC, LOGL_ERROR, "Codec already set, please fix!\n");
abort();
}
/* SDP IE */
rc = osmo_cc_get_ie_sdp(msg, 0, offer_sdp, sizeof(offer_sdp));
if (rc < 0) {
LOGP(DCC, LOGL_ERROR, "There is no SDP included in setup request.\n");
return NULL;
}
*session_p = osmo_cc_session_receive_offer(conf, priv, offer_sdp);
if (!*session_p) {
LOGP(DCC, LOGL_ERROR, "Failed to parse SDP.\n");
return NULL;
}
selected_media = NULL;
osmo_cc_session_for_each_media((*session_p)->media_list, media) {
/* only audio */
if (media->description.type != osmo_cc_session_media_type_audio)
continue;
selected_codec_i = -1;
selected_codec = NULL;
telephone_event_i = -1;
telephone_event = NULL;
osmo_cc_session_for_each_codec(media->codec_list, codec) {
if (!!strcasecmp(codec->payload_name, "telephone-event")) {
for (i = 0; codecs[i].payload_name; i++) {
if (osmo_cc_session_if_codec(codec, codecs[i].payload_name, codecs[i].payload_rate, codecs[i].payload_channels)) {
/* select the first matchting codec or the one we prefer */
if (selected_codec_i < 0 || i < selected_codec_i) {
selected_codec = codec;
selected_codec_i = i;
selected_media = media;
}
/* if we don't force our preferred codec, use the preferred one from the remote */
if (!force_our_codec)
break;
}
}
} else {
/* special case: add telephone-event, if supported */
for (i = 0; codecs[i].payload_name; i++) {
if (!!strcasecmp(codecs[i].payload_name, "telephone-event"))
continue;
telephone_event = codec;
telephone_event_i = i;
break;
}
}
}
/* codec is selected within this media, we are done */
if (selected_codec)
break;
}
if (!selected_codec) {
LOGP(DCC, LOGL_ERROR, "No codec found in setup message that we support.\n");
osmo_cc_free_session(*session_p);
*session_p = NULL;
return NULL;
}
osmo_cc_session_accept_codec(selected_codec, codecs[selected_codec_i].encoder, codecs[selected_codec_i].decoder);
if (telephone_event)
osmo_cc_session_accept_codec(telephone_event, codecs[telephone_event_i].encoder, codecs[telephone_event_i].decoder);
osmo_cc_session_accept_media(selected_media, 0, 0, NULL, 1, 1, receiver);
osmo_cc_rtp_open(selected_media);
osmo_cc_rtp_connect(selected_media);
*codec_p = selected_codec;
accept_sdp = osmo_cc_session_send_answer(*session_p);
if (!accept_sdp) {
osmo_cc_free_session(*session_p);
*session_p = NULL;
return NULL;
}
return accept_sdp;
}
int osmo_cc_helper_audio_negotiate(osmo_cc_msg_t *msg, osmo_cc_session_t **session_p, osmo_cc_session_codec_t **codec_p)
{
char sdp[65536];
osmo_cc_session_media_t *media;
int rc;
if (!(*session_p)) {
LOGP(DCC, LOGL_ERROR, "Session not set, please fix!\n");
abort();
}
/* once done, just ignore further messages that reply to setup */
if (*codec_p)
return 0;
/* SDP IE */
rc = osmo_cc_get_ie_sdp(msg, 0, sdp, sizeof(sdp));
if (rc < 0)
return 0; // no reply in this message
rc = osmo_cc_session_receive_answer(*session_p, sdp);
if (rc < 0)
return rc;
osmo_cc_session_for_each_media((*session_p)->media_list, media) {
/* only audio */
if (media->description.type != osmo_cc_session_media_type_audio)
continue;
/* select first codec, if one was accpeted */
if (media->codec_list)
*codec_p = media->codec_list;
if (*codec_p) {
osmo_cc_rtp_connect(media);
/* no more media streams */
break;
}
}
if (!(*codec_p)) {
LOGP(DCC, LOGL_ERROR, "No codec found in setup reply message that we support.\n");
return -EIO;
}
return 0;
}

View File

@ -1,13 +0,0 @@
struct osmo_cc_helper_audio_codecs {
const char *payload_name;
uint32_t payload_rate;
int payload_channels;
void (*encoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void (*decoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
};
osmo_cc_session_t *osmo_cc_helper_audio_offer(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), osmo_cc_msg_t *msg, int debug);
const char *osmo_cc_helper_audio_accept(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), osmo_cc_msg_t *msg, osmo_cc_session_t **session_p, osmo_cc_session_codec_t **codec_p, int force_our_codec);
int osmo_cc_helper_audio_negotiate(osmo_cc_msg_t *msg, osmo_cc_session_t **session_p, osmo_cc_session_codec_t **codec_p);

File diff suppressed because it is too large Load Diff

View File

@ -1,513 +0,0 @@
#ifndef OSMO_CC_MSG_H
#define OSMO_CC_MSG_H
#define OSMO_CC_VERSION "OSMOCCv1"
/* call control messages types */
enum osmo_cc_msg_type {
OSMO_CC_MSG_SETUP_REQ = 0x00,
OSMO_CC_MSG_SETUP_IND = 0x01,
OSMO_CC_MSG_REJ_REQ = 0x10,
OSMO_CC_MSG_REJ_IND = 0x11,
OSMO_CC_MSG_SETUP_ACK_REQ = 0x20,
OSMO_CC_MSG_SETUP_ACK_IND = 0x21,
OSMO_CC_MSG_PROC_REQ = 0x30,
OSMO_CC_MSG_PROC_IND = 0x31,
OSMO_CC_MSG_ALERT_REQ = 0x40,
OSMO_CC_MSG_ALERT_IND = 0x41,
OSMO_CC_MSG_SETUP_RSP = 0x02,
OSMO_CC_MSG_SETUP_CNF = 0x03,
OSMO_CC_MSG_SETUP_COMP_REQ = 0x50,
OSMO_CC_MSG_SETUP_COMP_IND = 0x51,
OSMO_CC_MSG_DISC_REQ = 0x60,
OSMO_CC_MSG_DISC_IND = 0x61,
OSMO_CC_MSG_REL_REQ = 0x70,
OSMO_CC_MSG_REL_CNF = 0x73,
OSMO_CC_MSG_REL_IND = 0x71,
OSMO_CC_MSG_PROGRESS_REQ = 0x80,
OSMO_CC_MSG_PROGRESS_IND = 0x81,
OSMO_CC_MSG_NOTIFY_REQ = 0x84,
OSMO_CC_MSG_NOTIFY_IND = 0x85,
OSMO_CC_MSG_INFO_REQ = 0x88,
OSMO_CC_MSG_INFO_IND = 0x89,
OSMO_CC_MSG_MODIFY_REQ = 0x90,
OSMO_CC_MSG_MODIFY_IND = 0x91,
OSMO_CC_MSG_MODIFY_RSP = 0x92,
OSMO_CC_MSG_MODIFY_CNF = 0x93,
OSMO_CC_MSG_ATTACH_REQ = 0xf8,
OSMO_CC_MSG_ATTACH_IND = 0xf9,
OSMO_CC_MSG_ATTACH_RSP = 0xfa,
OSMO_CC_MSG_ATTACH_CNF = 0xfb,
OSMO_CC_MSG_DUMMY_REQ = 0xfc,
};
#define OSMO_CC_MSG_NUM 0x100
#define OSMO_CC_MSG_MASK 0x03,
#define OSMO_CC_MSG_REQ 0x00,
#define OSMO_CC_MSG_IND 0x01,
#define OSMO_CC_MSG_RSP 0x02,
#define OSMO_CC_MSG_CNF 0x03,
const char *osmo_cc_msg_value2name(int value);
int osmo_cc_msg_name2value(const char *name);
/* information elements */
enum osmo_cc_ie_type {
OSMO_CC_IE_CALLED = 0x11,
OSMO_CC_IE_CALLED_SUB = 0x12,
OSMO_CC_IE_CALLED_NAME = 0x13,
OSMO_CC_IE_CALLED_INTERFACE = 0x14,
OSMO_CC_IE_DTMF = 0x1d,
OSMO_CC_IE_KEYPAD = 0x1e,
OSMO_CC_IE_COMPLETE = 0x1f,
OSMO_CC_IE_CALLING = 0x21,
OSMO_CC_IE_CALLING_SUB = 0x22,
OSMO_CC_IE_CALLING_NAME = 0x23,
OSMO_CC_IE_CALLING_INTERFACE = 0x24,
OSMO_CC_IE_CALLING_NETWORK = 0x2f,
OSMO_CC_IE_REDIR = 0x31,
OSMO_CC_IE_PROGRESS = 0x32,
OSMO_CC_IE_NOTIFY = 0x33,
OSMO_CC_IE_DISPLAY = 0x34,
OSMO_CC_IE_CAUSE = 0x41,
OSMO_CC_IE_BEARER = 0x51,
OSMO_CC_IE_SDP = 0x52,
OSMO_CC_IE_SOCKET_ADDRESS = 0x5e,
OSMO_CC_IE_PRIVATE = 0x5f,
};
#define OSMO_CC_IE_NUM 0x100
const char *osmo_cc_ie_value2name(int value);
int osmo_cc_ie_name2value(const char *name);
/* type of number, see ITU-T Rec. Q.931 */
#define OSMO_CC_TYPE_UNKNOWN 0
#define OSMO_CC_TYPE_INTERNATIONAL 1
#define OSMO_CC_TYPE_NATIONAL 2
#define OSMO_CC_TYPE_NETWORK 3
#define OSMO_CC_TYPE_SUBSCRIBER 4
#define OSMO_CC_TYPE_ABBREVIATED 5
#define OSMO_CC_TYPE_RESERVED 7
#define OSMO_CC_TYPE_NUM 8
const char *osmo_cc_type_value2name(int value);
int osmo_cc_type_name2value(const char *name);
/* numbering plan, see ITU-T Rec. Q.931 */
#define OSMO_CC_PLAN_UNKNOWN 0
#define OSMO_CC_PLAN_TELEPHONY 1
#define OSMO_CC_PLAN_DATA 3
#define OSMO_CC_PLAN_TTY 4
#define OSMO_CC_PLAN_NATIONAL_STANDARD 8
#define OSMO_CC_PLAN_PRIVATE 9
#define OSMO_CC_PLAN_RESERVED 15
#define OSMO_CC_PLAN_NUM 16
const char *osmo_cc_plan_value2name(int value);
int osmo_cc_plan_name2value(const char *name);
/* presentation indicator, see ITU-T Rec. Q.931 */
#define OSMO_CC_PRESENT_ALLOWED 0
#define OSMO_CC_PRESENT_RESTRICTED 1
#define OSMO_CC_PRESENT_NOT_AVAIL 2
#define OSMO_CC_PRESENT_RESERVED 3
#define OSMO_CC_PRESENT_NUM 4
const char *osmo_cc_present_value2name(int value);
int osmo_cc_present_name2value(const char *name);
/* screening indicator, see ITU-T Rec. Q.931 */
#define OSMO_CC_SCREEN_USER_UNSCREENED 0
#define OSMO_CC_SCREEN_USER_VERIFIED_PASSED 1
#define OSMO_CC_SCREEN_USER_VERIFIED_FAILED 2
#define OSMO_CC_SCREEN_NETWORK 3
#define OSMO_CC_SCREEN_NUM 4
const char *osmo_cc_screen_value2name(int value);
int osmo_cc_screen_name2value(const char *name);
/* screening indicator, see ITU-T Rec. Q.931 */
#define OSMO_CC_REDIR_REASON_UNKNOWN 0
#define OSMO_CC_REDIR_REASON_CFB 1
#define OSMO_CC_REDIR_REASON_CFNR 2
#define OSMO_CC_REDIR_REASON_CD 4
#define OSMO_CC_REDIR_REASON_CF_OUTOFORDER 9
#define OSMO_CC_REDIR_REASON_CF_BY_DTE 10
#define OSMO_CC_REDIR_REASON_CFU 15
#define OSMO_CC_REDIR_REASON_NUM 16
const char *osmo_cc_redir_reason_value2name(int value);
int osmo_cc_redir_reason_name2value(const char *name);
/* notification indicator, see ITU-T Rec. Q.931 ff. */
#define OSMO_CC_NOTIFY_USER_SUSPENDED 0x00
#define OSMO_CC_NOTIFY_USER_RESUMED 0x01
#define OSMO_CC_NOTIFY_BEARER_SERVICE_CHANGE 0x02
#define OSMO_CC_NOTIFY_CALL_COMPLETION_DELAY 0x03
#define OSMO_CC_NOTIFY_CONFERENCE_ESTABLISHED 0x42
#define OSMO_CC_NOTIFY_CONFERENCE_DISCONNECTED 0x43
#define OSMO_CC_NOTIFY_OTHER_PARTY_ADDED 0x44
#define OSMO_CC_NOTIFY_ISOLATED 0x45
#define OSMO_CC_NOTIFY_REATTACHED 0x46
#define OSMO_CC_NOTIFY_OTHER_PARTY_ISOLATED 0x47
#define OSMO_CC_NOTIFY_OTHER_PARTY_REATTACHED 0x48
#define OSMO_CC_NOTIFY_OTHER_PARTY_SPLIT 0x49
#define OSMO_CC_NOTIFY_OTHER_PARTY_DISCONNECTED 0x4a
#define OSMO_CC_NOTIFY_CONFERENCE_FLOATING 0x4b
#define OSMO_CC_NOTIFY_CONFERENCE_DISC_PREEMPT 0x4c /* disconnect preemted */
#define OSMO_CC_NOTIFY_CONFERENCE_FLOATING_SUP 0x4f /* served user preemted */
#define OSMO_CC_NOTIFY_CALL_IS_A_WAITING_CALL 0x60
#define OSMO_CC_NOTIFY_DIVERSION_ACTIVATED 0x68
#define OSMO_CC_NOTIFY_RESERVED_CT_1 0x69
#define OSMO_CC_NOTIFY_RESERVED_CT_2 0x6a
#define OSMO_CC_NOTIFY_REVERSE_CHARGING 0x6e
#define OSMO_CC_NOTIFY_REMOTE_HOLD 0x79
#define OSMO_CC_NOTIFY_REMOTE_RETRIEVAL 0x7a
#define OSMO_CC_NOTIFY_CALL_IS_DIVERTING 0x7b
#define OSMO_CC_NOTIFY_NUM 0x100
const char *osmo_cc_notify_value2name(int value);
int osmo_cc_notify_name2value(const char *name);
/* coding standard, see ITU-T Rec. Q.931 */
#define OSMO_CC_CODING_ITU_T 0
#define OSMO_CC_CODING_ISO_IEC 1
#define OSMO_CC_CODING_NATIONAL 2
#define OSMO_CC_CODING_STANDARD_SPECIFIC 3
#define OSMO_CC_CODING_NUM 4
const char *osmo_cc_coding_value2name(int value);
int osmo_cc_coding_name2value(const char *name);
/* cause, see ITU-T Rec. Q.850 */
#define OSMO_CC_ISDN_CAUSE_UNASSIGNED_NR 1
#define OSMO_CC_ISDN_CAUSE_NO_ROUTE_TRANSIT 2
#define OSMO_CC_ISDN_CAUSE_NO_ROUTE 3
#define OSMO_CC_ISDN_CAUSE_CHAN_UNACCEPT 6
#define OSMO_CC_ISDN_CAUSE_OP_DET_BARRING 8
#define OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR 16
#define OSMO_CC_ISDN_CAUSE_USER_BUSY 17
#define OSMO_CC_ISDN_CAUSE_USER_NOTRESPOND 18
#define OSMO_CC_ISDN_CAUSE_USER_ALERTING_NA 19
#define OSMO_CC_ISDN_CAUSE_CALL_REJECTED 21
#define OSMO_CC_ISDN_CAUSE_NUMBER_CHANGED 22
#define OSMO_CC_ISDN_CAUSE_PRE_EMPTION 25
#define OSMO_CC_ISDN_CAUSE_NONSE_USER_CLR 26
#define OSMO_CC_ISDN_CAUSE_DEST_OOO 27
#define OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT 28
#define OSMO_CC_ISDN_CAUSE_FACILITY_REJ 29
#define OSMO_CC_ISDN_CAUSE_RESP_STATUS_INQ 30
#define OSMO_CC_ISDN_CAUSE_NORMAL_UNSPEC 31
#define OSMO_CC_ISDN_CAUSE_NO_CIRCUIT_CHAN 34
#define OSMO_CC_ISDN_CAUSE_NETWORK_OOO 38
#define OSMO_CC_ISDN_CAUSE_TEMP_FAILURE 41
#define OSMO_CC_ISDN_CAUSE_SWITCH_CONG 42
#define OSMO_CC_ISDN_CAUSE_ACC_INF_DISCARD 43
#define OSMO_CC_ISDN_CAUSE_REQ_CHAN_UNAVAIL 44
#define OSMO_CC_ISDN_CAUSE_RESOURCE_UNAVAIL 47
#define OSMO_CC_ISDN_CAUSE_QOS_UNAVAIL 49
#define OSMO_CC_ISDN_CAUSE_REQ_FAC_NOT_SUBSC 50
#define OSMO_CC_ISDN_CAUSE_INC_BARRED_CUG 55
#define OSMO_CC_ISDN_CAUSE_BEARER_CAP_UNAUTH 57
#define OSMO_CC_ISDN_CAUSE_BEARER_CA_UNAVAIL 58
#define OSMO_CC_ISDN_CAUSE_SERV_OPT_UNAVAIL 63
#define OSMO_CC_ISDN_CAUSE_BEARERSERV_UNIMPL 65
#define OSMO_CC_ISDN_CAUSE_ACM_GE_ACM_MAX 68
#define OSMO_CC_ISDN_CAUSE_REQ_FAC_NOTIMPL 69
#define OSMO_CC_ISDN_CAUSE_RESTR_BCAP_AVAIL 70
#define OSMO_CC_ISDN_CAUSE_SERV_OPT_UNIMPL 79
#define OSMO_CC_ISDN_CAUSE_INVAL_CALLREF 81
#define OSMO_CC_ISDN_CAUSE_USER_NOT_IN_CUG 87
#define OSMO_CC_ISDN_CAUSE_INCOMPAT_DEST 88
#define OSMO_CC_ISDN_CAUSE_INVAL_TRANS_NET 91
#define OSMO_CC_ISDN_CAUSE_SEMANTIC_INCORR 95
#define OSMO_CC_ISDN_CAUSE_INVAL_MAND_INF 96
#define OSMO_CC_ISDN_CAUSE_MSGTYPE_NOTEXIST 97
#define OSMO_CC_ISDN_CAUSE_MSGTYPE_INCOMPAT 98
#define OSMO_CC_ISDN_CAUSE_IE_NOTEXIST 99
#define OSMO_CC_ISDN_CAUSE_COND_IE_ERR 100
#define OSMO_CC_ISDN_CAUSE_MSG_INCOMP_STATE 101
#define OSMO_CC_ISDN_CAUSE_RECOVERY_TIMER 102
#define OSMO_CC_ISDN_CAUSE_PROTO_ERR 111
#define OSMO_CC_ISDN_CAUSE_INTERWORKING 127
#define OSMO_CC_ISDN_CAUSE_NUM 128
const char *osmo_cc_isdn_cause_value2name(int value);
int osmo_cc_isdn_cause_name2value(const char *name);
/* location, see ITU-T Rec. Q.931 */
#define OSMO_CC_LOCATION_USER 0
#define OSMO_CC_LOCATION_PRIV_SERV_LOC_USER 1
#define OSMO_CC_LOCATION_PUB_SERV_LOC_USER 2
#define OSMO_CC_LOCATION_TRANSIT 3
#define OSMO_CC_LOCATION_PUB_SERV_REM_USER 4
#define OSMO_CC_LOCATION_PRIV_SERV_REM_USER 5
#define OSMO_CC_LOCATION_BEYOND_INTERWORKING 10
#define OSMO_CC_LOCATION_NUM 16
const char *osmo_cc_location_value2name(int value);
int osmo_cc_location_name2value(const char *name);
/* progress description, see ITU-T Rec. Q.931 */
#define OSMO_CC_PROGRESS_NOT_END_TO_END_ISDN 1
#define OSMO_CC_PROGRESS_DEST_NOT_ISDN 2
#define OSMO_CC_PROGRESS_ORIG_NOT_ISDN 3
#define OSMO_CC_PROGRESS_RETURN_TO_ISDN 4
#define OSMO_CC_PROGRESS_INTERWORKING 5
#define OSMO_CC_PROGRESS_INBAND_INFO_AVAILABLE 8
#define OSMO_CC_PROGRESS_NUM 16
const char *osmo_cc_progress_value2name(int value);
int osmo_cc_progress_name2value(const char *name);
/* information transfer capability, see ITU-T Rec. Q.931 */
#define OSMO_CC_CAPABILITY_SPEECH 0
#define OSMO_CC_CAPABILITY_DATA 8
#define OSMO_CC_CAPABILITY_DATA_RESTRICTED 9
#define OSMO_CC_CAPABILITY_AUDIO 16
#define OSMO_CC_CAPABILITY_DATA_WITH_TONES 17
#define OSMO_CC_CAPABILITY_VIDEO 24
#define OSMO_CC_CAPABILITY_NUM 32
const char *osmo_cc_capability_value2name(int value);
int osmo_cc_capability_name2value(const char *name);
/* transfer mode, see ITU-T Rec. Q.931 */
#define OSMO_CC_MODE_CIRCUIT 0
#define OSMO_CC_MODE_PACKET 2
#define OSMO_CC_MODE_NUM 4
const char *osmo_cc_mode_value2name(int value);
int osmo_cc_mode_name2value(const char *name);
#define OSMO_CC_DTMF_MODE_OFF 0 /* stop tone */
#define OSMO_CC_DTMF_MODE_ON 1 /* start tone */
#define OSMO_CC_DTMF_MODE_DIGITS 2 /* play tone(s) with duration and pauses */
#define OSMO_CC_DTMF_MODE_NUM 3
const char *osmo_cc_dtmf_mode_value2name(int value);
int osmo_cc_dtmf_mode_name2value(const char *name);
#define OSMO_CC_SOCKET_CAUSE_VERSION_MISMATCH 1 /* version mismatch */
#define OSMO_CC_SOCKET_CAUSE_FAILED 2 /* connection failed */
#define OSMO_CC_SOCKET_CAUSE_BROKEN_PIPE 3 /* connected socket failed */
#define OSMO_CC_SOCKET_CAUSE_TIMEOUT 4 /* keepalive packets timeout */
// if you add causes here, add them in process_cause.c also!
#define OSMO_CC_SOCKET_CAUSE_NUM 5
const char *osmo_cc_socket_cause_value2name(int value);
int osmo_cc_socket_cause_name2value(const char *name);
/* network type (network IE) and meaning of 'id' */
#define OSMO_CC_NETWORK_UNDEFINED 0x00
#define OSMO_CC_NETWORK_ALSA_NONE 0x01
#define OSMO_CC_NETWORK_POTS_NONE 0x02
#define OSMO_CC_NETWORK_ISDN_NONE 0x03
#define OSMO_CC_NETWORK_SIP_NONE 0x04
#define OSMO_CC_NETWORK_GSM_IMSI 0x05 /* id has decimal IMSI */
#define OSMO_CC_NETWORK_GSM_IMEI 0x06 /* id has decimal IMEI */
#define OSMO_CC_NETWORK_WEB_NONE 0x07
#define OSMO_CC_NETWORK_DECT_NONE 0x08
#define OSMO_CC_NETWORK_BLUETOOTH_NONE 0x09
#define OSMO_CC_NETWORK_SS5_NONE 0x0a
#define OSMO_CC_NETWORK_R1_NONE 0x0b
#define OSMO_CC_NETWORK_ANETZ_NONE 0x80
#define OSMO_CC_NETWORK_BNETZ_MUENZ 0x81 /* id starts with 'M' */
#define OSMO_CC_NETWORK_CNETZ_NONE 0x82
#define OSMO_CC_NETWORK_NMT_NONE 0x83 /* id has decimal password */
#define OSMO_CC_NETWORK_R2000_NONE 0x84
#define OSMO_CC_NETWORK_AMPS_ESN 0x85 /* if has decimal ESN (TACS also) */
#define OSMO_CC_NETWORK_MTS_NONE 0x86
#define OSMO_CC_NETWORK_IMTS_NONE 0x87
#define OSMO_CC_NETWORK_EUROSIGNAL_NONE 0x88
#define OSMO_CC_NETWORK_JOLLYCOM_NONE 0x89 /* call from JollyCom... */
#define OSMO_CC_NETWORK_MPT1327_PSTN 0x8a /* call from MPT1327 */
#define OSMO_CC_NETWORK_MPT1327_PBX 0x8b /* id is selected PBX number */
#define OSMO_CC_NETWORK_NUM 0x100
const char *osmo_cc_network_value2name(int value);
int osmo_cc_network_name2value(const char *name);
typedef struct osmo_cc_msg {
uint8_t type;
uint16_t length_networkorder;
uint8_t data[0];
} __attribute__((packed)) osmo_cc_msg_t;
typedef struct osmo_cc_msg_list {
struct osmo_cc_msg_list *next;
struct osmo_cc_msg *msg;
uint32_t callref;
char host[128];
uint16_t port;
} osmo_cc_msg_list_t;
typedef struct osmo_cc_ie {
uint8_t type;
uint16_t length_networkorder;
uint8_t data[0];
} __attribute__((packed)) osmo_cc_ie_t;
struct osmo_cc_ie_called {
uint8_t type;
uint8_t plan;
char digits[0];
} __attribute__((packed));
struct osmo_cc_ie_called_sub {
uint8_t type;
char digits[0];
} __attribute__((packed));
struct osmo_cc_ie_called_name {
char name[0];
} __attribute__((packed));
struct osmo_cc_ie_called_interface {
char name[0];
} __attribute__((packed));
struct osmo_cc_ie_calling {
uint8_t type;
uint8_t plan;
uint8_t present;
uint8_t screen;
char digits[0];
} __attribute__((packed));
struct osmo_cc_ie_calling_sub {
uint8_t type;
char digits[0];
} __attribute__((packed));
struct osmo_cc_ie_calling_name {
char name[0];
} __attribute__((packed));
struct osmo_cc_ie_calling_interface {
char name[0];
} __attribute__((packed));
struct osmo_cc_ie_network {
uint8_t type;
char id[0];
} __attribute__((packed));
struct osmo_cc_ie_bearer {
uint8_t coding;
uint8_t capability;
uint8_t mode;
} __attribute__((packed));
struct osmo_cc_ie_redir {
uint8_t type;
uint8_t plan;
uint8_t present;
uint8_t screen;
uint8_t redir_reason;
char digits[0];
} __attribute__((packed));
struct osmo_cc_ie_dtmf {
uint8_t duration_ms;
uint8_t pause_ms;
uint8_t dtmf_mode;
char digits[0];
} __attribute__((packed));
struct osmo_cc_ie_keypad {
char digits[0];
} __attribute__((packed));
struct osmo_cc_ie_progress {
uint8_t coding;
uint8_t location;
uint8_t progress;
} __attribute__((packed));
struct osmo_cc_ie_notify {
uint8_t notify;
} __attribute__((packed));
struct osmo_cc_ie_cause {
uint8_t location;
uint8_t isdn_cause;
uint16_t sip_cause_networkorder;
uint8_t socket_cause;
} __attribute__((packed));
struct osmo_cc_ie_display {
char text[0];
} __attribute__((packed));
struct osmo_cc_ie_sdp {
char sdp[0];
} __attribute__((packed));
struct osmo_cc_ie_socket_address {
char address[0];
} __attribute__((packed));
struct osmo_cc_ie_private {
uint32_t unique_networkorder;
uint8_t data[0];
} __attribute__((packed));
uint32_t osmo_cc_new_callref(void);
osmo_cc_msg_t *osmo_cc_new_msg(uint8_t msg_type);
osmo_cc_msg_t *osmo_cc_clone_msg(osmo_cc_msg_t *msg);
osmo_cc_msg_t *osmo_cc_msg_list_dequeue(osmo_cc_msg_list_t **mlp, uint32_t *callref_p);
osmo_cc_msg_list_t *osmo_cc_msg_list_enqueue(osmo_cc_msg_list_t **mlp, osmo_cc_msg_t *msg, uint32_t callref);
void osmo_cc_free_msg(osmo_cc_msg_t *msg);
void osmo_cc_debug_ie(osmo_cc_msg_t *msg, int level);
int osmo_cc_get_ie_struct(osmo_cc_msg_t *msg, uint8_t ie_type, int ie_repeat, int ie_len, const osmo_cc_ie_t **ie_struct);
int osmo_cc_get_ie_data(osmo_cc_msg_t *msg, uint8_t ie_type, int ie_repeat, int ie_len, const void **ie_data);
int osmo_cc_has_ie(osmo_cc_msg_t *msg, uint8_t ie_type, int ie_repeat);
int osmo_cc_remove_ie(osmo_cc_msg_t *msg, uint8_t ie_type, int ie_repeat);
void *osmo_cc_add_ie(osmo_cc_msg_t *msg, uint8_t ie_type, int ie_len);
void *osmo_cc_msg_sep_ie(osmo_cc_msg_t *msg, void **iep, uint8_t *ie_type, uint16_t *ie_length);
void osmo_cc_add_ie_called(osmo_cc_msg_t *msg, uint8_t type, uint8_t plan, const char *dialing);
int osmo_cc_get_ie_called(osmo_cc_msg_t *msg, int ie_repeat, uint8_t *type, uint8_t *plan, char *dialing, size_t dialing_size);
void osmo_cc_add_ie_called_sub(osmo_cc_msg_t *msg, uint8_t type, const char *dialing);
int osmo_cc_get_ie_called_sub(osmo_cc_msg_t *msg, int ie_repeat, uint8_t *type, char *dialing, size_t dialing_size);
void osmo_cc_add_ie_called_name(osmo_cc_msg_t *msg, const char *name);
int osmo_cc_get_ie_called_name(osmo_cc_msg_t *msg, int ie_repeat, char *name, size_t name_size);
void osmo_cc_add_ie_called_interface(osmo_cc_msg_t *msg, const char *interface);
int osmo_cc_get_ie_called_interface(osmo_cc_msg_t *msg, int ie_repeat, char *interface, size_t interface_size);
void osmo_cc_add_ie_complete(osmo_cc_msg_t *msg);
int osmo_cc_get_ie_complete(osmo_cc_msg_t *msg, int ie_repeat);
void osmo_cc_add_ie_calling(osmo_cc_msg_t *msg, uint8_t type, uint8_t plan, uint8_t present, uint8_t screen, const char *callerid);
int osmo_cc_get_ie_calling(osmo_cc_msg_t *msg, int ie_repeat, uint8_t *type, uint8_t *plan, uint8_t *present, uint8_t *screen, char *callerid, size_t callerid_size);
void osmo_cc_add_ie_calling_sub(osmo_cc_msg_t *msg, uint8_t type, const char *callerid);
int osmo_cc_get_ie_calling_sub(osmo_cc_msg_t *msg, int ie_repeat, uint8_t *type, char *callerid, size_t callerid_size);
void osmo_cc_add_ie_calling_name(osmo_cc_msg_t *msg, const char *name);
int osmo_cc_get_ie_calling_name(osmo_cc_msg_t *msg, int ie_repeat, char *name, size_t name_size);
void osmo_cc_add_ie_calling_interface(osmo_cc_msg_t *msg, const char *interface);
int osmo_cc_get_ie_calling_interface(osmo_cc_msg_t *msg, int ie_repeat, char *interface, size_t interface_size);
void osmo_cc_add_ie_calling_network(osmo_cc_msg_t *msg, uint8_t type, const char *networkid);
int osmo_cc_get_ie_calling_network(osmo_cc_msg_t *msg, int ie_repeat, uint8_t *type, char *networkid, size_t networkid_size);
void osmo_cc_add_ie_bearer(osmo_cc_msg_t *msg, uint8_t coding, uint8_t capability, uint8_t mode);
int osmo_cc_get_ie_bearer(osmo_cc_msg_t *msg, int ie_repeat, uint8_t *coding, uint8_t *capability, uint8_t *mode);
void osmo_cc_add_ie_redir(osmo_cc_msg_t *msg, uint8_t type, uint8_t plan, uint8_t present, uint8_t screen, uint8_t redir_reason, const char *callerid);
int osmo_cc_get_ie_redir(osmo_cc_msg_t *msg, int ie_repeat, uint8_t *type, uint8_t *plan, uint8_t *present, uint8_t *screen, uint8_t *reason, char *callerid, size_t callerid_size);
void osmo_cc_add_ie_dtmf(osmo_cc_msg_t *msg, uint8_t duration_ms, uint8_t pause_ms, uint8_t dtmf_mode, const char *digits);
int osmo_cc_get_ie_dtmf(osmo_cc_msg_t *msg, int ie_repeat, uint8_t *duration_ms, uint8_t *pause_ms, uint8_t *dtmf_mode, char *digits, size_t digits_size);
void osmo_cc_add_ie_keypad(osmo_cc_msg_t *msg, const char *digits);
int osmo_cc_get_ie_keypad(osmo_cc_msg_t *msg, int ie_repeat, char *digits, size_t digits_size);
void osmo_cc_add_ie_progress(osmo_cc_msg_t *msg, uint8_t coding, uint8_t location, uint8_t progress);
int osmo_cc_get_ie_progress(osmo_cc_msg_t *msg, int ie_repeat, uint8_t *coding, uint8_t *location, uint8_t *progress);
void osmo_cc_add_ie_notify(osmo_cc_msg_t *msg, uint8_t notify);
int osmo_cc_get_ie_notify(osmo_cc_msg_t *msg, int ie_repeat, uint8_t *notify);
void osmo_cc_add_ie_cause(osmo_cc_msg_t *msg, uint8_t location, uint8_t isdn_cause, uint16_t sip_cause, uint8_t socket_cause);
int osmo_cc_get_ie_cause(osmo_cc_msg_t *msg, int ie_repeat, uint8_t *location, uint8_t *isdn_cause, uint16_t *sip_cause, uint8_t *socket_cause);
void osmo_cc_add_ie_display(osmo_cc_msg_t *msg, const char *text);
int osmo_cc_get_ie_display(osmo_cc_msg_t *msg, int ie_repeat, char *text, size_t text_size);
void osmo_cc_add_ie_sdp(osmo_cc_msg_t *msg, const char *sdp);
int osmo_cc_get_ie_sdp(osmo_cc_msg_t *msg, int ie_repeat, char *sdp, size_t sdp_size);
void osmo_cc_add_ie_socket_address(osmo_cc_msg_t *msg, const char *address);
int osmo_cc_get_ie_socket_address(osmo_cc_msg_t *msg, int ie_repeat, char *address, size_t address_size);
void osmo_cc_add_ie_private(osmo_cc_msg_t *msg, uint32_t unique, const uint8_t *data, size_t data_size);
int osmo_cc_get_ie_private(osmo_cc_msg_t *msg, int ie_repeat, uint32_t *unique, uint8_t *data, size_t data_size);
#endif /* OSMO_CC_MSG_H */

View File

@ -1,484 +0,0 @@
/* Osmo-CC: RTP handling
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include "../libdebug/debug.h"
#include "../libtimer/timer.h"
#include "../libselect/select.h"
#include "endpoint.h"
#define RTP_VERSION 2
void osmo_cc_set_rtp_ports(osmo_cc_session_config_t *conf, uint16_t from, uint16_t to)
{
conf->rtp_port_next = from;
conf->rtp_port_from = from;
conf->rtp_port_to = to;
}
struct rtp_hdr {
uint8_t byte0;
uint8_t byte1;
uint16_t sequence;
uint32_t timestamp;
uint32_t ssrc;
} __attribute__((packed));
struct rtp_x_hdr {
uint16_t by_profile;
uint16_t length;
} __attribute__((packed));
static int rtp_receive(struct sockaddr_storage *sa, socklen_t *slen, int sock, uint8_t **payload_p, int *payload_len_p, uint8_t *marker_p, uint8_t *pt_p, uint16_t *sequence_p, uint32_t *timestamp_p, uint32_t *ssrc_p)
{
static uint8_t data[2048];
int len;
struct rtp_hdr *rtph = (struct rtp_hdr *)data;
uint8_t version, padding, extension, csrc_count, marker, payload_type;
struct rtp_x_hdr *rtpxh;
uint8_t *payload;
int payload_len;
int x_len;
len = recvfrom(sock, data, sizeof(data), 0, (struct sockaddr *)sa, slen);
if (len < 0) {
if (errno == EAGAIN)
return -EAGAIN;
LOGP(DCC, LOGL_DEBUG, "Read errno = %d (%s)\n", errno, strerror(errno));
return -EIO;
}
if (len < 12) {
LOGP(DCC, LOGL_NOTICE, "Received RTP frame too short (len = %d).\n", len);
return -EINVAL;
}
version = rtph->byte0 >> 6;
padding = (rtph->byte0 >> 5) & 1;
extension = (rtph->byte0 >> 4) & 1;
csrc_count = rtph->byte0 & 0x0f;
marker = rtph->byte1 >> 7;
payload_type = rtph->byte1 & 0x7f;
*sequence_p = ntohs(rtph->sequence);
*timestamp_p = ntohl(rtph->timestamp);
*ssrc_p = ntohl(rtph->ssrc);
if (version != RTP_VERSION) {
LOGP(DCC, LOGL_NOTICE, "Received RTP version %d not supported.\n", version);
return -EINVAL;
}
payload = data + sizeof(*rtph) + (csrc_count << 2);
payload_len = len - sizeof(*rtph) - (csrc_count << 2);
if (payload_len < 0) {
LOGP(DCC, LOGL_NOTICE, "Received RTP frame too short (len = %d, csrc count = %d).\n", len, csrc_count);
return -EINVAL;
}
if (extension) {
if (payload_len < (int)sizeof(*rtpxh)) {
LOGP(DCC, LOGL_NOTICE, "Received RTP frame too short for extension header.\n");
return -EINVAL;
}
rtpxh = (struct rtp_x_hdr *)payload;
x_len = ntohs(rtpxh->length) * 4 + sizeof(*rtpxh);
payload += x_len;
payload_len -= x_len;
if (payload_len < (int)sizeof(*rtpxh)) {
LOGP(DCC, LOGL_NOTICE, "Received RTP frame too short, extension header exceeds frame length.\n");
return -EINVAL;
}
}
if (padding) {
if (payload_len < 1) {
LOGP(DCC, LOGL_NOTICE, "Received RTP frame too short for padding length.\n");
return -EINVAL;
}
payload_len -= payload[payload_len - 1];
if (payload_len < 0) {
LOGP(DCC, LOGL_NOTICE, "Received RTP frame padding is greater than payload.\n");
return -EINVAL;
}
}
*payload_p = payload;
*payload_len_p = payload_len;
*marker_p = marker;
*pt_p = payload_type;
return 0;
}
static int rtcp_receive(struct sockaddr_storage *sa, socklen_t *slen, int sock)
{
static uint8_t data[2048];
int len;
len = recvfrom(sock, data, sizeof(data), 0, (struct sockaddr *)sa, slen);
if (len < 0) {
if (errno == EAGAIN)
return -EAGAIN;
LOGP(DCC, LOGL_DEBUG, "Read errno = %d (%s)\n", errno, strerror(errno));
return -EIO;
}
return 0;
}
static void rtp_send(struct sockaddr_storage *sa, socklen_t slen, int sock, uint8_t *payload, int payload_len, uint8_t marker, uint8_t pt, uint16_t sequence, uint32_t timestamp, uint32_t ssrc)
{
struct rtp_hdr *rtph;
char data[sizeof(*rtph) + payload_len];
int len, rc;
rtph = (struct rtp_hdr *)data;
len = sizeof(*rtph);
rtph->byte0 = RTP_VERSION << 6;
rtph->byte1 = pt | (marker << 7);
rtph->sequence = htons(sequence);
rtph->timestamp = htonl(timestamp);
rtph->ssrc = htonl(ssrc);
len += payload_len;
if (len > (int)sizeof(data)) {
LOGP(DCC, LOGL_NOTICE, "Buffer overflow, please fix!.\n");
abort();
}
memcpy(data + sizeof(*rtph), payload, payload_len);
rc = sendto(sock, data, len, 0, (struct sockaddr *)sa, slen);
if (rc < 0)
LOGP(DCC, LOGL_DEBUG, "sendto errno = %d (%s)\n", errno, strerror(errno));
}
static int rtp_listen_cb(struct osmo_fd *ofd, unsigned int when);
static int rtcp_listen_cb(struct osmo_fd *ofd, unsigned int when);
/* open and bind RTP
* set local port to what we bound
*/
int osmo_cc_rtp_open(osmo_cc_session_media_t *media)
{
osmo_cc_session_config_t *conf = media->session->config;
int domain = 0; // make GCC happy
uint16_t start_port;
struct sockaddr_storage sa;
socklen_t slen = 0; // make GCC happy
struct sockaddr_in6 *sa6;
struct sockaddr_in *sa4;
uint16_t *sport;
int flags;
int rc;
media->tx_ssrc = rand();
osmo_cc_rtp_close(media);
switch (media->connection_data_local.addrtype) {
case osmo_cc_session_addrtype_ipv4:
domain = AF_INET;
memset(&sa, 0, sizeof(sa));
sa4 = (struct sockaddr_in *)&sa;
sa4->sin_family = domain;
rc = inet_pton(AF_INET, media->connection_data_local.address, &sa4->sin_addr);
if (rc < 1) {
pton_error:
LOGP(DCC, LOGL_NOTICE, "Cannot bind to address '%s'.\n", media->connection_data_local.address);
return -EINVAL;
}
sport = &sa4->sin_port;
slen = sizeof(*sa4);
break;
case osmo_cc_session_addrtype_ipv6:
domain = AF_INET6;
memset(&sa, 0, sizeof(sa));
sa6 = (struct sockaddr_in6 *)&sa;
sa6->sin6_family = domain;
rc = inet_pton(AF_INET6, media->connection_data_local.address, &sa6->sin6_addr);
if (rc < 1)
goto pton_error;
sport = &sa6->sin6_port;
slen = sizeof(*sa6);
break;
case osmo_cc_session_addrtype_unknown:
LOGP(DCC, LOGL_NOTICE, "Unsupported address type '%s'.\n", media->connection_data_local.addrtype_name);
return -EINVAL;
}
/* rtp_port_from/rtp_port_to may be changed at run time, so rtp_port_next can become out of range. */
if (conf->rtp_port_next < conf->rtp_port_from || conf->rtp_port_next > conf->rtp_port_to)
conf->rtp_port_next = conf->rtp_port_from;
start_port = conf->rtp_port_next;
while (1) {
/* open sockets */
rc = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
if (rc < 0) {
socket_error:
LOGP(DCC, LOGL_ERROR, "Cannot create socket (domain=%d, errno=%d(%s))\n", domain, errno, strerror(errno));
osmo_cc_rtp_close(media);
return -EIO;
}
media->rtp_ofd.fd = rc;
media->rtp_ofd.cb = rtp_listen_cb;
media->rtp_ofd.data = media;
media->rtp_ofd.when = OSMO_FD_READ;
osmo_fd_register(&media->rtp_ofd);
rc = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
if (rc < 0)
goto socket_error;
media->rtcp_ofd.fd = rc;
media->rtcp_ofd.cb = rtcp_listen_cb;
media->rtcp_ofd.data = media;
media->rtcp_ofd.when = OSMO_FD_READ;
osmo_fd_register(&media->rtcp_ofd);
/* bind sockets */
*sport = htons(conf->rtp_port_next);
rc = bind(media->rtp_ofd.fd, (struct sockaddr *)&sa, slen);
if (rc < 0) {
bind_error:
osmo_cc_rtp_close(media);
conf->rtp_port_next = (conf->rtp_port_next + 2 > conf->rtp_port_to) ? conf->rtp_port_from : conf->rtp_port_next + 2;
if (conf->rtp_port_next == start_port) {
LOGP(DCC, LOGL_ERROR, "Cannot bind socket (errno=%d(%s))\n", errno, strerror(errno));
return -EIO;
}
continue;
}
*sport = htons(conf->rtp_port_next + 1);
rc = bind(media->rtcp_ofd.fd, (struct sockaddr *)&sa, slen);
if (rc < 0)
goto bind_error;
media->description.port_local = conf->rtp_port_next;
conf->rtp_port_next = (conf->rtp_port_next + 2 > conf->rtp_port_to) ? conf->rtp_port_from : conf->rtp_port_next + 2;
/* set nonblocking io, to prevent write to block */
flags = fcntl(media->rtp_ofd.fd, F_GETFL);
flags |= O_NONBLOCK;
fcntl(media->rtp_ofd.fd, F_SETFL, flags);
flags = fcntl(media->rtcp_ofd.fd, F_GETFL);
flags |= O_NONBLOCK;
fcntl(media->rtcp_ofd.fd, F_SETFL, flags);
break;
}
LOGP(DCC, LOGL_DEBUG, "Opening media port %d\n", media->description.port_local);
return 0;
}
/* connect RTP
* use remote port to connect to
*/
int osmo_cc_rtp_connect(osmo_cc_session_media_t *media)
{
struct sockaddr_in6 *sa6;
struct sockaddr_in *sa4;
int rc;
LOGP(DCC, LOGL_DEBUG, "Connecting media port %d->%d (remote %s)\n", media->description.port_local, media->description.port_remote, media->connection_data_remote.address);
switch (media->connection_data_remote.addrtype) {
case osmo_cc_session_addrtype_ipv4:
memset(&media->rtp_sa, 0, sizeof(media->rtp_sa));
sa4 = (struct sockaddr_in *)&media->rtp_sa;
sa4->sin_family = AF_INET;
rc = inet_pton(AF_INET, media->connection_data_remote.address, &sa4->sin_addr);
if (rc < 1) {
pton_error:
LOGP(DCC, LOGL_NOTICE, "Cannot connect to address '%s'.\n", media->connection_data_remote.address);
return -EINVAL;
}
media->rtp_sport = &sa4->sin_port;
media->rtp_slen = sizeof(*sa4);
memcpy(&media->rtcp_sa, &media->rtp_sa, sizeof(*sa4));
sa4 = (struct sockaddr_in *)&media->rtcp_sa;
media->rtcp_sport = &sa4->sin_port;
media->rtcp_slen = sizeof(*sa4);
break;
case osmo_cc_session_addrtype_ipv6:
memset(&media->rtp_sa, 0, sizeof(media->rtp_sa));
sa6 = (struct sockaddr_in6 *)&media->rtp_sa;
sa6->sin6_family = AF_INET6;
rc = inet_pton(AF_INET6, media->connection_data_remote.address, &sa6->sin6_addr);
if (rc < 1)
goto pton_error;
media->rtp_sport = &sa6->sin6_port;
media->rtp_slen = sizeof(*sa6);
memcpy(&media->rtcp_sa, &media->rtp_sa, sizeof(*sa6));
sa6 = (struct sockaddr_in6 *)&media->rtcp_sa;
media->rtcp_sport = &sa6->sin6_port;
media->rtcp_slen = sizeof(*sa6);
break;
case osmo_cc_session_addrtype_unknown:
LOGP(DCC, LOGL_NOTICE, "Unsupported address type '%s'.\n", media->connection_data_local.addrtype_name);
return -EINVAL;
}
*media->rtp_sport = htons(media->description.port_remote);
*media->rtcp_sport = htons(media->description.port_remote + 1);
return 0;
}
/* send rtp data with given codec */
void osmo_cc_rtp_send(osmo_cc_session_codec_t *codec, uint8_t *data, int len, uint8_t marker, int inc_sequence, int inc_timestamp, void *priv)
{
uint8_t *payload = NULL;
int payload_len = 0;
if (!codec || !codec->media->rtp_ofd.fd)
return;
if (codec->encoder)
codec->encoder(data, len, &payload, &payload_len, priv);
else {
payload = data;
payload_len = len;
}
rtp_send(&codec->media->rtp_sa, codec->media->rtp_slen, codec->media->rtp_ofd.fd, payload, payload_len, marker, codec->payload_type_remote, codec->media->tx_sequence, codec->media->tx_timestamp, codec->media->tx_ssrc);
codec->media->tx_sequence += inc_sequence;
codec->media->tx_timestamp += inc_timestamp;
if (codec->encoder)
free(payload);
}
static void check_port_translation(struct sockaddr_storage *sa, struct sockaddr_storage *media_sa, const char *what)
{
struct sockaddr_in6 *sa6, *sa6_2;
struct sockaddr_in *sa4, *sa4_2;
int from = 0, to = 0;
if (sa->ss_family != media_sa->ss_family)
return;
switch (sa->ss_family) {
case AF_INET:
sa4 = (struct sockaddr_in *)sa;
sa4_2 = (struct sockaddr_in *)media_sa;
if (sa4->sin_port != sa4_2->sin_port) {
if (!!memcmp(&sa4->sin_addr, &sa4_2->sin_addr, sizeof(struct in_addr)))
break;
from = ntohs(sa4_2->sin_port);
to = ntohs(sa4->sin_port);
sa4_2->sin_port = sa4->sin_port;
}
break;
case AF_INET6:
sa6 = (struct sockaddr_in6 *)sa;
sa6_2 = (struct sockaddr_in6 *)media_sa;
if (sa6->sin6_port != sa6_2->sin6_port) {
if (!!memcmp(&sa6->sin6_addr, &sa6_2->sin6_addr, sizeof(struct in6_addr)))
break;
from = ntohs(sa6_2->sin6_port);
to = ntohs(sa6->sin6_port);
sa6_2->sin6_port = sa6->sin6_port;
}
break;
}
if (from)
LOGP(DCC, LOGL_NOTICE, "Remote sends with different %s port, changing from %d to %d!\n", what, from, to);
}
static int rtp_listen_cb(struct osmo_fd *ofd, unsigned int when)
{
osmo_cc_session_media_t *media = ofd->data;
int rc;
uint8_t *payload = NULL;
int payload_len = 0;
uint8_t marker;
uint8_t payload_type;
osmo_cc_session_codec_t *codec;
uint8_t *data;
int len;
struct sockaddr_storage sa;
socklen_t slen = sizeof(sa); // must be initialized and will be overwritten
if (when & OSMO_FD_READ) {
rc = rtp_receive(&sa, &slen, media->rtp_ofd.fd, &payload, &payload_len, &marker, &payload_type, &media->rx_sequence, &media->rx_timestamp, &media->rx_ssrc);
if (rc < 0)
return rc;
check_port_translation(&sa, &media->rtp_sa, "RTP");
/* search for codec */
for (codec = media->codec_list; codec; codec = codec->next) {
if (codec->payload_type_local == payload_type)
break;
}
if (!codec) {
LOGP(DCC, LOGL_NOTICE, "Received RTP frame for unknown codec (payload_type = %d).\n", payload_type);
return 0;
}
if (codec->decoder)
codec->decoder(payload, payload_len, &data, &len, media->session->priv);
else {
data = payload;
len = payload_len;
}
if (codec->media->receive)
codec->media->receiver(codec, marker, media->rx_sequence, media->rx_timestamp, media->rx_ssrc, data, len);
if (codec->decoder)
free(data);
}
return 0;
}
static int rtcp_listen_cb(struct osmo_fd *ofd, unsigned int when)
{
osmo_cc_session_media_t *media = ofd->data;
int rc;
struct sockaddr_storage sa;
socklen_t slen = sizeof(sa); // must be initialized and will be overwritten
if (when & OSMO_FD_READ) {
rc = rtcp_receive(&sa, &slen, media->rtcp_ofd.fd);
if (rc < 0)
return rc;
check_port_translation(&sa, &media->rtcp_sa, "RTCP");
}
return 0;
}
void osmo_cc_rtp_close(osmo_cc_session_media_t *media)
{
if (media->rtp_ofd.fd) {
osmo_fd_unregister(&media->rtp_ofd);
close(media->rtp_ofd.fd);
media->rtp_ofd.fd = 0;
}
if (media->rtcp_ofd.fd) {
osmo_fd_unregister(&media->rtcp_ofd);
close(media->rtcp_ofd.fd);
media->rtcp_ofd.fd = 0;
}
}

View File

@ -1,7 +0,0 @@
void osmo_cc_set_rtp_ports(osmo_cc_session_config_t *conf, uint16_t from, uint16_t to);
int osmo_cc_rtp_open(osmo_cc_session_media_t *media);
int osmo_cc_rtp_connect(osmo_cc_session_media_t *media);
void osmo_cc_rtp_send(osmo_cc_session_codec_t *codec, uint8_t *data, int len, uint8_t marker, int inc_sequence, int inc_timestamp, void *priv);
void osmo_cc_rtp_close(osmo_cc_session_media_t *media);

View File

@ -1,694 +0,0 @@
/* Endpoint and call process handling
*
* (C) 2019 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "../libtimer/timer.h"
#include "../libselect/select.h"
#include "../libdebug/debug.h"
#include "endpoint.h"
#include "message.h"
#define SCREEN_QUESTIONMARK 1
#define SCREEN_STAR 2
#define SCREEN_AT 3
void osmo_cc_help_screen(void)
{
printf("Screening options:\n\n");
printf("screen-calling-in [attrs] <current caller ID> [attrs] <new caller ID>\n");
printf("screen-called-in [attrs] <current dialed number> [attrs] <new dialed number>\n");
printf("screen-calling-out [attrs] <current caller ID> [attrs] <new caller ID>\n");
printf("screen-called-out [attrs] <current dialed number> [attrs] <new dialed number>\n\n");
printf("These options allow to screen an incoming or outgoing caller ID or dialed\n");
printf("number. If 'the current caller ID' or 'current dialed number' matches, it will\n");
printf("be replaced by 'new caller ID' or 'new dialed number'. 'incoming' means from\n");
printf(" the interface and 'outgoing' means towards the interface.\n\n");
printf("Attributes prior 'current caller ID' or 'new dialed number' may be used to\n");
printf("perform screening only if the attribute match. Attributes prior\n");
printf("'new caller ID' or 'new dialed number' may be used to alter them. Attribute to\n");
printf("define the type of number can be: 'unknown', 'international', 'national',\n");
printf("'network', 'subscriber', 'abbreviated' Attribute to define the restriction of a\n");
printf("caller ID: 'allowed', 'restricted'\n\n");
printf("The current caller ID or dialed number may contain one or more '?', to allow\n");
printf("any digit to match. The current caller ID or dialed number may contain a '*',\n");
printf("to allow any suffix to match from now on. The new caller ID or dialed number\n");
printf("may contain a '*', to append the suffix from the current caller ID or dialed\n");
printf("number.\n\n");
printf("When screening an incoming caller ID or dialed number, the '@' can be appended\n");
printf("to the 'new caller ID', followed by a 'host:port', to route call to a special\n");
printf("Osmo-CC endpoint. This way it is possible to do simple routing.\n\n");
}
char *osmo_cc_strtok_quotes(const char **text_p)
{
static char token[1024];
const char *text = *text_p;
int i, quote;
/* skip spaces */
while (*text) {
if (*text > 32)
break;
text++;
}
/* if eol, return NULL */
if (!(*text))
return NULL;
i = 0;
quote = 0;
while (*text) {
/* escape allows all following characters */
if (*text == '\\') {
text++;
if (*text)
token[i++] = *text++;
continue;
}
/* no quote, check for them or break on white space */
if (quote == 0) {
if (*text == '\'') {
quote = 1;
text++;
continue;
}
if (*text == '\"') {
quote = 2;
text++;
continue;
}
if (*text <= ' ')
break;
}
/* single quote, check for unquote */
if (quote == 1 && *text == '\'') {
quote = 0;
text++;
continue;
}
/* double quote, check for unquote */
if (quote == 2 && *text == '\"') {
quote = 0;
text++;
continue;
}
/* copy character */
token[i++] = *text++;
}
token[i] = '\0';
*text_p = text;
return token;
}
int osmo_cc_add_screen(osmo_cc_endpoint_t *ep, const char *text)
{
osmo_cc_screen_list_t **list_p = NULL, *list;
const char *token;
int no_present = 0, calling_in = 0, star_used, at_used;
int i, j;
star_used = 0;
if (!strncasecmp(text, "screen-calling-in", 17)) {
text += 17;
list_p = &ep->screen_calling_in;
no_present = 1;
calling_in = 1;
} else if (!strncasecmp(text, "screen-called-in", 16)) {
text += 16;
list_p = &ep->screen_called_in;
calling_in = 1;
} else if (!strncasecmp(text, "screen-calling-out", 18)) {
text += 18;
list_p = &ep->screen_calling_out;
no_present = 1;
} else if (!strncasecmp(text, "screen-called-out", 17)) {
text += 17;
list_p = &ep->screen_called_out;
} else {
LOGP(DCC, LOGL_ERROR, "Invalid screening definition \"%s\". It must start with 'screen-calling-in' or 'screen-called-in' or 'screen-calling-out' or 'screen-called-out'\n", text);
return -EINVAL;
}
/* skip space behind screen list string */
while (*text) {
if (*text > 32)
break;
text++;
}
list = calloc(1, sizeof(*list));
if (!list)
return -ENOMEM;
next_from:
token = osmo_cc_strtok_quotes(&text);
if (!token) {
free(list);
LOGP(DCC, LOGL_ERROR, "Missing 'from' string in screening definition \"%s\". If the string shall be empty, use double quotes. (\'\' or \"\")\n", text);
return -EINVAL;
}
if (!strcasecmp(token, "unknown")) {
list->has_from_type = 1;
list->from_type = OSMO_CC_TYPE_UNKNOWN;
goto next_from;
} else
if (!strcasecmp(token, "international")) {
list->has_from_type = 1;
list->from_type = OSMO_CC_TYPE_INTERNATIONAL;
goto next_from;
} else
if (!strcasecmp(token, "national")) {
list->has_from_type = 1;
list->from_type = OSMO_CC_TYPE_NATIONAL;
goto next_from;
} else
if (!strcasecmp(token, "network")) {
list->has_from_type = 1;
list->from_type = OSMO_CC_TYPE_NETWORK;
goto next_from;
} else
if (!strcasecmp(token, "subscriber")) {
list->has_from_type = 1;
list->from_type = OSMO_CC_TYPE_SUBSCRIBER;
goto next_from;
} else
if (!strcasecmp(token, "abbreviated")) {
list->has_from_type = 1;
list->from_type = OSMO_CC_TYPE_ABBREVIATED;
goto next_from;
} else
if (!strcasecmp(token, "allowed")) {
if (no_present) {
no_present_error:
free(list);
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "Keyword '%s' not allowed in screen entry for called number\n", token);
return -EINVAL;
}
list->has_from_present = 1;
list->from_present = OSMO_CC_PRESENT_ALLOWED;
goto next_from;
} else
if (!strcasecmp(token, "restricted")) {
if (no_present)
goto no_present_error;
list->has_from_present = 1;
list->from_present = OSMO_CC_PRESENT_RESTRICTED;
goto next_from;
} else {
star_used = 0;
for (i = j = 0; token[i] && j < (int)sizeof(list->from) - 1; i++, j++) {
if (token[i] == '?')
list->from[j] = SCREEN_QUESTIONMARK;
else
if (token[i] == '*') {
if (star_used) {
free(list);
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "The '*' may be used only once.\n");
return -EINVAL;
}
list->from[j] = SCREEN_STAR;
star_used = 1;
} else
if (token[i] == '\\' && token[i + 1] != '\0')
list->from[j] = token[++i];
else
list->from[j] = token[i];
}
list->from[j] = '\0';
}
next_to:
token = osmo_cc_strtok_quotes(&text);
if (!token) {
free(list);
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "Missing screening result. If the string shall be empty, use double quotes. (\'\' or \"\")\n");
return -EINVAL;
}
if (!strcasecmp(token, "unknown")) {
list->has_to_type = 1;
list->to_type = OSMO_CC_TYPE_UNKNOWN;
goto next_to;
} else
if (!strcasecmp(token, "international")) {
list->has_to_type = 1;
list->to_type = OSMO_CC_TYPE_INTERNATIONAL;
goto next_to;
} else
if (!strcasecmp(token, "national")) {
list->has_to_type = 1;
list->to_type = OSMO_CC_TYPE_NATIONAL;
goto next_to;
} else
if (!strcasecmp(token, "network")) {
list->has_to_type = 1;
list->to_type = OSMO_CC_TYPE_NETWORK;
goto next_to;
} else
if (!strcasecmp(token, "subscriber")) {
list->has_to_type = 1;
list->to_type = OSMO_CC_TYPE_SUBSCRIBER;
goto next_to;
} else
if (!strcasecmp(token, "abbreviated")) {
list->has_to_type = 1;
list->to_type = OSMO_CC_TYPE_ABBREVIATED;
goto next_to;
} else
if (!strcasecmp(token, "allowed")) {
if (no_present)
goto no_present_error;
list->has_to_present = 1;
list->to_present = OSMO_CC_PRESENT_ALLOWED;
goto next_to;
} else
if (!strcasecmp(token, "restricted")) {
if (no_present)
goto no_present_error;
list->has_to_present = 1;
list->to_present = OSMO_CC_PRESENT_RESTRICTED;
goto next_to;
} else {
at_used = star_used = 0;
for (i = j = 0; token[i] && j < (int)sizeof(list->to) - 1; i++, j++) {
if (token[i] == '*') {
if (star_used) {
free(list);
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "The '*' may be used only once.\n");
return -EINVAL;
}
list->to[j] = SCREEN_STAR;
star_used = 1;
} else
if (token[i] == '@') {
if (!calling_in) {
free(list);
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "The '@' may be used only for incoming calls from interface.\n");
return -EINVAL;
}
if (at_used) {
free(list);
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "The '@' may be used only once.\n");
return -EINVAL;
}
list->to[j] = SCREEN_AT;
at_used = 1;
} else
if (token[i] == '\\' && token[i + 1] != '\0')
list->to[j] = token[++i];
else
list->to[j] = token[i];
}
list->to[j] = '\0';
}
token = osmo_cc_strtok_quotes(&text);
if (token) {
free(list);
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "Got garbage behind screening result.\n");
return -EINVAL;
}
/* attach screen entry to list */
while (*list_p)
list_p = &((*list_p)->next);
*list_p = list;
return 0;
}
void osmo_cc_flush_screen(osmo_cc_screen_list_t *list)
{
osmo_cc_screen_list_t *temp;
while (list) {
temp = list;
list = list->next;
free(temp);
}
}
const char *print_rule_string(const char *input)
{
static char output[256];
int i;
for (i = 0; *input && i < (int)sizeof(output) - 1; i++, input++) {
switch (*input) {
case SCREEN_QUESTIONMARK:
output[i] = '?';
break;
case SCREEN_STAR:
output[i] = '*';
break;
case SCREEN_AT:
output[i] = '@';
break;
default:
output[i] = *input;
}
}
output[i] = '\0';
return output;
}
static int osmo_cc_screen(const char *what, osmo_cc_screen_list_t *list, uint8_t *type, uint8_t *present, char *id_to, int id_to_size, const char *id_from, const char **routing_p)
{
const char *suffix;
int i, j, rule;
LOGP(DCC, LOGL_INFO, "Screening %s '%s':\n", what, id_from);
switch (*type) {
case OSMO_CC_TYPE_UNKNOWN:
LOGP(DCC, LOGL_INFO, " -> type = unknown\n");
break;
case OSMO_CC_TYPE_INTERNATIONAL:
LOGP(DCC, LOGL_INFO, " -> type = international\n");
break;
case OSMO_CC_TYPE_NATIONAL:
LOGP(DCC, LOGL_INFO, " -> type = national\n");
break;
case OSMO_CC_TYPE_NETWORK:
LOGP(DCC, LOGL_INFO, " -> type = network\n");
break;
case OSMO_CC_TYPE_SUBSCRIBER:
LOGP(DCC, LOGL_INFO, " -> type = subscriber\n");
break;
case OSMO_CC_TYPE_ABBREVIATED:
LOGP(DCC, LOGL_INFO, " -> type = abbreviated\n");
break;
}
if (present) switch (*present) {
case OSMO_CC_PRESENT_ALLOWED:
LOGP(DCC, LOGL_INFO, " -> present = allowed\n");
break;
case OSMO_CC_PRESENT_RESTRICTED:
LOGP(DCC, LOGL_INFO, " -> present = restricted\n");
break;
}
rule = 0;
while (list) {
rule++;
LOGP(DCC, LOGL_INFO, "Comparing with rule #%d: '%s':\n", rule, print_rule_string(list->from));
if (list->has_from_type) switch (list->from_type) {
case OSMO_CC_TYPE_UNKNOWN:
LOGP(DCC, LOGL_INFO, " -> type = unknown\n");
break;
case OSMO_CC_TYPE_INTERNATIONAL:
LOGP(DCC, LOGL_INFO, " -> type = international\n");
break;
case OSMO_CC_TYPE_NATIONAL:
LOGP(DCC, LOGL_INFO, " -> type = national\n");
break;
case OSMO_CC_TYPE_NETWORK:
LOGP(DCC, LOGL_INFO, " -> type = network\n");
break;
case OSMO_CC_TYPE_SUBSCRIBER:
LOGP(DCC, LOGL_INFO, " -> type = subscriber\n");
break;
case OSMO_CC_TYPE_ABBREVIATED:
LOGP(DCC, LOGL_INFO, " -> type = abbreviated\n");
break;
}
if (list->has_from_present) switch (list->from_present) {
case OSMO_CC_PRESENT_ALLOWED:
LOGP(DCC, LOGL_INFO, " -> present = allowed\n");
break;
case OSMO_CC_PRESENT_RESTRICTED:
LOGP(DCC, LOGL_INFO, " -> present = restricted\n");
break;
}
suffix = NULL;
/* attributes do not match */
if (list->has_from_type && list->from_type != *type) {
LOGP(DCC, LOGL_INFO, "Rule does not match, because 'type' is different.\n");
continue;
}
if (present && list->has_from_present && list->from_present != *present) {
LOGP(DCC, LOGL_INFO, "Rule does not match, because 'present' is different.\n");
continue;
}
for (i = 0; list->from[i] && id_from[i]; i++) {
/* '?' means: any digit, so it machtes */
if (list->from[i] == SCREEN_QUESTIONMARK) {
continue;
}
/* '*' means: anything may follow, so it machtes */
if (list->from[i] == SCREEN_STAR) {
suffix = id_from + i;
break;
}
/* check if digit doesn't matches */
if (list->from[i] != id_from[i])
break;
}
/* if last checked digit is '*', we have a match */
/* also if we hit EOL at id_from and next check digit is '*' */
if (list->from[i] == SCREEN_STAR)
break;
/* if all digits have matched */
if (list->from[i] == '\0' && id_from[i] == '\0')
break;
LOGP(DCC, LOGL_INFO, "Rule does not match, because %s is different.\n", what);
list = list->next;
}
/* if no list entry matches */
if (!list)
return -1;
/* replace ID */
if (list->has_to_type) {
*type = list->to_type;
}
if (present && list->has_to_present) {
*present = list->to_present;
}
for (i = j = 0; list->to[i]; i++) {
if (j == id_to_size - 1)
break;
/* '*' means to use suffix of input string */
if (list->to[i] == SCREEN_STAR && suffix) {
while (*suffix) {
id_to[j++] = *suffix++;
if (j == id_to_size - 1)
break;
}
continue;
/* '@' means to stop and return routing also */
} else if (list->to[i] == SCREEN_AT) {
if (routing_p)
*routing_p = &list->to[i + 1];
break;
}
/* copy output digit */
id_to[j++] = list->to[i];
}
id_to[j] = '\0';
LOGP(DCC, LOGL_INFO, "Rule matches, changing %s to '%s'.\n", what, print_rule_string(id_to));
if (list->has_to_type) switch (list->to_type) {
case OSMO_CC_TYPE_UNKNOWN:
LOGP(DCC, LOGL_INFO, " -> type = unknown\n");
break;
case OSMO_CC_TYPE_INTERNATIONAL:
LOGP(DCC, LOGL_INFO, " -> type = international\n");
break;
case OSMO_CC_TYPE_NATIONAL:
LOGP(DCC, LOGL_INFO, " -> type = national\n");
break;
case OSMO_CC_TYPE_NETWORK:
LOGP(DCC, LOGL_INFO, " -> type = network\n");
break;
case OSMO_CC_TYPE_SUBSCRIBER:
LOGP(DCC, LOGL_INFO, " -> type = subscriber\n");
break;
case OSMO_CC_TYPE_ABBREVIATED:
LOGP(DCC, LOGL_INFO, " -> type = abbreviated\n");
break;
}
if (list->has_to_present) switch (list->to_present) {
case OSMO_CC_PRESENT_ALLOWED:
LOGP(DCC, LOGL_INFO, " -> present = allowed\n");
break;
case OSMO_CC_PRESENT_RESTRICTED:
LOGP(DCC, LOGL_INFO, " -> present = restricted\n");
break;
}
if (routing_p && *routing_p)
LOGP(DCC, LOGL_INFO, " -> remote = %s\n", *routing_p);
return 0;
}
osmo_cc_msg_t *osmo_cc_screen_msg(osmo_cc_endpoint_t *ep, osmo_cc_msg_t *old_msg, int in, const char **routing_p)
{
osmo_cc_msg_t *new_msg;
char id[256], calling[256], called[256], redir[256];
uint8_t calling_type, calling_plan, calling_present, calling_screen;
uint8_t called_type, called_plan;
uint8_t redir_type, redir_plan, redir_present, redir_screen, redir_reason;
int calling_status = 0, called_status = 0, redir_status = 0;
int rc;
void *ie, *to_ie;
uint8_t ie_type;
uint16_t ie_length;
void *ie_value;
if (in && ep->screen_calling_in) {
rc = osmo_cc_get_ie_calling(old_msg, 0, &calling_type, &calling_plan, &calling_present, &calling_screen, id, sizeof(id));
if (rc >= 0) {
rc = osmo_cc_screen("incoming caller ID", ep->screen_calling_in, &calling_type, &calling_present, calling, sizeof(calling), id, routing_p);
if (rc >= 0)
calling_status = 1;
} else {
calling_type = OSMO_CC_TYPE_UNKNOWN;
calling_plan = OSMO_CC_PLAN_TELEPHONY;
calling_present = OSMO_CC_PRESENT_ALLOWED;
calling_screen = OSMO_CC_SCREEN_NETWORK;
rc = osmo_cc_screen("incoming caller ID", ep->screen_calling_in, &calling_type, &calling_present, calling, sizeof(calling), "", routing_p);
if (rc >= 0)
calling_status = 1;
}
rc = osmo_cc_get_ie_redir(old_msg, 0, &redir_type, &redir_plan, &redir_present, &redir_screen, &redir_reason, id, sizeof(id));
if (rc >= 0) {
rc = osmo_cc_screen("incoming redirecting number", ep->screen_calling_in, &redir_type, &redir_present, redir, sizeof(redir), id, NULL);
if (rc >= 0)
redir_status = 1;
}
}
if (in && ep->screen_called_in) {
rc = osmo_cc_get_ie_called(old_msg, 0, &called_type, &called_plan, id, sizeof(id));
if (rc >= 0) {
rc = osmo_cc_screen("incoming dialed number", ep->screen_called_in, &called_type, NULL, called, sizeof(called), id, routing_p);
if (rc >= 0)
called_status = 1;
} else {
called_type = OSMO_CC_TYPE_UNKNOWN;
called_plan = OSMO_CC_PLAN_TELEPHONY;
rc = osmo_cc_screen("incoming dialed number", ep->screen_called_in, &called_type, NULL, called, sizeof(called), "", routing_p);
if (rc >= 0)
called_status = 1;
}
}
if (!in && ep->screen_calling_out) {
rc = osmo_cc_get_ie_calling(old_msg, 0, &calling_type, &calling_plan, &calling_present, &calling_screen, id, sizeof(id));
if (rc >= 0) {
rc = osmo_cc_screen("outgoing caller ID", ep->screen_calling_out, &calling_type, &calling_present, calling, sizeof(calling), id, NULL);
if (rc >= 0)
calling_status = 1;
} else {
calling_type = OSMO_CC_TYPE_UNKNOWN;
calling_plan = OSMO_CC_PLAN_TELEPHONY;
calling_present = OSMO_CC_PRESENT_ALLOWED;
calling_screen = OSMO_CC_SCREEN_NETWORK;
rc = osmo_cc_screen("outgoing caller ID", ep->screen_calling_out, &calling_type, &calling_present, calling, sizeof(calling), "", NULL);
if (rc >= 0)
calling_status = 1;
}
rc = osmo_cc_get_ie_redir(old_msg, 0, &redir_type, &redir_plan, &redir_present, &redir_screen, &redir_reason, id, sizeof(id));
if (rc >= 0) {
rc = osmo_cc_screen("outgoing redirecting number", ep->screen_calling_out, &redir_type, &redir_present, redir, sizeof(redir), id, NULL);
if (rc >= 0)
redir_status = 1;
}
}
if (!in && ep->screen_called_out) {
rc = osmo_cc_get_ie_called(old_msg, 0, &called_type, &called_plan, id, sizeof(id));
if (rc >= 0) {
rc = osmo_cc_screen("outgoing dialed number", ep->screen_called_out, &called_type, NULL, called, sizeof(called), id, NULL);
if (rc >= 0)
called_status = 1;
} else {
called_type = OSMO_CC_TYPE_UNKNOWN;
called_plan = OSMO_CC_PLAN_TELEPHONY;
rc = osmo_cc_screen("outgoing dialed number", ep->screen_called_out, &called_type, NULL, called, sizeof(called), "", NULL);
if (rc >= 0)
called_status = 1;
}
}
/* nothing screened */
if (!calling_status && !called_status && !redir_status)
return old_msg;
new_msg = osmo_cc_new_msg(old_msg->type);
/* copy and replace */
ie = old_msg->data;
while ((ie_value = osmo_cc_msg_sep_ie(old_msg, &ie, &ie_type, &ie_length))) {
switch (ie_type) {
case OSMO_CC_IE_CALLING:
if (calling_status) {
osmo_cc_add_ie_calling(new_msg, calling_type, calling_plan, calling_present, calling_screen, calling);
calling_status = 0;
break;
}
goto copy;
case OSMO_CC_IE_CALLED:
if (called_status) {
osmo_cc_add_ie_called(new_msg, called_type, called_plan, called);
called_status = 0;
break;
}
goto copy;
case OSMO_CC_IE_REDIR:
if (redir_status) {
osmo_cc_add_ie_redir(new_msg, redir_type, redir_plan, redir_present, redir_screen, redir_reason, redir);
redir_status = 0;
break;
}
goto copy;
default:
copy:
to_ie = osmo_cc_add_ie(new_msg, ie_type, ie_length);
memcpy(to_ie, ie_value, ie_length);
}
}
/* applend, if not yet in message (except redir, since it must exist) */
if (calling_status)
osmo_cc_add_ie_calling(new_msg, calling_type, calling_plan, calling_present, calling_screen, calling);
if (called_status)
osmo_cc_add_ie_called(new_msg, called_type, called_plan, called);
free(old_msg);
return new_msg;
}

View File

@ -1,7 +0,0 @@
void osmo_cc_help_screen(void);
char *osmo_cc_strtok_quotes(const char **text_p);
int osmo_cc_add_screen(osmo_cc_endpoint_t *ep, const char *text);
void osmo_cc_flush_screen(osmo_cc_screen_list_t *list);
osmo_cc_msg_t *osmo_cc_screen_msg(osmo_cc_endpoint_t *ep, osmo_cc_msg_t *old_msg, int in, const char **routing_p);

View File

@ -1,545 +0,0 @@
/* Session Description Protocol parsing and generator
* This shall be simple and is incomplete.
*
* (C) 2019 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include "../libdebug/debug.h"
#include "../libtimer/timer.h"
#include "../libselect/select.h"
#include "endpoint.h"
#include "sdp.h"
#define strncat_printf(sdp, fmt, arg...) \
{ \
snprintf(sdp + strlen(sdp), sizeof(sdp) - strlen(sdp), fmt, ## arg); \
sdp[sizeof(sdp) - 1] = '\0'; \
}
/* generate SDP from session structure */
char *osmo_cc_session_gensdp(osmo_cc_session_t *session)
{
/* calc max size of SDP: quick an dirty (close to max UDP payload size) */
static char sdp[65000];
const char *username, *sess_id, *sess_version, *nettype, *addrtype, *unicast_address;
const char *session_name;
int individual_connection_data = 1; /* in case there is no media, there is no connection data */
int individual_send_receive = 1; /* in case there is no media, there is no send/receive attribute */
struct osmo_cc_session_media *media;
struct osmo_cc_session_codec *codec;
sdp[0] = 0;
/* Version */
strncat_printf(sdp, "v=0\r\n");
/* Origin */
username = session->origin_local.username;
sess_id = session->origin_local.sess_id;
sess_version = session->origin_local.sess_version;
nettype = session->origin_local.nettype;
addrtype = session->origin_local.addrtype;
unicast_address = session->origin_local.unicast_address;
strncat_printf(sdp, "o=%s %s %s %s %s %s\r\n", username, sess_id, sess_version, nettype, addrtype, unicast_address);
/* Session */
session_name = session->name;
strncat_printf(sdp, "s=%s\r\n", session_name);
/* Connection Data (if all media have the same data) */
if (session->media_list) {
osmo_cc_session_for_each_media(session->media_list->next, media) {
if (session->media_list->connection_data_local.nettype != media->connection_data_local.nettype)
break;
if (session->media_list->connection_data_local.addrtype != media->connection_data_local.addrtype)
break;
if (!!strcmp(session->media_list->connection_data_local.address, media->connection_data_local.address))
break;
}
if (!media)
individual_connection_data = 0;
}
if (!individual_connection_data)
strncat_printf(sdp, "c=%s %s %s\r\n", osmo_cc_session_nettype2string(session->media_list->connection_data_local.nettype), osmo_cc_session_addrtype2string(session->media_list->connection_data_local.addrtype), session->media_list->connection_data_local.address);
/* timestamp */
strncat_printf(sdp, "t=0 0\r\n");
/* sendonly /recvonly (if all media have the same data) */
if (session->media_list) {
osmo_cc_session_for_each_media(session->media_list->next, media) {
if (session->media_list->send != media->send)
break;
if (session->media_list->receive != media->receive)
break;
}
if (!media)
individual_send_receive = 0;
}
if (!individual_send_receive) {
if (session->media_list->send && !session->media_list->receive)
strncat_printf(sdp, "a=sendonly\r\n");
if (!session->media_list->send && session->media_list->receive)
strncat_printf(sdp, "a=recvonly\r\n");
if (!session->media_list->send && !session->media_list->receive)
strncat_printf(sdp, "a=inactive\r\n");
}
/* media */
osmo_cc_session_for_each_media(session->media_list, media) {
strncat_printf(sdp, "m=%s %u %s",
osmo_cc_session_media_type2string(media->description.type) ? : media->description.type_name,
media->description.port_local,
osmo_cc_session_media_proto2string(media->description.proto) ? : media->description.proto_name);
osmo_cc_session_for_each_codec(media->codec_list, codec)
strncat_printf(sdp, " %u", codec->payload_type_local);
strncat_printf(sdp, "\r\n");
/* don't list rtpmap when session was canceled by setting port to 0 */
if (media->description.port_local == 0)
continue;
if (individual_connection_data)
strncat_printf(sdp, "c=%s %s %s\r\n", osmo_cc_session_nettype2string(media->connection_data_local.nettype), osmo_cc_session_addrtype2string(media->connection_data_local.addrtype), media->connection_data_local.address);
osmo_cc_session_for_each_codec(media->codec_list, codec) {
strncat_printf(sdp, "a=rtpmap:%u %s/%d", codec->payload_type_local, codec->payload_name, codec->payload_rate);
if (codec->payload_channels >= 2)
strncat_printf(sdp, "/%d", codec->payload_channels);
strncat_printf(sdp, "\r\n");
}
if (individual_send_receive) {
if (media->send && !media->receive)
strncat_printf(sdp, "a=sendonly\r\n");
if (!media->send && media->receive)
strncat_printf(sdp, "a=recvonly\r\n");
if (!media->send && !media->receive)
strncat_printf(sdp, "a=inactive\r\n");
}
}
/* check for overflow and return */
if (strlen(sdp) == sizeof(sdp) - 1) {
LOGP(DCC, LOGL_ERROR, "Fatal error: Allocated SDP buffer with %d bytes is too small, please fix!\n", (int)sizeof(sdp));
return NULL;
}
return sdp;
}
/* separate a word from string that is delimited with one or more space characters */
static char *wordsep(char **text_p)
{
char *text = *text_p;
static char word[256];
int i;
/* no text */
if (text == NULL || *text == '\0')
return NULL;
/* skip spaces before text */
while (*text && *text <= ' ')
text++;
/* copy content */
i = 0;
while (*text > ' ' && i < (int)sizeof(word))
word[i++] = *text++;
word[i] = '\0';
/* set next */
*text_p = text;
return word;
}
/*
* codecs and their default values
*
* if format is -1, payload type is dynamic
* if rate is 0, rate may be any rate
*/
struct codec_defaults {
int fmt;
char *name;
uint32_t rate;
int channels;
} codec_defaults[] = {
{ 0, "PCMU", 8000, 1 },
{ 3, "GSM", 8000, 1 },
{ 4, "G723", 8000, 1 },
{ 5, "DVI4", 8000, 1 },
{ 6, "DVI4", 16000, 1 },
{ 7, "LPC", 8000, 1 },
{ 8, "PCMA", 8000, 1 },
{ 9, "G722", 8000, 1 },
{ 10, "L16", 44100, 2 },
{ 11, "L16", 44100, 1 },
{ 12, "QCELP", 8000, 1 },
{ 13, "CN", 8000, 1 },
{ 14, "MPA", 90000, 1 },
{ 15, "G728", 8000, 1 },
{ 16, "DVI4", 11025, 1 },
{ 17, "DVI4", 22050, 1 },
{ 18, "G729", 8000, 1 },
{ 25, "CELB", 90000, 0 },
{ 26, "JPEG", 90000, 0 },
{ 28, "nv", 90000, 0 },
{ 31, "H261", 90000, 0 },
{ 32, "MPV", 90000, 0 },
{ 33, "MP2T", 90000, 0 },
{ 34, "H263", 90000, 0 },
{ -1, NULL, 0, 0 },
};
static void complete_codec_by_fmt(uint8_t fmt, const char **name, uint32_t *rate, int *channels)
{
int i;
for (i = 0; codec_defaults[i].name; i++) {
if (codec_defaults[i].fmt == fmt)
break;
}
if (!codec_defaults[i].name)
return;
free((char *)*name);
*name = strdup(codec_defaults[i].name);
*rate = codec_defaults[i].rate;
*channels = codec_defaults[i].channels;
}
int osmo_cc_payload_type_by_attrs(uint8_t *fmt, const char *name, uint32_t *rate, int *channels)
{
int i;
for (i = 0; codec_defaults[i].name; i++) {
if (!strcmp(codec_defaults[i].name, name)
&& (*rate == 0 || codec_defaults[i].rate == *rate)
&& (*channels == 0 || codec_defaults[i].channels == *channels))
break;
}
if (!codec_defaults[i].name)
return -EINVAL;
*fmt = codec_defaults[i].fmt;
*rate = codec_defaults[i].rate;
*channels = codec_defaults[i].channels;
return 0;
}
/* parses data and codec list from SDP
*
* sdp = given SDP text
* return: SDP session description structure */
struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf, void *priv, const char *_sdp)
{
char buffer[strlen(_sdp) + 1], *sdp = buffer;
char *line, *p, *word, *next_word;
int line_no = 0;
struct osmo_cc_session_connection_data ccd, *cd;
int csend = 1, creceive = 1; /* common default */
struct osmo_cc_session *session = NULL;
struct osmo_cc_session_media *media = NULL;
struct osmo_cc_session_codec *codec = NULL;
/* prepare data */
strcpy(sdp, _sdp);
memset(&ccd, 0, sizeof(ccd));
/* create SDP session description */
session = osmo_cc_new_session(conf, priv, NULL, NULL, NULL, 0, 0, NULL, NULL, 0);
/* check every line of SDP and parse its data */
while(*sdp) {
if ((p = strchr(sdp, '\r'))) {
*p++ = '\0';
if (*p == '\n')
p++;
line = sdp;
sdp = p;
} else if ((p = strchr(sdp, '\n'))) {
*p++ = '\0';
line = sdp;
sdp = p;
} else {
line = sdp;
sdp = strchr(sdp, '\0');
}
next_word = line + 2;
line_no++;
if (line[0] == '\0')
continue;
if (line[1] != '=') {
LOGP(DCC, LOGL_NOTICE, "SDP line %d = '%s' is garbage, expecting '=' as second character.\n", line_no, line);
continue;
}
switch(line[0]) {
case 'v':
LOGP(DCC, LOGL_DEBUG, " -> Version: %s\n", next_word);
if (atoi(next_word) != 0) {
LOGP(DCC, LOGL_NOTICE, "SDP line %d = '%s' describes unsupported version.\n", line_no, line);
osmo_cc_free_session(session);
return NULL;
}
break;
case 'o':
LOGP(DCC, LOGL_DEBUG, " -> Originator: %s\n", next_word);
/* Originator */
word = wordsep(&next_word);
if (!word)
break;
free((char *)session->origin_remote.username); // if already set
session->origin_remote.username = strdup(word);
word = wordsep(&next_word);
if (!word)
break;
free((char *)session->origin_remote.sess_id); // if already set
session->origin_remote.sess_id = strdup(word);
word = wordsep(&next_word);
if (!word)
break;
free((char *)session->origin_remote.sess_version); // if already set
session->origin_remote.sess_version = strdup(word);
word = wordsep(&next_word);
if (!word)
break;
free((char *)session->origin_remote.nettype); // if already set
session->origin_remote.nettype = strdup(word);
word = wordsep(&next_word);
if (!word)
break;
free((char *)session->origin_remote.addrtype); // if already set
session->origin_remote.addrtype = strdup(word);
word = wordsep(&next_word);
if (!word)
break;
free((char *)session->origin_remote.unicast_address); // if already set
session->origin_remote.unicast_address = strdup(word);
break;
case 's':
/* Session Name */
LOGP(DCC, LOGL_DEBUG, " -> Session Name: %s\n", next_word);
free((char *)session->name); // if already set
session->name = strdup(next_word);
break;
case 'c': /* Connection Data */
LOGP(DCC, LOGL_DEBUG, " -> Connection Data: %s\n", next_word);
if (media)
cd = &media->connection_data_remote;
else
cd = &ccd;
/* network type */
if (!(word = wordsep(&next_word)))
break;
if (!strcmp(word, "IN"))
cd->nettype = osmo_cc_session_nettype_inet;
else {
LOGP(DCC, LOGL_NOTICE, "Unsupported network type '%s' in SDP line %d = '%s'\n", word, line_no, line);
break;
}
/* address type */
if (!(word = wordsep(&next_word)))
break;
if (!strcmp(word, "IP4")) {
cd->addrtype = osmo_cc_session_addrtype_ipv4;
LOGP(DCC, LOGL_DEBUG, " -> Address Type = IPv4\n");
} else
if (!strcmp(word, "IP6")) {
cd->addrtype = osmo_cc_session_addrtype_ipv6;
LOGP(DCC, LOGL_DEBUG, " -> Address Type = IPv6\n");
} else {
LOGP(DCC, LOGL_NOTICE, "Unsupported address type '%s' in SDP line %d = '%s'\n", word, line_no, line);
break;
}
/* connection address */
if (!(word = wordsep(&next_word)))
break;
if ((p = strchr(word, '/')))
*p++ = '\0';
free((char *)cd->address); // in case of multiple lines of 'c'
cd->address = strdup(word);
LOGP(DCC, LOGL_DEBUG, " -> Address = %s\n", word);
break;
case 'm': /* Media Description */
LOGP(DCC, LOGL_DEBUG, " -> Media Description: %s\n", next_word);
/* add media description */
media = osmo_cc_add_media(session, 0, 0, NULL, 0, 0, 0, csend, creceive, NULL, 0);
/* copy common connection data from common connection, if exists */
cd = &media->connection_data_remote;
memcpy(cd, &ccd, sizeof(*cd));
/* media type */
if (!(word = wordsep(&next_word)))
break;
if (!strcmp(word, "audio"))
media->description.type = osmo_cc_session_media_type_audio;
else
if (!strcmp(word, "video"))
media->description.type = osmo_cc_session_media_type_video;
else {
media->description.type = osmo_cc_session_media_type_unknown;
media->description.type_name = strdup(word);
LOGP(DCC, LOGL_DEBUG, "Unsupported media type in SDP line %d = '%s'\n", line_no, line);
}
/* port */
if (!(word = wordsep(&next_word)))
break;
media->description.port_remote = atoi(word);
/* proto */
if (!(word = wordsep(&next_word)))
break;
if (!strcmp(word, "RTP/AVP"))
media->description.proto = osmo_cc_session_media_proto_rtp;
else {
media->description.proto = osmo_cc_session_media_proto_unknown;
media->description.proto_name = strdup(word);
LOGP(DCC, LOGL_NOTICE, "Unsupported protocol type in SDP line %d = '%s'\n", line_no, line);
break;
}
/* create codec description for each codec and link */
while ((word = wordsep(&next_word))) {
/* create codec */
codec = osmo_cc_add_codec(media, NULL, 0, 1, NULL, NULL, 0);
/* fmt */
codec->payload_type_remote = atoi(word);
complete_codec_by_fmt(codec->payload_type_remote, &codec->payload_name, &codec->payload_rate, &codec->payload_channels);
LOGP(DCC, LOGL_DEBUG, " -> payload type = %d\n", codec->payload_type_remote);
if (codec->payload_name)
LOGP(DCC, LOGL_DEBUG, " -> payload name = %s\n", codec->payload_name);
if (codec->payload_rate)
LOGP(DCC, LOGL_DEBUG, " -> payload rate = %d\n", codec->payload_rate);
if (codec->payload_channels)
LOGP(DCC, LOGL_DEBUG, " -> payload channels = %d\n", codec->payload_channels);
}
break;
case 'a':
LOGP(DCC, LOGL_DEBUG, " -> Attribute: %s\n", next_word);
word = wordsep(&next_word);
if (!strcmp(word, "sendrecv")) {
if (media) {
media->receive = 1;
media->send = 1;
} else {
creceive = 1;
csend = 1;
}
break;
} else
if (!strcmp(word, "recvonly")) {
if (media) {
media->receive = 1;
media->send = 0;
} else {
creceive = 1;
csend = 0;
}
break;
} else
if (!strcmp(word, "sendonly")) {
if (media) {
media->receive = 0;
media->send = 1;
} else {
creceive = 0;
csend = 1;
}
break;
} else
if (!strcmp(word, "inactive")) {
if (media) {
media->receive = 0;
media->send = 0;
} else {
creceive = 0;
csend = 0;
}
break;
} else
if (!media) {
LOGP(DCC, LOGL_NOTICE, "Attribute without previously defined media in SDP line %d = '%s'\n", line_no, line);
break;
}
if (!strncmp(word, "rtpmap:", 7)) {
int fmt = atoi(word + 7);
osmo_cc_session_for_each_codec(media->codec_list, codec) {
if (codec->payload_type_remote == fmt)
break;
}
if (!codec) {
LOGP(DCC, LOGL_NOTICE, "Attribute without previously defined codec in SDP line %d = '%s'\n", line_no, line);
break;
}
LOGP(DCC, LOGL_DEBUG, " -> (rtpmap) payload type = %d\n", codec->payload_type_remote);
if (!(word = wordsep(&next_word)))
goto rtpmap_done;
if ((p = strchr(word, '/')))
*p++ = '\0';
free((char *)codec->payload_name); // in case it is already set above
codec->payload_name = strdup(word);
LOGP(DCC, LOGL_DEBUG, " -> (rtpmap) payload name = %s\n", codec->payload_name);
if (!(word = p))
goto rtpmap_done;
if ((p = strchr(word, '/')))
*p++ = '\0';
codec->payload_rate = atoi(word);
LOGP(DCC, LOGL_DEBUG, " -> (rtpmap) payload rate = %d\n", codec->payload_rate);
if (!(word = p)) {
/* if no channel is given and no default was specified, we must set 1 channel */
if (!codec->payload_channels)
codec->payload_channels = 1;
goto rtpmap_done;
}
codec->payload_channels = atoi(word);
LOGP(DCC, LOGL_DEBUG, " -> (rtpmap) payload channels = %d\n", codec->payload_channels);
rtpmap_done:
if (!codec->payload_name || !codec->payload_rate || !codec->payload_channels) {
LOGP(DCC, LOGL_NOTICE, "Broken 'rtpmap' definition in SDP line %d = '%s' Skipping codec!\n", line_no, line);
osmo_cc_free_codec(codec);
}
}
break;
}
}
/* if something is incomplete, abort here */
if (osmo_cc_session_check(session, 1)) {
LOGP(DCC, LOGL_NOTICE, "Parsing SDP failed.\n");
osmo_cc_free_session(session);
return NULL;
}
return session;
}
void osmo_cc_debug_sdp(const char *_sdp)
{
const unsigned char *sdp = (const unsigned char *)_sdp;
char text[256];
int i;
while (*sdp) {
for (i = 0; *sdp > 0 && *sdp >= 32 && i < (int)sizeof(text) - 1; i++)
text[i] = *sdp++;
text[i] = '\0';
LOGP(DCC, LOGL_DEBUG, " | %s\n", text);
while (*sdp > 0 && *sdp < 32)
sdp++;
}
}

View File

@ -1,6 +0,0 @@
char *osmo_cc_session_gensdp(struct osmo_cc_session *session);
struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf, void *priv, const char *_sdp);
int osmo_cc_payload_type_by_attrs(uint8_t *fmt, const char *name, uint32_t *rate, int *channels);
void osmo_cc_debug_sdp(const char *sdp);

View File

@ -1,625 +0,0 @@
/* Osmo-CC: Media Session handling
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include <inttypes.h>
#include "../libtimer/timer.h"
#include "../libselect/select.h"
#include "../libdebug/debug.h"
#include "../liboptions/options.h"
#include "endpoint.h"
#define NTP_OFFSET 2208988800U
void osmo_cc_set_local_peer(osmo_cc_session_config_t *conf, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address)
{
conf->default_nettype = nettype;
conf->default_addrtype = addrtype;
conf->default_unicast_address = options_strdup(address);
}
osmo_cc_session_t *osmo_cc_new_session(osmo_cc_session_config_t *conf, void *priv, const char *username, const char *sess_id, const char *sess_version, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *unicast_address, const char *session_name, int debug)
{
osmo_cc_session_t *session;
if (debug) LOGP(DCC, LOGL_DEBUG, "Creating session structure.\n");
session = calloc(1, sizeof(*session));
if (!session) {
LOGP(DCC, LOGL_ERROR, "No mem!\n");
abort();
}
session->config = conf;
session->priv = priv;
if (username) {
int i;
for (i = 0; username[i]; i++) {
if ((uint8_t)username[i] < 33) {
LOGP(DCC, LOGL_ERROR, "Fatal error: SDP's originator (username) uses invalid characters, please fix!\n");
abort();
}
}
session->origin_local.username = strdup(username);
}
if (!username)
session->origin_local.username = strdup("-");
if (debug) LOGP(DCC, LOGL_DEBUG, " -> user name = %s\n", session->origin_local.username);
if (sess_id)
session->origin_local.sess_id = strdup(sess_id);
if (sess_version)
session->origin_local.sess_version = strdup(sess_version);
if (!sess_id || !sess_version) {
struct timeval tv;
char ntp_timestamp[32];
/* get time NTP format time stamp (time since 1900) */
gettimeofday(&tv, NULL);
sprintf(ntp_timestamp, "%" PRIu64, (uint64_t)tv.tv_sec + NTP_OFFSET);
if (!sess_id)
session->origin_local.sess_id = strdup(ntp_timestamp);
if (!sess_version)
session->origin_local.sess_version = strdup(ntp_timestamp);
}
if (debug) LOGP(DCC, LOGL_DEBUG, " -> session ID = %s\n", session->origin_local.sess_id);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> session version = %s\n", session->origin_local.sess_version);
if (nettype)
session->origin_local.nettype = strdup(osmo_cc_session_nettype2string(nettype));
else
session->origin_local.nettype = strdup(osmo_cc_session_nettype2string(conf->default_nettype));
if (debug) LOGP(DCC, LOGL_DEBUG, " -> network type = %s\n", session->origin_local.nettype);
if (addrtype)
session->origin_local.addrtype = strdup(osmo_cc_session_addrtype2string(addrtype));
else
session->origin_local.addrtype = strdup(osmo_cc_session_addrtype2string(conf->default_addrtype));
if (debug) LOGP(DCC, LOGL_DEBUG, " -> address type = %s\n", session->origin_local.addrtype);
if (unicast_address)
session->origin_local.unicast_address = strdup(unicast_address);
else
session->origin_local.unicast_address = strdup(conf->default_unicast_address);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> unicast address = %s\n", session->origin_local.unicast_address);
if (session_name)
session->name = strdup(session_name);
if (!session_name)
session->name = strdup("-");
if (debug) LOGP(DCC, LOGL_DEBUG, " -> session name = %s\n", session->name);
return session;
}
void osmo_cc_free_session(osmo_cc_session_t *session)
{
LOGP(DCC, LOGL_DEBUG, "Free session structure.\n");
free((char *)session->origin_local.username);
free((char *)session->origin_local.sess_id);
free((char *)session->origin_local.sess_version);
free((char *)session->origin_local.nettype);
free((char *)session->origin_local.addrtype);
free((char *)session->origin_local.unicast_address);
free((char *)session->origin_remote.username);
free((char *)session->origin_remote.sess_id);
free((char *)session->origin_remote.sess_version);
free((char *)session->origin_remote.nettype);
free((char *)session->origin_remote.addrtype);
free((char *)session->origin_remote.unicast_address);
free((char *)session->name);
while (session->media_list)
osmo_cc_free_media(session->media_list);
free(session);
}
osmo_cc_session_media_t *osmo_cc_add_media(osmo_cc_session_t *session, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, enum osmo_cc_session_media_type type, uint16_t port, enum osmo_cc_session_media_proto proto, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), int debug)
{
osmo_cc_session_config_t *conf = session->config;
osmo_cc_session_media_t *media, **mediap;
media = calloc(1, sizeof(*media));
if (!media) {
LOGP(DCC, LOGL_ERROR, "No mem!\n");
abort();
}
media->session = session;
if (nettype)
media->connection_data_local.nettype = nettype;
else
media->connection_data_local.nettype = conf->default_nettype;
if (addrtype)
media->connection_data_local.addrtype = addrtype;
else
media->connection_data_local.addrtype = conf->default_addrtype;
if (address)
media->connection_data_local.address = strdup(address);
else
media->connection_data_local.address = strdup(conf->default_unicast_address);
media->description.type = type;
media->description.port_local = port;
media->description.proto = proto;
media->send = send;
media->receive = receive;
media->receiver = receiver;
media->tx_sequence = random();
media->tx_timestamp = random();
mediap = &media->session->media_list;
while (*mediap)
mediap = &((*mediap)->next);
*mediap = media;
if (debug) LOGP(DCC, LOGL_DEBUG, "Adding session media.\n");
if (debug) LOGP(DCC, LOGL_DEBUG, " -> network type = %s\n", osmo_cc_session_nettype2string(media->connection_data_local.nettype));
if (debug) LOGP(DCC, LOGL_DEBUG, " -> address type = %s\n", osmo_cc_session_addrtype2string(media->connection_data_local.addrtype));
if (debug) LOGP(DCC, LOGL_DEBUG, " -> address = %s\n", media->connection_data_local.address);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> media type = %s\n", osmo_cc_session_media_type2string(media->description.type));
if (debug) LOGP(DCC, LOGL_DEBUG, " -> media port = %d\n", media->description.port_local);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> media proto = %s\n", osmo_cc_session_media_proto2string(media->description.proto));
if (debug) LOGP(DCC, LOGL_DEBUG, "Opening and binding media port %d\n", media->description.port_local);
return media;
}
void osmo_cc_free_media(osmo_cc_session_media_t *media)
{
osmo_cc_session_media_t **mediap;
LOGP(DCC, LOGL_DEBUG, "Free session media.\n");
osmo_cc_rtp_close(media);
free((char *)media->connection_data_local.nettype_name);
free((char *)media->connection_data_local.addrtype_name);
free((char *)media->connection_data_local.address);
free((char *)media->connection_data_remote.nettype_name);
free((char *)media->connection_data_remote.addrtype_name);
free((char *)media->connection_data_remote.address);
while (media->codec_list)
osmo_cc_free_codec(media->codec_list);
mediap = &media->session->media_list;
while (*mediap != media)
mediap = &((*mediap)->next);
*mediap = media->next;
free(media);
}
osmo_cc_session_codec_t *osmo_cc_add_codec(osmo_cc_session_media_t *media, const char *payload_name, uint32_t payload_rate, int payload_channels, void (*encoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv), void (*decoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv), int debug)
{
osmo_cc_session_codec_t *codec, **codecp;
int rc;
codec = calloc(1, sizeof(*codec));
if (!codec) {
LOGP(DCC, LOGL_ERROR, "No mem!\n");
abort();
}
codec->media = media;
if (payload_name) {
codec->payload_name = strdup(payload_name);
codec->payload_rate = payload_rate;
codec->payload_channels = payload_channels;
rc = osmo_cc_payload_type_by_attrs(&codec->payload_type_local, payload_name, &payload_rate, &payload_channels);
if (rc < 0) {
/* hunt for next free dynamic payload type */
uint8_t fmt = 96;
osmo_cc_session_codec_t *c;
osmo_cc_session_for_each_codec(media->codec_list, c) {
if (c->payload_type_local >= fmt)
fmt = c->payload_type_local + 1;
}
codec->payload_type_local = fmt;
}
}
codec->encoder = encoder;
codec->decoder = decoder;
codecp = &codec->media->codec_list;
while (*codecp)
codecp = &((*codecp)->next);
*codecp = codec;
if (debug) LOGP(DCC, LOGL_DEBUG, "Adding session codec.\n");
if (debug) LOGP(DCC, LOGL_DEBUG, " -> payload type = %d\n", codec->payload_type_local);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> payload name = %s\n", codec->payload_name);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> payload rate = %d\n", codec->payload_rate);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> payload channels = %d\n", codec->payload_channels);
return codec;
}
void osmo_cc_free_codec(osmo_cc_session_codec_t *codec)
{
osmo_cc_session_codec_t **codecp;
LOGP(DCC, LOGL_DEBUG, "Free session codec.\n");
free((char *)codec->payload_name);
codecp = &codec->media->codec_list;
while (*codecp != codec)
codecp = &((*codecp)->next);
*codecp = codec->next;
free(codec);
}
int osmo_cc_session_check(osmo_cc_session_t *session, int remote)
{
struct osmo_cc_session_origin *orig;
struct osmo_cc_session_media *media;
struct osmo_cc_session_connection_data *cd;
struct osmo_cc_session_media_description *md;
struct osmo_cc_session_codec *codec;
int i, j;
if (remote)
orig = &session->origin_remote;
else
orig = &session->origin_local;
if (!orig->username
|| !orig->sess_id
|| !orig->sess_version
|| !orig->nettype
|| !orig->addrtype
|| !orig->unicast_address) {
LOGP(DCC, LOGL_NOTICE, "Missing data in session origin\n");
return -EINVAL;
}
if (!session->name) {
LOGP(DCC, LOGL_NOTICE, "Missing data in session origin\n");
return -EINVAL;
}
if (!session->media_list) {
LOGP(DCC, LOGL_NOTICE, "Missing media session\n");
return -EINVAL;
}
i = 0;
osmo_cc_session_for_each_media(session->media_list, media) {
i++;
if (remote)
cd = &media->connection_data_remote;
else
cd = &media->connection_data_local;
if (!cd->nettype && !cd->nettype_name) {
LOGP(DCC, LOGL_NOTICE, "Session with media #%d is missing connection network type\n", i);
return -EINVAL;
}
if (!cd->addrtype && !cd->addrtype_name) {
LOGP(DCC, LOGL_NOTICE, "Session with media #%d is missing connection address type\n", i);
return -EINVAL;
}
if (!cd->address) {
LOGP(DCC, LOGL_NOTICE, "Session with media #%d is missing connection address\n", i);
return -EINVAL;
}
md = &media->description;
if (!md->type && !md->type_name) {
LOGP(DCC, LOGL_NOTICE, "Session with media #%d is missing media type\n", i);
return -EINVAL;
}
if (!md->proto && !md->proto_name) {
LOGP(DCC, LOGL_NOTICE, "Session with media #%d is missing protocol\n", i);
return -EINVAL;
}
j = 0;
osmo_cc_session_for_each_codec(media->codec_list, codec) {
j++;
if (!codec->payload_name) {
LOGP(DCC, LOGL_NOTICE, "Session with media #%d, codec #%d is missing name\n", i, j);
return -EINVAL;
}
if (!codec->payload_rate) {
LOGP(DCC, LOGL_NOTICE, "Session with media #%d, codec #%d is missing rate\n", i, j);
return -EINVAL;
}
if (!codec->payload_channels) {
LOGP(DCC, LOGL_NOTICE, "Session with media #%d, codec #%d is missing channel count\n", i, j);
return -EINVAL;
}
}
}
return 0;
}
/* check session description and generate SDP */
const char *osmo_cc_session_send_offer(osmo_cc_session_t *session)
{
const char *sdp;
int rc;
LOGP(DCC, LOGL_DEBUG, "Generating session offer and opening RTP stream.\n");
rc = osmo_cc_session_check(session, 0);
if (rc < 0) {
LOGP(DCC, LOGL_ERROR, "Please fix!\n");
abort();
}
sdp = osmo_cc_session_gensdp(session);
osmo_cc_debug_sdp(sdp);
return sdp;
}
osmo_cc_session_t *osmo_cc_session_receive_offer(osmo_cc_session_config_t *conf, void *priv, const char *sdp)
{
osmo_cc_session_t *session;
int rc;
LOGP(DCC, LOGL_DEBUG, "Parsing session offer.\n");
osmo_cc_debug_sdp(sdp);
session = osmo_cc_session_parsesdp(conf, priv, sdp);
if (!session)
return NULL;
rc = osmo_cc_session_check(session, 0);
if (rc < 0) {
osmo_cc_free_session(session);
return NULL;
}
return session;
}
void osmo_cc_session_accept_media(osmo_cc_session_media_t *media, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len))
{
osmo_cc_session_config_t *conf = media->session->config;
media->accepted = 1;
if (nettype)
media->connection_data_local.nettype = nettype;
else
media->connection_data_local.nettype = conf->default_nettype;
if (addrtype)
media->connection_data_local.addrtype = addrtype;
else
media->connection_data_local.addrtype = conf->default_addrtype;
free((char *)media->connection_data_local.address);
if (address)
media->connection_data_local.address = strdup(address);
else
media->connection_data_local.address = strdup(conf->default_unicast_address);
media->send = send;
media->receive = receive;
media->receiver = receiver;
LOGP(DCC, LOGL_DEBUG, "Accepting session media.\n");
LOGP(DCC, LOGL_DEBUG, " -> network type = %s\n", osmo_cc_session_nettype2string(media->connection_data_local.nettype));
LOGP(DCC, LOGL_DEBUG, " -> address type = %s\n", osmo_cc_session_addrtype2string(media->connection_data_local.addrtype));
LOGP(DCC, LOGL_DEBUG, " -> address = %s\n", media->connection_data_local.address);
}
void osmo_cc_session_accept_codec(osmo_cc_session_codec_t *codec, void (*encoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv), void (*decoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv))
{
codec->accepted = 1;
codec->encoder = encoder;
codec->decoder = decoder;
/* when we accept a codec, we just use the same payload type as the remote */
codec->payload_type_local = codec->payload_type_remote;
LOGP(DCC, LOGL_DEBUG, "Accepting session codec.\n");
LOGP(DCC, LOGL_DEBUG, " -> payload type = %d\n", codec->payload_type_local);
LOGP(DCC, LOGL_DEBUG, " -> payload name = %s\n", codec->payload_name);
LOGP(DCC, LOGL_DEBUG, " -> payload rate = %d\n", codec->payload_rate);
LOGP(DCC, LOGL_DEBUG, " -> payload channels = %d\n", codec->payload_channels);
}
/* remove codecs/media that have not been accepted and generate SDP */
const char *osmo_cc_session_send_answer(osmo_cc_session_t *session)
{
osmo_cc_session_media_t *media;
osmo_cc_session_codec_t *codec, **codec_p;
const char *sdp;
int rc;
LOGP(DCC, LOGL_DEBUG, "Generating session answer.\n");
/* loop all media */
osmo_cc_session_for_each_media(session->media_list, media) {
/* remove unaccepted codecs */
codec_p = &media->codec_list;
codec = *codec_p;
while (codec) {
if (!codec->accepted) {
osmo_cc_free_codec(codec);
codec = *codec_p;
continue;
}
codec_p = &codec->next;
codec = *codec_p;
}
/* mark media as unused, if no codec or not accepted */
if (!media->accepted || !media->codec_list)
media->description.port_local = 0;
}
rc = osmo_cc_session_check(session, 0);
if (rc < 0) {
LOGP(DCC, LOGL_ERROR, "Please fix!\n");
abort();
}
sdp = osmo_cc_session_gensdp(session);
osmo_cc_debug_sdp(sdp);
return sdp;
}
/* Apply remote session description to local session description.
* If remote media's port is 0, remove from local session description.
* If codecs in the remote session description are missing, remove from local session description.
*/
static int osmo_cc_session_negotiate(osmo_cc_session_t *session_local, struct osmo_cc_session *session_remote)
{
osmo_cc_session_media_t *media_local, *media_remote, **media_local_p;
osmo_cc_session_codec_t *codec_local, *codec_remote, **codec_local_p;
int rc;
LOGP(DCC, LOGL_DEBUG, "Negotiating session.\n");
/* copy remote session information */
session_local->origin_remote.username = strdup(session_remote->origin_remote.username);
session_local->origin_remote.sess_id = strdup(session_remote->origin_remote.sess_id);
session_local->origin_remote.sess_version = strdup(session_remote->origin_remote.sess_version);
session_local->origin_remote.nettype = strdup(session_remote->origin_remote.nettype);
session_local->origin_remote.addrtype = strdup(session_remote->origin_remote.addrtype);
session_local->origin_remote.unicast_address = strdup(session_remote->origin_remote.unicast_address);
/* loop all media */
for (media_local = session_local->media_list, media_remote = session_remote->media_list; media_local && media_remote; media_local = media_local->next, media_remote = media_remote->next) {
/* copy remote media information */
media_local->connection_data_remote.nettype = media_remote->connection_data_remote.nettype;
if (media_remote->connection_data_remote.nettype_name)
media_local->connection_data_remote.nettype_name = strdup(media_remote->connection_data_remote.nettype_name);
media_local->connection_data_remote.addrtype = media_remote->connection_data_remote.addrtype;
if (media_remote->connection_data_remote.addrtype_name)
media_local->connection_data_remote.addrtype_name = strdup(media_remote->connection_data_remote.addrtype_name);
if (media_remote->connection_data_remote.address)
media_local->connection_data_remote.address = strdup(media_remote->connection_data_remote.address);
media_local->description.port_remote = media_remote->description.port_remote;
media_local->send = media_remote->send;
media_local->receive = media_remote->receive;
/* loop all codecs and remove if they are not found in local session description */
codec_local_p = &media_local->codec_list;
codec_local = *codec_local_p;
while (codec_local) {
/* search for equal codec, payload type may differe for each direction */
osmo_cc_session_for_each_codec(media_remote->codec_list, codec_remote) {
if (!strcmp(codec_local->payload_name, codec_remote->payload_name)
&& codec_local->payload_rate == codec_remote->payload_rate
&& codec_local->payload_channels == codec_remote->payload_channels)
break;
}
if (!codec_remote) {
osmo_cc_free_codec(codec_local);
codec_local = *codec_local_p;
continue;
}
/* copy remote codec information */
codec_local->payload_type_remote = codec_remote->payload_type_remote;
codec_local_p = &codec_local->next;
codec_local = *codec_local_p;
}
}
if (media_local) {
LOGP(DCC, LOGL_NOTICE, "Negotiation failed, because remote endpoint returns less media streams than we offered.\n");
return -EINVAL;
}
if (media_remote) {
LOGP(DCC, LOGL_NOTICE, "Negotiation failed, because remote endpoint returns more media streams than we offered.\n");
return -EINVAL;
}
/* remove media with port == 0 or no codec at all */
media_local_p = &session_local->media_list;
media_local = *media_local_p;
while (media_local) {
if (media_local->description.port_remote == 0 || !media_local->codec_list) {
osmo_cc_free_media(media_local);
media_local = *media_local_p;
continue;
}
media_local_p = &media_local->next;
media_local = *media_local_p;
}
rc = osmo_cc_session_check(session_local, 1);
if (rc < 0)
return rc;
return 0;
}
int osmo_cc_session_receive_answer(osmo_cc_session_t *session, const char *sdp)
{
osmo_cc_session_t *session_remote;
int rc;
LOGP(DCC, LOGL_DEBUG, "Parsing session answer.\n");
osmo_cc_debug_sdp(sdp);
session_remote = osmo_cc_session_parsesdp(session->config, NULL, sdp);
if (!session_remote)
return -EINVAL;
rc = osmo_cc_session_check(session_remote, 1);
if (rc < 0) {
osmo_cc_free_session(session_remote);
return rc;
}
rc = osmo_cc_session_negotiate(session, session_remote);
if (rc < 0) {
osmo_cc_free_session(session_remote);
return rc;
}
osmo_cc_free_session(session_remote);
return 0;
}
const char *osmo_cc_session_nettype2string(enum osmo_cc_session_nettype nettype)
{
switch (nettype) {
case osmo_cc_session_nettype_inet:
return "IN";
default:
return NULL;
}
}
const char *osmo_cc_session_addrtype2string(enum osmo_cc_session_addrtype addrtype)
{
switch (addrtype) {
case osmo_cc_session_addrtype_ipv4:
return "IP4";
case osmo_cc_session_addrtype_ipv6:
return "IP6";
default:
return NULL;
}
}
const char *osmo_cc_session_media_type2string(enum osmo_cc_session_media_type media_type)
{
switch (media_type) {
case osmo_cc_session_media_type_audio:
return "audio";
case osmo_cc_session_media_type_video:
return "video";
default:
return NULL;
}
}
const char *osmo_cc_session_media_proto2string(enum osmo_cc_session_media_proto media_proto)
{
switch (media_proto) {
case osmo_cc_session_media_proto_rtp:
return "RTP/AVP";
default:
return NULL;
}
}
int osmo_cc_session_if_codec(osmo_cc_session_codec_t *codec, const char *name, uint32_t rate, int channels)
{
return (!strcmp(codec->payload_name, name)
&& codec->payload_rate == rate
&& codec->payload_channels == channels);
}

View File

@ -1,134 +0,0 @@
#include <sys/socket.h>
/* configuration */
enum osmo_cc_session_nettype {
osmo_cc_session_nettype_unknown = 0,
osmo_cc_session_nettype_inet,
};
enum osmo_cc_session_addrtype {
osmo_cc_session_addrtype_unknown = 0,
osmo_cc_session_addrtype_ipv4,
osmo_cc_session_addrtype_ipv6,
};
typedef struct osmo_cc_session_config {
enum osmo_cc_session_nettype default_nettype;
enum osmo_cc_session_addrtype default_addrtype;
const char *default_unicast_address;
uint16_t rtp_port_next;
uint16_t rtp_port_from;
uint16_t rtp_port_to;
} osmo_cc_session_config_t;
/* session description, global part: */
typedef struct osmo_cc_session_origin {
const char *username;
const char *sess_id;
const char *sess_version;
const char *nettype;
const char *addrtype;
const char *unicast_address;
} osmo_cc_session_origin_t;
/* session instance */
typedef struct osmo_cc_session {
osmo_cc_session_config_t *config;
void *priv;
osmo_cc_session_origin_t origin_local, origin_remote;
const char *name;
struct osmo_cc_session_media *media_list;
} osmo_cc_session_t;
/* connection description: */
typedef struct osmo_cc_session_connection_data {
enum osmo_cc_session_nettype nettype;
const char *nettype_name;
enum osmo_cc_session_addrtype addrtype;
const char *addrtype_name;
const char *address;
} osmo_cc_session_connection_data_t;
/* one media of session description: */
enum osmo_cc_session_media_type {
osmo_cc_session_media_type_unknown,
osmo_cc_session_media_type_audio,
osmo_cc_session_media_type_video,
};
enum osmo_cc_session_media_proto {
osmo_cc_session_media_proto_unknown,
osmo_cc_session_media_proto_rtp,
};
typedef struct osmo_cc_session_media_description {
enum osmo_cc_session_media_type type;
const char *type_name;
uint16_t port_local, port_remote;
enum osmo_cc_session_media_proto proto;
const char *proto_name;
} osmo_cc_session_media_description_t;
/* media entry */
typedef struct osmo_cc_session_media {
struct osmo_cc_session_media *next;
osmo_cc_session_t *session;
osmo_cc_session_media_description_t description;
osmo_cc_session_connection_data_t connection_data_local, connection_data_remote;
struct osmo_cc_session_codec *codec_list;
int send, receive;
void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len);
struct sockaddr_storage rtp_sa, rtcp_sa;
socklen_t rtp_slen, rtcp_slen;
uint16_t *rtp_sport, *rtcp_sport; // pointers to the port inside sa sockaddr
struct osmo_fd rtp_ofd;
struct osmo_fd rtcp_ofd;
uint32_t tx_ssrc, rx_ssrc;
uint16_t tx_sequence, rx_sequence;
uint32_t tx_timestamp, rx_timestamp;
int accepted;
} osmo_cc_session_media_t;
/* codec entry */
typedef struct osmo_cc_session_codec {
struct osmo_cc_session_codec *next;
osmo_cc_session_media_t *media;
uint8_t payload_type_local, payload_type_remote; /* local = towards local, remote = toward remote */
const char *payload_name;
uint32_t payload_rate;
int payload_channels;
void (*encoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
void (*decoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
int accepted;
} osmo_cc_session_codec_t;
#define osmo_cc_session_for_each_media(head, m) \
for (m = (head); m; m = m->next)
#define osmo_cc_session_for_each_codec(head, c) \
for (c = (head); c; c = c->next)
void osmo_cc_set_local_peer(osmo_cc_session_config_t *conf, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address);
osmo_cc_session_t *osmo_cc_new_session(osmo_cc_session_config_t *conf, void *priv, const char *username, const char *sess_id, const char *sess_version, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *unicast_address, const char *session_name, int debug);
void osmo_cc_free_session(osmo_cc_session_t *session);
osmo_cc_session_media_t *osmo_cc_add_media(osmo_cc_session_t *session, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, enum osmo_cc_session_media_type type, uint16_t port, enum osmo_cc_session_media_proto proto, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), int debug);
void osmo_cc_free_media(osmo_cc_session_media_t *media);
osmo_cc_session_codec_t *osmo_cc_add_codec(osmo_cc_session_media_t *media, const char *playload_name, uint32_t playload_rate, int playload_channels, void (*encoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv), void (*decoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv), int debug);
void osmo_cc_free_codec(osmo_cc_session_codec_t *codec);
int osmo_cc_session_check(struct osmo_cc_session *session, int remote);
const char *osmo_cc_session_send_offer(osmo_cc_session_t *session);
osmo_cc_session_t *osmo_cc_session_receive_offer(osmo_cc_session_config_t *conf, void *priv, const char *sdp);
void osmo_cc_session_accept_media(osmo_cc_session_media_t *media, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len));
void osmo_cc_session_accept_codec(osmo_cc_session_codec_t *codec, void (*encoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv), void (*decoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv));
const char *osmo_cc_session_send_answer(osmo_cc_session_t *session);
int osmo_cc_session_receive_answer(osmo_cc_session_t *session, const char *sdp);
const char *osmo_cc_session_nettype2string(enum osmo_cc_session_nettype nettype);
const char *osmo_cc_session_addrtype2string(enum osmo_cc_session_addrtype addrtype);
const char *osmo_cc_session_media_type2string(enum osmo_cc_session_media_type media_type);
const char *osmo_cc_session_media_proto2string(enum osmo_cc_session_media_proto media_proto);
int osmo_cc_session_if_codec(osmo_cc_session_codec_t *codec, const char *name, uint32_t rate, int channels);

View File

@ -1,619 +0,0 @@
/* Osmo-CC: Socket handling
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netdb.h>
#include "../libdebug/debug.h"
#include "../libtimer/timer.h"
#include "../libselect/select.h"
#include "message.h"
#include "cause.h"
#include "socket.h"
static const char version_string[] = OSMO_CC_VERSION;
static int _getaddrinfo(const char *host, uint16_t port, struct addrinfo **result)
{
char portstr[8];
struct addrinfo hints;
int rc;
sprintf(portstr, "%d", port);
/* bind socket */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
rc = getaddrinfo(host, portstr, &hints, result);
if (rc < 0) {
LOGP(DCC, LOGL_ERROR, "Failed to create socket for host '%s', port '%d': %s.\n", host, port, gai_strerror(rc));
return rc;
}
return rc;
}
/* send a reject message toward CC process.
* the CC process will change the reject message to a release message when not in INIT_IN state
*/
static void rej_msg(osmo_cc_socket_t *os, uint32_t callref, uint8_t socket_cause, uint8_t isdn_cause, uint16_t sip_cause)
{
osmo_cc_msg_t *msg;
/* create message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_REJ_REQ);
if (!msg)
abort();
/* add cause */
osmo_cc_add_ie_cause(msg, os->location, isdn_cause, sip_cause, socket_cause);
osmo_cc_convert_cause_msg(msg);
/* message down */
os->recv_msg_cb(os->priv, callref, msg);
}
static void tx_keepalive_timeout(void *data)
{
osmo_cc_conn_t *conn = data;
osmo_cc_msg_t *msg;
/* send keepalive message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_DUMMY_REQ);
osmo_cc_msg_list_enqueue(&conn->os->write_list, msg, conn->callref);
timer_start(&conn->tx_keepalive_timer, OSMO_CC_SOCKET_TX_KEEPALIVE);
}
static void close_conn(osmo_cc_conn_t *conn, uint8_t socket_cause);
static void rx_keepalive_timeout(void *data)
{
osmo_cc_conn_t *conn = data;
LOGP(DCC, LOGL_ERROR, "OsmoCC-Socket failed due to timeout.\n");
close_conn(conn, OSMO_CC_SOCKET_CAUSE_TIMEOUT);
}
static int socket_listen_cb(struct osmo_fd *ofd, unsigned int when);
/* create socket process and bind socket */
int osmo_cc_open_socket(osmo_cc_socket_t *os, const char *host, uint16_t port, void *priv, void (*recv_msg_cb)(void *priv, uint32_t callref, osmo_cc_msg_t *msg), uint8_t location)
{
int try = 0, auto_port = 0;
struct addrinfo *result, *rp;
int rc, sock;
memset(os, 0, sizeof(*os));
try_again:
/* check for given port, if NULL, autoselect port */
if (!port || auto_port) {
port = OSMO_CC_DEFAULT_PORT + try;
try++;
auto_port = 1;
}
LOGP(DCC, LOGL_DEBUG, "Create socket for host %s port %d.\n", host, port);
rc = _getaddrinfo(host, port, &result);
if (rc < 0)
return rc;
for (rp = result; rp; rp = rp->ai_next) {
int on = 1;
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sock < 0)
continue;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (unsigned char *)&on, sizeof(on));
rc = bind(sock, rp->ai_addr, rp->ai_addrlen);
if (rc == 0)
break;
close(sock);
}
freeaddrinfo(result);
if (rp == NULL) {
if (auto_port && port < OSMO_CC_DEFAULT_PORT_MAX) {
LOGP(DCC, LOGL_DEBUG, "Failed to bind host %s port %d, trying again.\n", host, port);
goto try_again;
}
LOGP(DCC, LOGL_ERROR, "Failed to bind given host %s port %d.\n", host, port);
return -EIO;
}
/* listen to socket */
rc = listen(sock, 10);
if (rc < 0) {
LOGP(DCC, LOGL_ERROR, "Failed to listen on socket.\n");
close(sock);
return rc;
}
/* register */
os->ofd.fd = sock;
os->ofd.cb = socket_listen_cb;
os->ofd.data = os;
os->ofd.when = OSMO_FD_READ;
osmo_fd_register(&os->ofd);
os->recv_msg_cb = recv_msg_cb;
os->priv = priv;
os->location = location;
return port;
}
static int socket_conn_cb(struct osmo_fd *ofd, unsigned int when);
/* create a connection */
static osmo_cc_conn_t *open_conn(osmo_cc_socket_t *os, int sock, uint32_t callref, int read_setup)
{
osmo_cc_conn_t *conn, **connp;
/* create connection */
conn = calloc(1, sizeof(*conn));
if (!conn) {
LOGP(DCC, LOGL_ERROR, "No mem!\n");
abort();
}
conn->os = os;
conn->ofd.fd = sock;
conn->ofd.cb = socket_conn_cb;
conn->ofd.data = conn;
conn->ofd.when = OSMO_FD_READ;
osmo_fd_register(&conn->ofd);
conn->read_version = 1;
conn->write_version = 1;
conn->read_setup = read_setup;
if (callref)
conn->callref = callref;
else
conn->callref = osmo_cc_new_callref();
timer_init(&conn->tx_keepalive_timer, tx_keepalive_timeout, conn);
timer_init(&conn->rx_keepalive_timer, rx_keepalive_timeout, conn);
timer_start(&conn->tx_keepalive_timer, OSMO_CC_SOCKET_TX_KEEPALIVE);
timer_start(&conn->rx_keepalive_timer, OSMO_CC_SOCKET_RX_KEEPALIVE);
LOGP(DCC, LOGL_DEBUG, "New socket connection (callref %d).\n", conn->callref);
/* attach to list */
connp = &os->conn_list;
while (*connp)
connp = &((*connp)->next);
*connp = conn;
return conn;
}
/* remove a connection */
static void close_conn(osmo_cc_conn_t *conn, uint8_t socket_cause)
{
osmo_cc_conn_t **connp;
osmo_cc_msg_list_t *ml;
/* detach connection first, to prevent a destruction during message handling (double free) */
connp = &conn->os->conn_list;
while (*connp != conn)
connp = &((*connp)->next);
*connp = conn->next;
/* send reject message, if socket_cause is set */
if (socket_cause && !conn->read_setup) {
/* receive a release or reject (depending on state), but only if we sent a setup */
rej_msg(conn->os, conn->callref, socket_cause, 0, 0);
}
LOGP(DCC, LOGL_DEBUG, "Destroy socket connection (callref %d).\n", conn->callref);
/* close socket */
if (conn->ofd.fd) {
osmo_fd_unregister(&conn->ofd);
close(conn->ofd.fd);
}
/* free partly received message */
if (conn->read_msg)
osmo_cc_free_msg(conn->read_msg);
/* free send queue */
while ((ml = conn->write_list)) {
osmo_cc_free_msg(ml->msg);
conn->write_list = ml->next;
free(ml);
}
/* free timers */
timer_exit(&conn->tx_keepalive_timer);
timer_exit(&conn->rx_keepalive_timer);
/* free connection (already detached above) */
free(conn);
}
/* close socket and remove */
void osmo_cc_close_socket(osmo_cc_socket_t *os)
{
osmo_cc_msg_list_t *ml;
LOGP(DCC, LOGL_DEBUG, "Destroy socket.\n");
/* free all connections */
while (os->conn_list)
close_conn(os->conn_list, 0);
/* close socket */
if (os->ofd.fd > 0) {
osmo_fd_unregister(&os->ofd);
close(os->ofd.fd);
os->ofd.fd = 0;
}
/* free send queue */
while ((ml = os->write_list)) {
osmo_cc_free_msg(ml->msg);
os->write_list = ml->next;
free(ml);
}
}
/* send message to send_queue of sock instance */
int osmo_cc_sock_send_msg(osmo_cc_socket_t *os, uint32_t callref, osmo_cc_msg_t *msg, const char *host, uint16_t port)
{
osmo_cc_msg_list_t *ml;
/* turn _IND into _REQ and _CNF into _RSP */
msg->type &= ~1;
/* create list entry */
ml = osmo_cc_msg_list_enqueue(&os->write_list, msg, callref);
if (host)
strncpy(ml->host, host, sizeof(ml->host) - 1);
ml->port = port;
return 0;
}
/* receive message
* return 1 if work was done.
*/
static int receive_conn(osmo_cc_conn_t *conn)
{
uint8_t socket_cause = OSMO_CC_SOCKET_CAUSE_BROKEN_PIPE;
int rc;
osmo_cc_msg_t *msg;
uint8_t msg_type;
int len;
int work = 0;
/* get version from remote */
if (conn->read_version) {
rc = recv(conn->ofd.fd, conn->read_version_string + conn->read_version_pos, strlen(version_string) - conn->read_version_pos, 0);
if (rc < 0 && errno == EAGAIN)
return work;
work = 1;
if (rc <= 0) {
goto close;
}
conn->read_version_pos += rc;
if (conn->read_version_pos == strlen(version_string)) {
conn->read_version = 0;
if (!!memcmp(conn->read_version_string, version_string, strlen(version_string) - 1)) {
LOGP(DCC, LOGL_NOTICE, "Remote does not seem to be an Osmo-CC socket, rejecting!\n");
socket_cause = OSMO_CC_SOCKET_CAUSE_FAILED;
goto close;
}
if (conn->read_version_string[strlen(version_string) - 1] != version_string[strlen(version_string) - 1]) {
LOGP(DCC, LOGL_NOTICE, "Remote Osmo-CC socket has wrong version (local=%s, remote=%s), rejecting!\n", version_string, conn->read_version_string);
socket_cause = OSMO_CC_SOCKET_CAUSE_VERSION_MISMATCH;
goto close;
}
} else
return work;
}
try_next_message:
/* read message header from remote */
if (!conn->read_msg) {
rc = recv(conn->ofd.fd, ((uint8_t *)&conn->read_hdr) + conn->read_pos, sizeof(conn->read_hdr) - conn->read_pos, 0);
if (rc < 0 && errno == EAGAIN)
return work;
work = 1;
if (rc <= 0) {
goto close;
}
conn->read_pos += rc;
if (conn->read_pos == sizeof(conn->read_hdr)) {
conn->read_msg = osmo_cc_new_msg(conn->read_hdr.type);
if (!conn->read_msg)
abort();
conn->read_msg->length_networkorder = conn->read_hdr.length_networkorder;
/* prepare for reading message */
conn->read_pos = 0;
} else
return work;
}
/* read message data from remote */
msg = conn->read_msg;
len = ntohs(msg->length_networkorder);
if (len == 0)
goto empty_message;
rc = recv(conn->ofd.fd, msg->data + conn->read_pos, len - conn->read_pos, 0);
if (rc < 0 && errno == EAGAIN)
return work;
work = 1;
if (rc <= 0) {
goto close;
}
conn->read_pos += rc;
if (conn->read_pos == len) {
empty_message:
/* start RX keepalive timeer, if not already */
timer_start(&conn->rx_keepalive_timer, OSMO_CC_SOCKET_RX_KEEPALIVE);
/* we got our setup message, so we clear the flag */
conn->read_setup = 0;
/* prepare for reading header */
conn->read_pos = 0;
/* detach message first, because the connection might be destroyed during message handling */
msg_type = conn->read_msg->type;
conn->read_msg = NULL;
/* drop dummy or forward message */
if (msg_type == OSMO_CC_MSG_DUMMY_REQ)
osmo_cc_free_msg(msg);
else
conn->os->recv_msg_cb(conn->os->priv, conn->callref, msg);
if (msg_type == OSMO_CC_MSG_REL_REQ || msg_type == OSMO_CC_MSG_REJ_REQ) {
LOGP(DCC, LOGL_DEBUG, "closing socket because we received a release or reject message.\n");
close_conn(conn, 0);
return 1; /* conn removed */
}
goto try_next_message;
}
return work;
close:
LOGP(DCC, LOGL_ERROR, "OsmoCC-Socket failed, socket cause %d.\n", socket_cause);
close_conn(conn, socket_cause);
return work; /* conn removed */
}
/* transmit message
* return 1 if work was done.
*/
static int transmit_conn(osmo_cc_conn_t *conn)
{
uint8_t socket_cause = OSMO_CC_SOCKET_CAUSE_BROKEN_PIPE;
int rc;
osmo_cc_msg_t *msg;
int len;
osmo_cc_msg_list_t *ml;
int work = 0;
/* send socket version to remote */
if (conn->write_version) {
rc = write(conn->ofd.fd, version_string, strlen(version_string));
if (rc < 0 && errno == EAGAIN)
return work;
work = 1;
if (rc <= 0) {
goto close;
}
if (rc != strlen(version_string)) {
LOGP(DCC, LOGL_ERROR, "short write, please fix handling!\n");
abort();
}
conn->write_version = 0;
}
/* send message to remote */
while (conn->write_list) {
timer_stop(&conn->tx_keepalive_timer);
msg = conn->write_list->msg;
len = sizeof(*msg) + ntohs(msg->length_networkorder);
rc = write(conn->ofd.fd, msg, len);
if (rc < 0 && errno == EAGAIN)
return work;
work = 1;
if (rc <= 0) {
goto close;
}
if (rc != len) {
LOGP(DCC, LOGL_ERROR, "short write, please fix handling!\n");
abort();
}
/* close socket after sending release/reject message */
if (msg->type == OSMO_CC_MSG_REL_REQ || msg->type == OSMO_CC_MSG_REJ_REQ) {
LOGP(DCC, LOGL_DEBUG, "closing socket because we sent a release or reject message.\n");
close_conn(conn, 0);
return work; /* conn removed */
}
/* free message after sending */
ml = conn->write_list;
conn->write_list = ml->next;
osmo_cc_free_msg(msg);
free(ml);
}
/* start TX keepalive timeer, if not already
* because we stop at every message above, we actually restart the timer here.
* only if there is no message for the amount of time, the timer fires.
*/
if (!timer_running(&conn->tx_keepalive_timer))
timer_start(&conn->tx_keepalive_timer, OSMO_CC_SOCKET_TX_KEEPALIVE);
return work;
close:
LOGP(DCC, LOGL_NOTICE, "OsmoCC-Socket failed.\n");
close_conn(conn, socket_cause);
return work; /* conn removed */
}
/* handle all sockets of a socket interface
* return 1 if work was done.
*/
int osmo_cc_handle_socket(osmo_cc_socket_t *os)
{
int sock;
osmo_cc_conn_t *conn;
osmo_cc_msg_list_t *ml, **mlp;
int flags;
struct addrinfo *result, *rp;
int rc;
int work = 0;
/* handle messages in send queue */
while ((ml = os->write_list)) {
work = 1;
/* detach list entry */
os->write_list = ml->next;
ml->next = NULL;
/* search for socket connection */
for (conn = os->conn_list; conn; conn=conn->next) {
if (conn->callref == ml->callref)
break;
}
if (conn) {
/* attach to list */
mlp = &conn->write_list;
while (*mlp)
mlp = &((*mlp)->next);
*mlp = ml;
conn->ofd.when |= OSMO_FD_WRITE;
/* done with message */
continue;
}
/* reject and release are ignored */
if (ml->msg->type == OSMO_CC_MSG_REJ_REQ
|| ml->msg->type == OSMO_CC_MSG_REL_REQ) {
/* drop message */
osmo_cc_free_msg(ml->msg);
free(ml);
/* done with message */
continue;
}
/* reject, if this is not a setup message */
if (ml->msg->type != OSMO_CC_MSG_SETUP_REQ
&& ml->msg->type != OSMO_CC_MSG_ATTACH_REQ) {
LOGP(DCC, LOGL_ERROR, "Message with unknown callref.\n");
rej_msg(os, ml->callref, 0, OSMO_CC_ISDN_CAUSE_INVAL_CALLREF, 0);
/* drop message */
osmo_cc_free_msg(ml->msg);
free(ml);
/* done with message */
continue;
}
/* connect to remote */
rc = _getaddrinfo(ml->host, ml->port, &result);
if (rc < 0) {
rej_msg(os, ml->callref, OSMO_CC_SOCKET_CAUSE_FAILED, 0, 0);
/* drop message */
osmo_cc_free_msg(ml->msg);
free(ml);
/* done with message */
continue;
}
for (rp = result; rp; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sock < 0)
continue;
/* set nonblocking io, to prevent connect() and subsequent reads from blocking */
flags = fcntl(sock, F_GETFL);
flags |= O_NONBLOCK;
fcntl(sock, F_SETFL, flags);
/* connect */
rc = connect(sock, rp->ai_addr, rp->ai_addrlen);
if (rc == 0 || errno == EINPROGRESS)
break;
close(sock);
}
freeaddrinfo(result);
if (rp == NULL) {
LOGP(DCC, LOGL_ERROR, "Failed to connect to given host %s port %d.\n", ml->host, ml->port);
rej_msg(os, ml->callref, OSMO_CC_SOCKET_CAUSE_FAILED, 0, 0);
/* drop message */
osmo_cc_free_msg(ml->msg);
free(ml);
/* done with message */
continue;
}
/* create connection */
conn = open_conn(os, sock, ml->callref, 0);
/* attach to list */
conn->write_list = ml;
conn->ofd.when |= OSMO_FD_WRITE;
/* done with (setup) message */
}
return work;
}
static int socket_listen_cb(struct osmo_fd *ofd, unsigned int when)
{
osmo_cc_socket_t *os = ofd->data;
struct sockaddr_storage sa;
socklen_t slen = sizeof(sa);
int sock;
int flags;
if (when & OSMO_FD_READ) {
/* handle new socket connection */
if ((sock = accept(os->ofd.fd, (struct sockaddr *)&sa, &slen)) > 0) {
/* set nonblocking io, to prevent subsequent reads from blocking */
flags = fcntl(sock, F_GETFL);
flags |= O_NONBLOCK;
fcntl(sock, F_SETFL, flags);
/* create connection */
open_conn(os, sock, 0, 1);
}
}
return 0;
}
static int socket_conn_cb(struct osmo_fd *ofd, unsigned int when)
{
osmo_cc_conn_t *conn = ofd->data;
int work;
if (when & OSMO_FD_READ) {
/* check for rx */
work = receive_conn(conn);
/* if "change" is set, connection list might have changed, so we restart processing the list */
if (work)
return 0;
}
if (when & OSMO_FD_WRITE) {
/* check for tx */
work = transmit_conn(conn);
/* if "change" is set, connection list might have changed, so we restart processing the list */
if (work)
return 0;
else
conn->ofd.when &= ~OSMO_FD_WRITE;
}
return 0;
}

View File

@ -1,44 +0,0 @@
#ifndef OSMO_CC_SOCKET_H
#define OSMO_CC_SOCKET_H
#define OSMO_CC_DEFAULT_PORT 4200
#define OSMO_CC_DEFAULT_PORT_MAX 4219
#define OSMO_CC_SOCKET_TX_KEEPALIVE 10.0
#define OSMO_CC_SOCKET_RX_KEEPALIVE 20.0
struct osmo_cc_socket;
typedef struct osmo_cc_conn {
struct osmo_cc_conn *next;
struct osmo_cc_socket *os;
struct osmo_fd ofd;
uint32_t callref;
int read_setup;
int read_version;
char read_version_string[sizeof(OSMO_CC_VERSION)]; /* must include 0-termination */
int read_version_pos;
int write_version;
osmo_cc_msg_t read_hdr;
osmo_cc_msg_t *read_msg;
int read_pos;
osmo_cc_msg_list_t *write_list;
struct timer tx_keepalive_timer;
struct timer rx_keepalive_timer;
} osmo_cc_conn_t;
typedef struct osmo_cc_socket {
struct osmo_fd ofd;
osmo_cc_conn_t *conn_list;
osmo_cc_msg_list_t *write_list;
void (*recv_msg_cb)(void *priv, uint32_t callref, osmo_cc_msg_t *msg);
void *priv;
uint8_t location;
} osmo_cc_socket_t;
int osmo_cc_open_socket(osmo_cc_socket_t *os, const char *host, uint16_t port, void *priv, void (*recv_msg_cb)(void *priv, uint32_t callref, osmo_cc_msg_t *msg), uint8_t location);
void osmo_cc_close_socket(osmo_cc_socket_t *os);
int osmo_cc_sock_send_msg(osmo_cc_socket_t *os, uint32_t callref, osmo_cc_msg_t *msg, const char *host, uint16_t port);
int osmo_cc_handle_socket(osmo_cc_socket_t *os);
#endif /* OSMO_CC_SOCKET_H */

View File

@ -3,9 +3,11 @@
* (C) 2022 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* SPDX-License-Identifier: GPL-2.0+
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
@ -13,8 +15,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdio.h>
@ -26,9 +30,10 @@
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "../libtimer/timer.h"
#include "../libselect/select.h"
#include "../libdebug/debug.h"
#include <osmocom/core/utils.h>
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include "../liblogging/logging.h"
#include "ph_socket.h"
static int ph_socket_listen_cb(struct osmo_fd *ofd, unsigned int __attribute__((unused)) what);

View File

@ -4,12 +4,12 @@
/*
* Procedure:
*
* If socket connection is establised, a PH_PRIM_CTRL_REQ message with
* If socket connection is established, a PH_PRIM_CTRL_REQ message with
* PH_CTRL_ENABLE information is received by the socket server user.
* If the socket connection is lost, a PH_PRIM_CTRL_REQ message with
* PH_CTRL_DISABLE information is received by the user.
*
* If socket connection is establised, a PH_PRIM_CTRL_IND message with
*
* If socket connection is established, a PH_PRIM_CTRL_IND message with
* PH_CTRL_ENABLE information is received by the socket client user.
* If the socket connection is lost, a PH_PRIM_CTRL_IND message with
* PH_CTRL_DISABLE information is received by the user.
@ -24,14 +24,14 @@
* PH_PRIM_DACT_IND, if the socket is currently unavailable.
*
* PH_PRIM_CTRL_REQ and PH_PRIM_CTRL_IND messages with PH_CTRL_ENABLE
* and PH_CTRL_DISABLE informations are not assoicated with a channel
* and PH_CTRL_DISABLE information are not associated with a channel
* number. The socket sender shall set it to 0, the receiver shall
* ignore it.
*
* A missing MODE in PH_PRIM_ACT_REQ is interepreted as default:
* A missing MODE in PH_PRIM_ACT_REQ is interpreted as default:
* HDLC on D-channel, TRANS on B-channel.
*
* Each packet on the socket shall have the follwoing header:
* Each packet on the socket shall have the following header:
* uint8_t channel;
* uint8_t prim;
* uint16_t length;
@ -65,8 +65,8 @@
#define PH_CTRL_BLOCK 0x00 /* disable (block) interface, when socket is disconnected */
#define PH_CTRL_UNBLOCK 0x01 /* enable (unblock) interface, when socket is connected */
#define PH_CTRL_LOOP_DISABLE 0x04 /* disable loopback */
#define PH_CTRL_LOOP1_ENABLE 0x05 /* enable LT transceier loopback */
#define PH_CTRL_LOOP2_ENABLE 0x06 /* enable NT transceier loopback */
#define PH_CTRL_LOOP1_ENABLE 0x05 /* enable LT transceiver loopback */
#define PH_CTRL_LOOP2_ENABLE 0x06 /* enable NT transceiver loopback */
#define PH_CTRL_LOOP_ERROR 0x10 /* frame error report (loopback test) */
#define PH_CTRL_VIOLATION_LT 0x11 /* code violation received by LT */
#define PH_CTRL_VIOLATION_NT 0x12 /* code violation received by NT */

View File

@ -1,6 +0,0 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
noinst_LIBRARIES = libselect.a
libselect_a_SOURCES = \
select.c

View File

@ -1,168 +0,0 @@
/* Timer handling
*
* (C) 2023 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* Inspired by libosmocore
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include "select.h"
//#define DEBUG
#define MAX_OFD 1024
struct osmo_fd *ofd_list = NULL;
int ofd_changed = 0;
int osmo_fd_register(struct osmo_fd *ofd)
{
struct osmo_fd **ofdp;
/* attach to list, if not already */
ofdp = &ofd_list;
while (*ofdp) {
if (*ofdp == ofd)
break;
ofdp = &((*ofdp)->next);
}
if (!*ofdp) {
#ifdef DEBUG
fprintf(stderr, "%s: ofd=%p fd=%d registers.\n", __func__, ofd, ofd->fd);
#endif
ofd->next = NULL;
*ofdp = ofd;
ofd_changed = 1;
}
return 0;
}
void osmo_fd_unregister(struct osmo_fd *ofd)
{
struct osmo_fd **ofdp;
/* detach from list, if not already */
ofdp = &ofd_list;
while (*ofdp) {
if (*ofdp == ofd)
break;
ofdp = &((*ofdp)->next);
}
if (*ofdp) {
#ifdef DEBUG
fprintf(stderr, "%s: ofd=%p fd=%d unregisters.\n", __func__, ofd, ofd->fd);
#endif
*ofdp = ofd->next;
ofd->next = NULL;
ofd_changed = 1;
}
}
int osmo_fd_select(double timeout)
{
fd_set readset;
fd_set writeset;
fd_set exceptset;
struct osmo_fd *ofd;
struct timeval tv;
int max_fd;
unsigned int what;
int work = 0;
int rc;
/* init event sets */
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_ZERO(&exceptset);
/* populate event set with all file descriptios */
ofd = ofd_list;
max_fd = 0;
while (ofd) {
if (ofd->fd > max_fd)
max_fd = ofd->fd;
if (ofd->when & OSMO_FD_READ)
FD_SET(ofd->fd, &readset);
if (ofd->when & OSMO_FD_WRITE)
FD_SET(ofd->fd, &writeset);
if (ofd->when & OSMO_FD_EXCEPT)
FD_SET(ofd->fd, &exceptset);
ofd = ofd->next;
}
if (timeout >= 0) {
/* prepare timeout */
tv.tv_sec = floor(timeout);
tv.tv_usec = (timeout - tv.tv_sec) * 1000000.0;
/* wait for event or timeout */
rc = select(max_fd + 1, &readset, &writeset, &exceptset, &tv);
} else {
/* wait for event */
rc = select(max_fd + 1, &readset, &writeset, &exceptset, NULL);
}
if (rc < 0) {
if (errno != EINTR)
fprintf(stderr, "%s: select() failed: '%d' with errno %d (%s) Please fix!\n", __func__, rc, errno, strerror(errno));
return 0;
}
again:
/* check the result and call handler */
ofd_changed = 0;
ofd = ofd_list;
while (ofd) {
what = 0;
if (FD_ISSET(ofd->fd, &readset)) {
#ifdef DEBUG
fprintf(stderr, "%s: ofd=%p fd=%d get READ event.\n", __func__, ofd, ofd->fd);
#endif
what |= OSMO_FD_READ;
FD_CLR(ofd->fd, &readset);
}
if (FD_ISSET(ofd->fd, &writeset)) {
#ifdef DEBUG
fprintf(stderr, "%s: ofd=%p fd=%d get WRITE event.\n", __func__, ofd, ofd->fd);
#endif
what |= OSMO_FD_WRITE;
FD_CLR(ofd->fd, &writeset);
}
if (FD_ISSET(ofd->fd, &exceptset)) {
#ifdef DEBUG
fprintf(stderr, "%s: ofd=%p fd=%d get EXCEPTION event.\n", __func__, ofd, ofd->fd);
#endif
what |= OSMO_FD_EXCEPT;
FD_CLR(ofd->fd, &exceptset);
}
if (what) {
work = 1;
ofd->cb(ofd, what);
/* list has changed */
if (ofd_changed)
goto again;
}
ofd = ofd->next;
}
return work;
}

View File

@ -1,20 +0,0 @@
#define OSMO_FD_READ 0x0001
#define OSMO_FD_WRITE 0x0002
#define OSMO_FD_EXCEPT 0x0004
#define BSC_FD_READ 0x0001
#define BSC_FD_WRITE 0x0002
#define BSC_FD_EXCEPT 0x0004
struct osmo_fd {
struct osmo_fd *next;
int fd;
unsigned int when;
int (*cb)(struct osmo_fd *fd, unsigned int what);
void *data;
};
int osmo_fd_register(struct osmo_fd *ofd);
void osmo_fd_unregister(struct osmo_fd *ofd);
int osmo_fd_select(double timeout);

View File

@ -1,6 +0,0 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
noinst_LIBRARIES = libtimer.a
libtimer_a_SOURCES = \
timer.c

View File

@ -1,165 +0,0 @@
/* Timer handling
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
//#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include "timer.h"
//#define DEBUG
static struct timer *timer_head = NULL;
static struct timer **timer_tail_p = &timer_head;
double get_time(void)
{
static struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
return (double)tv.tv_sec + (double)tv.tv_nsec / 1000000000.0;
}
void timer_init(struct timer *timer, void (*fn)(void *data), void *priv)
{
if (timer->linked) {
fprintf(stderr, "Timer is already initialized, aborting!\n");
abort();
}
timer->timeout = 0;
timer->cb = fn;
timer->data = priv;
timer->next = NULL;
*timer_tail_p = timer;
timer_tail_p = &timer->next;
timer->linked = 1;
#ifdef DEBUG
fprintf(stderr, "%s: timer=%p linked.\n", __func__, timer);
#endif
}
void timer_exit(struct timer *timer)
{
timer_tail_p = &timer_head;
while (*timer_tail_p) {
if (timer == *timer_tail_p)
*timer_tail_p = (*timer_tail_p)->next;
else
timer_tail_p = &((*timer_tail_p)->next);
}
timer->linked = 0;
#ifdef DEBUG
fprintf(stderr, "%s: timer=%p unlinked.\n", __func__, timer);
#endif
}
void timer_start(struct timer *timer, double duration)
{
if (!timer->linked) {
fprintf(stderr, "Timer is not initialized, aborting!\n");
abort();
}
timer->duration = duration;
timer->timeout = get_time() + duration;
#ifdef DEBUG
fprintf(stderr, "%s: timer=%p started %.3f seconds.\n", __func__, timer, duration);
#endif
}
void timer_stop(struct timer *timer)
{
if (!timer->linked) {
fprintf(stderr, "Timer is not initialized, aborting!\n");
abort();
}
timer->timeout = 0;
#ifdef DEBUG
fprintf(stderr, "%s: timer=%p stopped.\n", __func__, timer);
#endif
}
int timer_running(struct timer *timer)
{
if (!timer->linked) {
fprintf(stderr, "Timer is not initialized, aborting!\n");
abort();
}
return (timer->timeout != 0);
}
double process_timer(void)
{
struct timer *timer;
double now, timeout = -1.0;
now = get_time();
again:
timer = timer_head;
while (timer) {
if (timer->linked && timer->timeout > 0) {
/* timeout, handle it, set timeout to 0 */
if (now >= timer->timeout) {
timer->timeout = 0;
#ifdef DEBUG
fprintf(stderr, "%s: timer=%p fired.\n", __func__, timer);
#endif
if (!timer->cb)
abort();
timer->cb(timer->data);
timeout = 0.0;
goto again;
}
/* in the future, set timeout to future */
if (timeout < 0.0 || (timer->timeout - now) < timeout)
timeout = timer->timeout - now;
}
timer = timer->next;
}
return timeout;
}
void osmo_timer_schedule(struct osmo_timer_list *ti, time_t sec, suseconds_t usec)
{
if (!ti->linked)
timer_init(ti, ti->cb, ti->data);
timer_start(ti, (double)sec + (double)usec / 1000000.0);
}
void osmo_timer_del(struct osmo_timer_list *ti)
{
timer_exit(ti);
}
int osmo_timer_pending(struct osmo_timer_list *ti)
{
if (!ti->linked)
return 0;
return (ti->timeout != 0);
}

View File

@ -1,23 +0,0 @@
struct timer {
struct timer *next;
int linked; /* set is timer is initialized and linked */
double duration;
double timeout;
void (*cb)(void *data);
void *data;
};
double get_time(void);
void timer_init(struct timer *timer, void (*fn)(void *data), void *priv);
void timer_exit(struct timer *timer);
void timer_start(struct timer *timer, double duration);
void timer_stop(struct timer *timer);
int timer_running(struct timer *timer);
double process_timer(void);
#define osmo_timer_list timer
void osmo_timer_schedule(struct osmo_timer_list *ti, time_t sec, long usec);
void osmo_timer_del(struct osmo_timer_list *ti);
int osmo_timer_pending(struct osmo_timer_list *ti);