Replace polling by select and timer events
This commit is contained in:
parent
3e970cbc48
commit
8c10ee4a26
|
@ -40,6 +40,7 @@ src/liboptions/liboptions.a
|
||||||
src/libosmocc/libosmocc.a
|
src/libosmocc/libosmocc.a
|
||||||
src/libsample/libsample.a
|
src/libsample/libsample.a
|
||||||
src/libtimer/libtimer.a
|
src/libtimer/libtimer.a
|
||||||
|
src/libselect/libselect.a
|
||||||
src/libph_socket/libph_socket.a
|
src/libph_socket/libph_socket.a
|
||||||
src/libmisdn/libmisdn.a
|
src/libmisdn/libmisdn.a
|
||||||
src/libmisdnuser/libmisdnuser.a
|
src/libmisdnuser/libmisdnuser.a
|
||||||
|
|
|
@ -84,6 +84,7 @@ AC_OUTPUT(
|
||||||
src/libdebug/Makefile
|
src/libdebug/Makefile
|
||||||
src/libsample/Makefile
|
src/libsample/Makefile
|
||||||
src/libtimer/Makefile
|
src/libtimer/Makefile
|
||||||
|
src/libselect/Makefile
|
||||||
src/libjitter/Makefile
|
src/libjitter/Makefile
|
||||||
src/libosmocc/Makefile
|
src/libosmocc/Makefile
|
||||||
src/libg711/Makefile
|
src/libg711/Makefile
|
||||||
|
|
|
@ -5,6 +5,7 @@ SUBDIRS = \
|
||||||
libdebug \
|
libdebug \
|
||||||
libsample \
|
libsample \
|
||||||
libtimer \
|
libtimer \
|
||||||
|
libselect \
|
||||||
libjitter \
|
libjitter \
|
||||||
libosmocc \
|
libosmocc \
|
||||||
libg711 \
|
libg711 \
|
||||||
|
|
|
@ -18,6 +18,7 @@ osmo_cc_misdn_endpoint_LDADD = \
|
||||||
../liboptions/liboptions.a \
|
../liboptions/liboptions.a \
|
||||||
../libsample/libsample.a \
|
../libsample/libsample.a \
|
||||||
../libtimer/libtimer.a \
|
../libtimer/libtimer.a \
|
||||||
|
../libselect/libselect.a \
|
||||||
../libjitter/libjitter.a \
|
../libjitter/libjitter.a \
|
||||||
../libosmocc/libosmocc.a \
|
../libosmocc/libosmocc.a \
|
||||||
../libg711/libg711.a \
|
../libg711/libg711.a \
|
||||||
|
|
|
@ -113,7 +113,7 @@ static int num_slots;
|
||||||
|
|
||||||
struct conn {
|
struct conn {
|
||||||
struct conn *next;
|
struct conn *next;
|
||||||
int socket;
|
struct osmo_fd ofd;
|
||||||
int rx_index;
|
int rx_index;
|
||||||
struct msg_channel_info
|
struct msg_channel_info
|
||||||
rx_msg;
|
rx_msg;
|
||||||
|
@ -137,7 +137,8 @@ struct channel {
|
||||||
int tx_bank;
|
int tx_bank;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int server_socket;
|
static struct osmo_fd server_ofd = { .fd = -1 };
|
||||||
|
static struct timer server_timer;
|
||||||
static struct conn *conn_list = NULL;
|
static struct conn *conn_list = NULL;
|
||||||
static struct channel *channel_list = NULL;
|
static struct channel *channel_list = NULL;
|
||||||
|
|
||||||
|
@ -190,18 +191,20 @@ static void free_all_connections(void)
|
||||||
while (c) {
|
while (c) {
|
||||||
PDEBUG(DISDN, DEBUG_INFO, "Free pending bridge connection.\n");
|
PDEBUG(DISDN, DEBUG_INFO, "Free pending bridge connection.\n");
|
||||||
c2 = c;
|
c2 = c;
|
||||||
close(c->socket);
|
osmo_fd_unregister(&c->ofd);
|
||||||
|
close(c->ofd.fd);
|
||||||
c = c->next;
|
c = c->next;
|
||||||
free(c2);
|
free(c2);
|
||||||
}
|
}
|
||||||
conn_list = NULL;
|
conn_list = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bridge_socket_server_cb(struct osmo_fd *ofd, unsigned int when);
|
||||||
|
|
||||||
/* function to open the server socket */
|
/* function to open the server socket */
|
||||||
static int open_server_socket(int daemon)
|
static int open_server_socket(int daemon)
|
||||||
{
|
{
|
||||||
struct sockaddr_un sock_address;
|
struct sockaddr_un sock_address;
|
||||||
int flags;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
memset(&sock_address, 0, sizeof(sock_address));
|
memset(&sock_address, 0, sizeof(sock_address));
|
||||||
|
@ -213,64 +216,70 @@ static int open_server_socket(int daemon)
|
||||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to create UNIX socket.\n");
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to create UNIX socket.\n");
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
server_socket = rc;
|
server_ofd.fd = rc;
|
||||||
|
server_ofd.cb = bridge_socket_server_cb;
|
||||||
|
server_ofd.data = NULL;
|
||||||
|
server_ofd.when = OSMO_FD_READ;
|
||||||
|
osmo_fd_register(&server_ofd);
|
||||||
|
|
||||||
rc = bind(server_socket, (struct sockaddr *)(&sock_address), sizeof(struct sockaddr_un));
|
rc = bind(server_ofd.fd, (struct sockaddr *)(&sock_address), sizeof(struct sockaddr_un));
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
if (!daemon || errno != EADDRINUSE)
|
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));
|
PDEBUG(DISDN, DEBUG_INFO, "Failed to bind UNIX socket with path '%s' (errno = %d (%s)).\n", SOCKET_NAME, errno, strerror(errno));
|
||||||
close(server_socket);
|
osmo_fd_unregister(&server_ofd);
|
||||||
|
close(server_ofd.fd);
|
||||||
return -EADDRINUSE;
|
return -EADDRINUSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = listen(server_socket, 10);
|
rc = listen(server_ofd.fd, 10);
|
||||||
if (rc < 0) {
|
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));
|
PDEBUG(DISDN, DEBUG_INFO, "Failed to listen to UNIX socket with path '%s' (errno = %d (%s)).\n", SOCKET_NAME, errno, strerror(errno));
|
||||||
close(server_socket);
|
osmo_fd_unregister(&server_ofd);
|
||||||
|
close(server_ofd.fd);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set nonblocking io */
|
|
||||||
flags = fcntl(server_socket, F_GETFL);
|
|
||||||
flags |= O_NONBLOCK;
|
|
||||||
fcntl(server_socket, F_SETFL, flags);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void listen_server_socket(void)
|
static int bridge_socket_conn_cb(struct osmo_fd *ofd, unsigned int when);
|
||||||
|
|
||||||
|
static int bridge_socket_server_cb(struct osmo_fd __attribute__((unused)) *ofd, unsigned int when)
|
||||||
{
|
{
|
||||||
struct sockaddr_un sock_address;
|
struct sockaddr_un sock_address;
|
||||||
socklen_t sock_len = sizeof(sock_address);
|
socklen_t sock_len = sizeof(sock_address);
|
||||||
struct conn *c;
|
struct conn *c;
|
||||||
int flags;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = accept(server_socket, (struct sockaddr *)&sock_address, &sock_len);
|
if ((when & OSMO_FD_READ)) {
|
||||||
if (rc > 0) {
|
rc = accept(server_ofd.fd, (struct sockaddr *)&sock_address, &sock_len);
|
||||||
PDEBUG(DISDN, DEBUG_INFO, "Connection from bridge socket client.\n");
|
if (rc > 0) {
|
||||||
/* create connection */
|
PDEBUG(DISDN, DEBUG_INFO, "Connection from bridge socket client.\n");
|
||||||
c = calloc(1, sizeof(*c));
|
/* create connection */
|
||||||
if (!c) {
|
c = calloc(1, sizeof(*c));
|
||||||
PDEBUG(DISDN, DEBUG_ERROR, "No mem!\n");
|
if (!c) {
|
||||||
abort();
|
PDEBUG(DISDN, DEBUG_ERROR, "No mem!\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
c->next = conn_list;
|
||||||
|
conn_list = c;
|
||||||
|
c->ofd.fd = rc;
|
||||||
|
c->ofd.cb = bridge_socket_conn_cb;
|
||||||
|
c->ofd.data = c;
|
||||||
|
c->ofd.when = OSMO_FD_READ;
|
||||||
|
osmo_fd_register(&c->ofd);
|
||||||
|
/* reset rx buffer */
|
||||||
|
c->rx_index = 0;
|
||||||
}
|
}
|
||||||
c->next = conn_list;
|
|
||||||
conn_list = c;
|
|
||||||
c->socket = rc;
|
|
||||||
/* set nonblocking io */
|
|
||||||
flags = fcntl(c->socket, F_GETFL);
|
|
||||||
flags |= O_NONBLOCK;
|
|
||||||
fcntl(c->socket, F_SETFL, flags);
|
|
||||||
/* reset rx buffer */
|
|
||||||
c->rx_index = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rx_channel_info(int socket, int card, int port, int channel, uint16_t orig_rtp_port, int can_bridge);
|
static void rx_channel_info(int socket, int card, int port, int channel, uint16_t orig_rtp_port, int can_bridge);
|
||||||
|
|
||||||
/* close server socket and remove all channels that are associated with it */
|
/* close server socket and remove all channels that are associated with it */
|
||||||
void close_server_connection(int socket)
|
void close_server_connection(struct osmo_fd *ofd)
|
||||||
{
|
{
|
||||||
struct channel *c;
|
struct channel *c;
|
||||||
|
|
||||||
|
@ -278,7 +287,7 @@ void close_server_connection(int socket)
|
||||||
do {
|
do {
|
||||||
c = channel_list;
|
c = channel_list;
|
||||||
while (c) {
|
while (c) {
|
||||||
if (c->socket == socket)
|
if (c->socket == ofd->fd)
|
||||||
break;
|
break;
|
||||||
c = c->next;
|
c = c->next;
|
||||||
}
|
}
|
||||||
|
@ -288,36 +297,41 @@ void close_server_connection(int socket)
|
||||||
}
|
}
|
||||||
} while (c);
|
} while (c);
|
||||||
|
|
||||||
close(socket);
|
osmo_fd_unregister(ofd);
|
||||||
|
close(ofd->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read message from server socket */
|
/* read message from server socket */
|
||||||
static void read_server_socket(struct conn *c)
|
static int bridge_socket_conn_cb(struct osmo_fd *ofd, unsigned int when)
|
||||||
{
|
{
|
||||||
|
struct conn *c = ofd->data;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* read message until complete */
|
if ((when & OSMO_FD_READ)) {
|
||||||
rc = recv(c->socket, ((uint8_t *)&c->rx_msg) + c->rx_index, sizeof(c->rx_msg) - c->rx_index, 0);
|
rc = recv(c->ofd.fd, ((uint8_t *)&c->rx_msg) + c->rx_index, sizeof(c->rx_msg) - c->rx_index, 0);
|
||||||
if (rc > 0) {
|
if (rc > 0) {
|
||||||
c->rx_index += rc;
|
c->rx_index += rc;
|
||||||
if (c->rx_index == sizeof(c->rx_msg)) {
|
if (c->rx_index == sizeof(c->rx_msg)) {
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "Message from bridge socket client.\n");
|
PDEBUG(DISDN, DEBUG_DEBUG, "Message from bridge socket client.\n");
|
||||||
/* different version ? */
|
/* different version ? */
|
||||||
if (c->rx_msg.version != SOCKET_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");
|
PDEBUG(DISDN, DEBUG_ERROR, "Bridge client uses different version than bridge server. Please update all applications to use same server version\n");
|
||||||
return;
|
return 0;
|
||||||
|
}
|
||||||
|
/* process message and reset buffer index */
|
||||||
|
rx_channel_info(c->ofd.fd, c->rx_msg.card, c->rx_msg.port, c->rx_msg.channel, c->rx_msg.orig_rtp_port, c->rx_msg.can_bridge);
|
||||||
|
c->rx_index = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
/* process message and reset buffer index */
|
} else if (rc == 0 || errno != EAGAIN) {
|
||||||
rx_channel_info(c->socket, c->rx_msg.card, c->rx_msg.port, c->rx_msg.channel, c->rx_msg.orig_rtp_port, c->rx_msg.can_bridge);
|
PDEBUG(DISDN, DEBUG_DEBUG, "Close from bridge socket client.\n");
|
||||||
c->rx_index = 0;
|
close_server_connection(&c->ofd);
|
||||||
return;
|
/* destroy connection */
|
||||||
|
free_connection(c);
|
||||||
}
|
}
|
||||||
} else if (rc == 0 || errno != EAGAIN) {
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "Close from bridge socket client.\n");
|
|
||||||
close_server_connection(c->socket);
|
|
||||||
/* destroy connection */
|
|
||||||
free_connection(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sighandler(int sigset)
|
static void sighandler(int sigset)
|
||||||
|
@ -325,11 +339,34 @@ static void sighandler(int sigset)
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "Signal %d received.\n", sigset);
|
PDEBUG(DISDN, DEBUG_DEBUG, "Signal %d received.\n", sigset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
quit = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
timer_start(&server_timer, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void server_show_timeout(void __attribute__((unused)) *data)
|
||||||
|
{
|
||||||
|
struct channel *ch = channel_list;
|
||||||
|
|
||||||
|
if (ch)
|
||||||
|
printf("Connections:\n");
|
||||||
|
while (ch) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/* open socket, wait for connections and read incoming messages */
|
/* open socket, wait for connections and read incoming messages */
|
||||||
void bridge_socket_server_child(int slots, int daemon)
|
void bridge_socket_server_child(int slots, int daemon)
|
||||||
{
|
{
|
||||||
struct conn *c, *c2;
|
|
||||||
int count_ms = 0, delay_ms = 10;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
num_slots = slots;
|
num_slots = slots;
|
||||||
|
@ -349,43 +386,27 @@ void bridge_socket_server_child(int slots, int daemon)
|
||||||
signal(SIGPIPE, sighandler);
|
signal(SIGPIPE, sighandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(42) {
|
if (daemon) {
|
||||||
listen_server_socket();
|
timer_init(&server_timer, server_exit_timeout, NULL);
|
||||||
c = conn_list;
|
timer_start(&server_timer, 0.3);
|
||||||
if (daemon) {
|
} else {
|
||||||
/* timeout after some time without a connection */
|
timer_init(&server_timer, server_show_timeout, NULL);
|
||||||
if (!c) {
|
timer_start(&server_timer, 1.0);
|
||||||
count_ms += delay_ms;
|
|
||||||
if (count_ms >= 300) {
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "All clients gone, exitting.\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* show all existing channels */
|
|
||||||
count_ms += delay_ms;
|
|
||||||
if (count_ms >= 1000) {
|
|
||||||
struct channel *ch = channel_list;
|
|
||||||
if (ch)
|
|
||||||
printf("Connections:\n");
|
|
||||||
while (ch) {
|
|
||||||
printf("Card=%d Port=%d Channel=%d Bridge=%d\n", ch->card, ch->port, ch->channel, ch->pcm_bridge);
|
|
||||||
ch = ch->next;
|
|
||||||
}
|
|
||||||
count_ms = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (c) {
|
|
||||||
c2 = c->next;
|
|
||||||
read_server_socket(c);
|
|
||||||
c = c2;
|
|
||||||
}
|
|
||||||
usleep(delay_ms * 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while(!quit) {
|
||||||
|
double timeout;
|
||||||
|
|
||||||
|
timeout = process_timer();
|
||||||
|
osmo_fd_select(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_exit(&server_timer);
|
||||||
|
|
||||||
free_all_channels();
|
free_all_channels();
|
||||||
free_all_connections();
|
free_all_connections();
|
||||||
close(server_socket);
|
osmo_fd_unregister(&server_ofd);
|
||||||
|
close(server_ofd.fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create socket server thread and return 0 on success, return -errno on failure */
|
/* create socket server thread and return 0 on success, return -errno on failure */
|
||||||
|
@ -599,15 +620,16 @@ void tx_bridge_order(int socket, int card, int port, int channel, int pcm_bridge
|
||||||
* client
|
* client
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int client_socket = -1;
|
static struct osmo_fd client_ofd = { .fd = -1 };
|
||||||
int client_rx_index = 0;
|
int client_rx_index = 0;
|
||||||
struct msg_bridge_order client_rx_msg;
|
struct msg_bridge_order client_rx_msg;
|
||||||
|
|
||||||
|
static int bridge_socket_client_cb(struct osmo_fd *ofd, unsigned int when);
|
||||||
|
|
||||||
/* function to open the client socket */
|
/* function to open the client socket */
|
||||||
int bridge_socket_client(void)
|
int bridge_socket_client(isdn_t *isdn_ep)
|
||||||
{
|
{
|
||||||
struct sockaddr_un sock_address;
|
struct sockaddr_un sock_address;
|
||||||
int flags;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
memset(&sock_address, 0, sizeof(sock_address));
|
memset(&sock_address, 0, sizeof(sock_address));
|
||||||
|
@ -619,21 +641,21 @@ int bridge_socket_client(void)
|
||||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to create UNIX socket.\n");
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to create UNIX socket.\n");
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
client_socket = rc;
|
client_ofd.fd = rc;
|
||||||
|
client_ofd.cb = bridge_socket_client_cb;
|
||||||
|
client_ofd.data = isdn_ep;
|
||||||
|
client_ofd.when = OSMO_FD_READ;
|
||||||
|
osmo_fd_register(&client_ofd);
|
||||||
|
|
||||||
rc = connect(client_socket, (struct sockaddr *)(&sock_address), sizeof(struct sockaddr_un));
|
rc = connect(client_ofd.fd, (struct sockaddr *)(&sock_address), sizeof(struct sockaddr_un));
|
||||||
if (rc < 0) {
|
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));
|
PDEBUG(DISDN, DEBUG_DEBUG, "Failed to connect to UNIX socket with path '%s' (errno = %d (%s)).\n", SOCKET_NAME, errno, strerror(errno));
|
||||||
close(client_socket);
|
osmo_fd_unregister(&client_ofd);
|
||||||
client_socket = 0;
|
close(client_ofd.fd);
|
||||||
|
client_ofd.fd = -1;
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set nonblocking io */
|
|
||||||
flags = fcntl(client_socket, F_GETFL);
|
|
||||||
flags |= O_NONBLOCK;
|
|
||||||
fcntl(client_socket, F_SETFL, flags);
|
|
||||||
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "Created bridging socket client.\n");
|
PDEBUG(DISDN, DEBUG_DEBUG, "Created bridging socket client.\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -642,38 +664,37 @@ int bridge_socket_client(void)
|
||||||
void rx_bridge_order(isdn_t *isdn_ep, int card, int port, int channel, int pcm_bridge, int rx_slot, int tx_slot, int rx_bank, int tx_bank);
|
void rx_bridge_order(isdn_t *isdn_ep, int card, int port, int channel, int pcm_bridge, int rx_slot, int tx_slot, int rx_bank, int tx_bank);
|
||||||
|
|
||||||
/* read message from client socket */
|
/* read message from client socket */
|
||||||
void bridge_socket_client_work(isdn_t *isdn_ep)
|
static int bridge_socket_client_cb(struct osmo_fd *ofd, unsigned int when)
|
||||||
{
|
{
|
||||||
|
isdn_t *isdn_ep = ofd->data;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
again:
|
if ((when & OSMO_FD_READ)) {
|
||||||
/* no client */
|
/* read message until complete */
|
||||||
if (client_socket <= 0)
|
rc = recv(client_ofd.fd, ((uint8_t *)&client_rx_msg) + client_rx_index, sizeof(client_rx_msg) - client_rx_index, 0);
|
||||||
return;
|
if (rc > 0) {
|
||||||
|
client_rx_index += rc;
|
||||||
/* read message until complete */
|
if (client_rx_index == sizeof(client_rx_msg)) {
|
||||||
rc = recv(client_socket, ((uint8_t *)&client_rx_msg) + client_rx_index, sizeof(client_rx_msg) - client_rx_index, 0);
|
PDEBUG(DISDN, DEBUG_DEBUG, "Message from bridge socket server.\n");
|
||||||
if (rc > 0) {
|
/* different version ? */
|
||||||
client_rx_index += rc;
|
if (client_rx_msg.version != SOCKET_VERSION) {
|
||||||
if (client_rx_index == sizeof(client_rx_msg)) {
|
PDEBUG(DISDN, DEBUG_ERROR, "Bridge server uses different version than bridge client. Please update all applications to use same server version\n");
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "Message from bridge socket server.\n");
|
return 0;
|
||||||
/* different version ? */
|
}
|
||||||
if (client_rx_msg.version != SOCKET_VERSION) {
|
/* process message and reset buffer index */
|
||||||
PDEBUG(DISDN, DEBUG_ERROR, "Bridge server uses different version than bridge client. Please update all applications to use same server version\n");
|
rx_bridge_order(isdn_ep, client_rx_msg.card, client_rx_msg.port, client_rx_msg.channel, client_rx_msg.pcm_bridge, client_rx_msg.rx_slot, client_rx_msg.tx_slot, client_rx_msg.rx_bank, client_rx_msg.tx_bank);
|
||||||
return;
|
client_rx_index = 0;
|
||||||
}
|
}
|
||||||
/* process message and reset buffer index */
|
} else if (rc == 0 || errno != EAGAIN) {
|
||||||
rx_bridge_order(isdn_ep, client_rx_msg.card, client_rx_msg.port, client_rx_msg.channel, client_rx_msg.pcm_bridge, client_rx_msg.rx_slot, client_rx_msg.tx_slot, client_rx_msg.rx_bank, client_rx_msg.tx_bank);
|
PDEBUG(DISDN, DEBUG_DEBUG, "Close from bridge socket client.\n");
|
||||||
client_rx_index = 0;
|
osmo_fd_unregister(&client_ofd);
|
||||||
goto again;
|
close(client_ofd.fd);
|
||||||
|
client_ofd.fd = -1;
|
||||||
}
|
}
|
||||||
} else if (rc == 0 || errno != EAGAIN) {
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "Close from bridge socket client.\n");
|
|
||||||
close(client_socket);
|
|
||||||
client_socket = -1;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* check if ip address is one of the local interfaces */
|
/* check if ip address is one of the local interfaces */
|
||||||
int check_local_address(sa_family_t family, struct sockaddr *addr)
|
int check_local_address(sa_family_t family, struct sockaddr *addr)
|
||||||
|
@ -758,7 +779,7 @@ void bridge_socket_client_update(call_t *call, int enable)
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* no client */
|
/* no client */
|
||||||
if (client_socket <= 0)
|
if (client_ofd.fd <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PDEBUG(DISDN, DEBUG_INFO, "We got called with enable=%d\n", enable);
|
PDEBUG(DISDN, DEBUG_INFO, "We got called with enable=%d\n", enable);
|
||||||
|
@ -850,7 +871,7 @@ send:
|
||||||
else
|
else
|
||||||
orig_rtp_port = media->description.port_remote;
|
orig_rtp_port = media->description.port_remote;
|
||||||
|
|
||||||
tx_channel_info(client_socket, call->isdn_ep->bridge_cardnum, call->isdn_ep->bridge_portnum, call->b_channel, orig_rtp_port, can_bridge);
|
tx_channel_info(client_ofd.fd, call->isdn_ep->bridge_cardnum, call->isdn_ep->bridge_portnum, call->b_channel, orig_rtp_port, can_bridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tx_channel_info(int socket, int card, int port, int channel, uint16_t orig_rtp_port, int can_bridge)
|
static void tx_channel_info(int socket, int card, int port, int channel, uint16_t orig_rtp_port, int can_bridge)
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
int brigde_socket_server(int slots);
|
int brigde_socket_server(int slots);
|
||||||
void bridge_socket_server_child(int slots, int daemon);
|
void bridge_socket_server_child(int slots, int daemon);
|
||||||
|
|
||||||
int bridge_socket_client(void);
|
int bridge_socket_client(isdn_t *isdn_ep);
|
||||||
void bridge_socket_client_work(isdn_t *isdn_ep);
|
|
||||||
void bridge_socket_client_update(call_t *call, int enable);
|
void bridge_socket_client_update(call_t *call, int enable);
|
||||||
|
|
||||||
|
|
|
@ -955,6 +955,9 @@ void hold_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
|
||||||
/* reset jitter buffer, to ignore packets coming from remote */
|
/* reset jitter buffer, to ignore packets coming from remote */
|
||||||
jitter_reset(&call->tx_dejitter);
|
jitter_reset(&call->tx_dejitter);
|
||||||
|
|
||||||
|
/* generate hold tone, using local clock */
|
||||||
|
enable_hold_clock(call->isdn_ep);
|
||||||
|
|
||||||
/* acknowledge hold */
|
/* acknowledge hold */
|
||||||
PDEBUG(DDSS1, DEBUG_INFO, "HOLD-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
|
PDEBUG(DDSS1, DEBUG_INFO, "HOLD-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
|
||||||
l3m = create_l3msg();
|
l3m = create_l3msg();
|
||||||
|
@ -1078,6 +1081,9 @@ void suspend_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
|
||||||
/* deactivate bchannel */
|
/* deactivate bchannel */
|
||||||
drop_bchannel(call);
|
drop_bchannel(call);
|
||||||
|
|
||||||
|
/* generate hold tone, using local clock */
|
||||||
|
enable_hold_clock(call->isdn_ep);
|
||||||
|
|
||||||
/* sending SUSPEND_ACKNOWLEDGE */
|
/* sending SUSPEND_ACKNOWLEDGE */
|
||||||
PDEBUG(DDSS1, DEBUG_INFO, "SUSPEND-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
|
PDEBUG(DDSS1, DEBUG_INFO, "SUSPEND-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
|
||||||
l3m = create_l3msg();
|
l3m = create_l3msg();
|
||||||
|
|
364
src/isdn/isdn.c
364
src/isdn/isdn.c
|
@ -671,11 +671,15 @@ void isdn_destroy(isdn_t *isdn_ep)
|
||||||
|
|
||||||
timer_exit(&isdn_ep->l2establish_timer);
|
timer_exit(&isdn_ep->l2establish_timer);
|
||||||
|
|
||||||
|
timer_exit(&isdn_ep->clock_timer);
|
||||||
|
|
||||||
free(isdn_ep);
|
free(isdn_ep);
|
||||||
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "ISDN instance destroyed\n");
|
PDEBUG(DISDN, DEBUG_DEBUG, "ISDN instance destroyed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void clock_timeout(void *data);
|
||||||
|
|
||||||
/* initialization and configuration to isdn interface instance */
|
/* initialization and configuration to isdn interface instance */
|
||||||
int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int local_tones, int serving_location)
|
int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int local_tones, int serving_location)
|
||||||
{
|
{
|
||||||
|
@ -875,18 +879,19 @@ static void im_control(int sock, uint32_t op, uint32_t channel, uint32_t p1, uin
|
||||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send IMCTRLREQ to socket %d (errno=%d:%s)\n", sock, errno, strerror(errno));
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send IMCTRLREQ to socket %d (errno=%d:%s)\n", sock, errno, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bchannel_kernel_sock_receive_cb(struct osmo_fd *ofd, unsigned int when);
|
||||||
|
|
||||||
/* create B-channel stack */
|
/* create B-channel stack */
|
||||||
static int bchannel_create(isdn_t *isdn_ep, int index)
|
static int bchannel_create(isdn_t *isdn_ep, int index)
|
||||||
{
|
{
|
||||||
int channel = index + 1 + (index >= 15);
|
int channel = index + 1 + (index >= 15);
|
||||||
struct sockaddr_mISDN addr;
|
struct sockaddr_mISDN addr;
|
||||||
int flags;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
|
||||||
if (isdn_ep->l2sock) {
|
if (isdn_ep->l2sock) {
|
||||||
if (isdn_ep->b_sock[index] > 0) {
|
if (isdn_ep->b_sock[index].ofd.fd > 0) {
|
||||||
PDEBUG(DISDN, DEBUG_ERROR, "Socket already created for index %d\n", index);
|
PDEBUG(DISDN, DEBUG_ERROR, "Socket already created for index %d\n", index);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
@ -900,26 +905,31 @@ static int bchannel_create(isdn_t *isdn_ep, int index)
|
||||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", index);
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", index);
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
isdn_ep->b_sock[index] = rc;
|
isdn_ep->b_sock[index].ofd.fd = rc;
|
||||||
|
|
||||||
/* set nonblocking io */
|
/* register */
|
||||||
flags = fcntl(isdn_ep->b_sock[index], F_GETFL);
|
isdn_ep->b_sock[index].isdn_ep = isdn_ep;
|
||||||
flags |= O_NONBLOCK;
|
isdn_ep->b_sock[index].index = index;
|
||||||
fcntl(isdn_ep->b_sock[index], F_SETFL, flags);
|
isdn_ep->b_sock[index].ofd.cb = bchannel_kernel_sock_receive_cb;
|
||||||
|
isdn_ep->b_sock[index].ofd.data = &isdn_ep->b_sock[index];
|
||||||
|
isdn_ep->b_sock[index].ofd.when = OSMO_FD_READ;
|
||||||
|
osmo_fd_register(&isdn_ep->b_sock[index].ofd);
|
||||||
|
|
||||||
/* bind socket to bchannel */
|
/* bind socket to bchannel */
|
||||||
addr.family = AF_ISDN;
|
addr.family = AF_ISDN;
|
||||||
addr.dev = isdn_ep->portnum;
|
addr.dev = isdn_ep->portnum;
|
||||||
addr.channel = channel;
|
addr.channel = channel;
|
||||||
rc = bind(isdn_ep->b_sock[index], (struct sockaddr *)&addr, sizeof(addr));
|
rc = bind(isdn_ep->b_sock[index].ofd.fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to bind bchannel-socket for index %d with mISDN-DSP layer (errno=%d). Did you load mISDN_dsp.ko?\n", index, errno);
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to bind bchannel-socket for index %d with mISDN-DSP layer (errno=%d). Did you load mISDN_dsp.ko?\n", index, errno);
|
||||||
close(isdn_ep->b_sock[index]);
|
/* unregister and close */
|
||||||
|
osmo_fd_unregister(&isdn_ep->b_sock[index].ofd);
|
||||||
|
close(isdn_ep->b_sock[index].ofd.fd);
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "created socket #%d for B-channel %d\n", isdn_ep->b_sock[index], channel);
|
PDEBUG(DISDN, DEBUG_DEBUG, "created socket #%d for B-channel %d\n", isdn_ep->b_sock[index].ofd.fd, channel);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -932,14 +942,14 @@ static void bchannel_activate(isdn_t *isdn_ep, int index, int activate, int time
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (isdn_ep->l2sock) {
|
if (isdn_ep->l2sock) {
|
||||||
if (isdn_ep->b_sock[index] <= 0)
|
if (isdn_ep->b_sock[index].ofd.fd <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
act.prim = (activate) ? PH_ACTIVATE_REQ : PH_DEACTIVATE_REQ;
|
act.prim = (activate) ? PH_ACTIVATE_REQ : PH_DEACTIVATE_REQ;
|
||||||
act.id = 0;
|
act.id = 0;
|
||||||
rc = sendto(isdn_ep->b_sock[index], &act, MISDN_HEADER_LEN, 0, NULL, 0);
|
rc = sendto(isdn_ep->b_sock[index].ofd.fd, &act, MISDN_HEADER_LEN, 0, NULL, 0);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send to socket #%d, of B-channel %d\n", isdn_ep->b_sock[index], channel);
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send to socket #%d, of B-channel %d\n", isdn_ep->b_sock[index].ofd.fd, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isdn_ep->l2inst) {
|
if (isdn_ep->l2inst) {
|
||||||
|
@ -964,10 +974,10 @@ static void bchannel_configure(isdn_t *isdn_ep, int index)
|
||||||
call_t *call;
|
call_t *call;
|
||||||
int handle;
|
int handle;
|
||||||
|
|
||||||
if (isdn_ep->b_sock[index] <= 0)
|
if (isdn_ep->b_sock[index].ofd.fd <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
handle = isdn_ep->b_sock[index];
|
handle = isdn_ep->b_sock[index].ofd.fd;
|
||||||
call = isdn_ep->b_call[index];
|
call = isdn_ep->b_call[index];
|
||||||
|
|
||||||
/* set PCM bridge features */
|
/* set PCM bridge features */
|
||||||
|
@ -1007,13 +1017,15 @@ static void bchannel_destroy(isdn_t *isdn_ep, int index)
|
||||||
int channel = index + 1 + (index >= 15);
|
int channel = index + 1 + (index >= 15);
|
||||||
|
|
||||||
if (isdn_ep->l2sock) {
|
if (isdn_ep->l2sock) {
|
||||||
if (isdn_ep->b_sock[index] <= 0)
|
if (isdn_ep->b_sock[index].ofd.fd <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "destroyed socket #%d for B-channel %d\n", isdn_ep->b_sock[index], channel);
|
PDEBUG(DISDN, DEBUG_DEBUG, "destroyed socket #%d for B-channel %d\n", isdn_ep->b_sock[index].ofd.fd, channel);
|
||||||
|
|
||||||
close(isdn_ep->b_sock[index]);
|
/* unregister and close */
|
||||||
isdn_ep->b_sock[index] = 0;
|
osmo_fd_unregister(&isdn_ep->b_sock[index].ofd);
|
||||||
|
close(isdn_ep->b_sock[index].ofd.fd);
|
||||||
|
isdn_ep->b_sock[index].ofd.fd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isdn_ep->l2inst) {
|
if (isdn_ep->l2inst) {
|
||||||
|
@ -1226,18 +1238,26 @@ static void bchannel_rx_tx(isdn_t *isdn_ep, int index, struct mISDNhead *hh, uns
|
||||||
static void bchannel_confirm(isdn_t *isdn_ep, int index);
|
static void bchannel_confirm(isdn_t *isdn_ep, int index);
|
||||||
|
|
||||||
/* handle frames from B-channel (kernel socket) */
|
/* handle frames from B-channel (kernel socket) */
|
||||||
static int bchannel_kernel_sock_receive(isdn_t *isdn_ep, int index)
|
static int bchannel_kernel_sock_receive_cb(struct osmo_fd *ofd, unsigned int when)
|
||||||
{
|
{
|
||||||
|
struct isdn_b_sock *b_sock = ofd->data;
|
||||||
|
int index = b_sock->index;
|
||||||
|
isdn_t *isdn_ep = b_sock->isdn_ep;
|
||||||
int channel = index + 1 + (index >= 15);
|
int channel = index + 1 + (index >= 15);
|
||||||
unsigned char buffer[2048+MISDN_HEADER_LEN];
|
unsigned char buffer[2048+MISDN_HEADER_LEN];
|
||||||
struct mISDNhead *hh = (struct mISDNhead *)buffer;
|
struct mISDNhead *hh = (struct mISDNhead *)buffer;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = recv(isdn_ep->b_sock[index], buffer, sizeof(buffer), 0);
|
if (!(when & OSMO_FD_READ)) {
|
||||||
|
PDEBUG(DISDN, DEBUG_ERROR, "this should never happen!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = recv(ofd->fd, buffer, sizeof(buffer), 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN)
|
||||||
return 0;
|
return 0;
|
||||||
PDEBUG(DISDN, DEBUG_ERROR, "read error B-channel data (socket #%d errno=%d:%s)\n", isdn_ep->b_sock[index], errno, strerror(errno));
|
PDEBUG(DISDN, DEBUG_ERROR, "read error B-channel data (socket #%d errno=%d:%s)\n", ofd->fd, errno, strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (rc < (int)MISDN_HEADER_LEN) {
|
if (rc < (int)MISDN_HEADER_LEN) {
|
||||||
|
@ -1318,9 +1338,9 @@ void bchannel_ph_sock_receive(void *priv, int channel, uint8_t prim, uint8_t *da
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void b_timer_timeout(struct timer *timer)
|
static void b_timer_timeout(void *data)
|
||||||
{
|
{
|
||||||
struct b_timer_inst *ti = timer->priv;
|
struct b_timer_inst *ti = data;
|
||||||
|
|
||||||
bchannel_event(ti->isdn_ep, ti->index, B_EVENT_TIMEOUT);
|
bchannel_event(ti->isdn_ep, ti->index, B_EVENT_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
@ -1618,9 +1638,9 @@ static void bchannel_rx_tx(isdn_t *isdn_ep, int index, struct mISDNhead *hh, uns
|
||||||
if (call->isdn_ep->ph_socket)
|
if (call->isdn_ep->ph_socket)
|
||||||
ph_socket_tx_msg(call->isdn_ep->ph_socket, call->b_channel, PH_PRIM_DATA_REQ, buf + MISDN_HEADER_LEN, offset + len);
|
ph_socket_tx_msg(call->isdn_ep->ph_socket, call->b_channel, PH_PRIM_DATA_REQ, buf + MISDN_HEADER_LEN, offset + len);
|
||||||
else
|
else
|
||||||
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + offset + len, 0);
|
rc = send(call->isdn_ep->b_sock[call->b_index].ofd.fd, buf, MISDN_HEADER_LEN + offset + len, 0);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
PDEBUG(DISDN, DEBUG_ERROR, "Write error B-channel data (socket #%d errno=%d:%s)\n", call->isdn_ep->b_sock[call->b_index], errno, strerror(errno));
|
PDEBUG(DISDN, DEBUG_ERROR, "Write error B-channel data (socket #%d errno=%d:%s)\n", call->isdn_ep->b_sock[call->b_index].ofd.fd, errno, strerror(errno));
|
||||||
else
|
else
|
||||||
call->b_transmitting = 1;
|
call->b_transmitting = 1;
|
||||||
}
|
}
|
||||||
|
@ -1643,18 +1663,6 @@ static void bchannel_confirm(isdn_t *isdn_ep, int index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void isdn_rtp_work(isdn_t *isdn_ep)
|
|
||||||
{
|
|
||||||
call_t *call;
|
|
||||||
|
|
||||||
call = isdn_ep->call_list;
|
|
||||||
while (call) {
|
|
||||||
if (call->cc_session)
|
|
||||||
osmo_cc_session_handle(call->cc_session, call);
|
|
||||||
call = call->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send audio from RTP to B-channel's jitter buffer */
|
/* send audio from RTP to B-channel's jitter buffer */
|
||||||
void rtp_receive(struct osmo_cc_session_codec *codec, uint8_t __attribute__((unused)) marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len)
|
void rtp_receive(struct osmo_cc_session_codec *codec, uint8_t __attribute__((unused)) marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len)
|
||||||
{
|
{
|
||||||
|
@ -1716,6 +1724,10 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
|
||||||
mqueue_tail(&isdn_ep->upqueue, mb);
|
mqueue_tail(&isdn_ep->upqueue, mb);
|
||||||
pthread_mutex_unlock(&isdn_ep->upqueue_lock);
|
pthread_mutex_unlock(&isdn_ep->upqueue_lock);
|
||||||
|
|
||||||
|
/* wake main thread */
|
||||||
|
char wakeup = 0;
|
||||||
|
write(isdn_ep->upqueue_pipe[1], &wakeup, 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1745,7 +1757,8 @@ int mISDN_getportbyname(isdn_t *isdn_ep, int cnt, const char *portname)
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void l2establish_timeout(struct timer *timer);
|
static void l2establish_timeout(void *data);
|
||||||
|
static int isdn_upqueue_cb(struct osmo_fd *ofd, unsigned int what);
|
||||||
|
|
||||||
/* open mISDN port */
|
/* open mISDN port */
|
||||||
int isdn_open(isdn_t *isdn_ep)
|
int isdn_open(isdn_t *isdn_ep)
|
||||||
|
@ -1766,6 +1779,16 @@ int isdn_open(isdn_t *isdn_ep)
|
||||||
/* queue must be initializes, because l3-thread may send messages during open_layer3() */
|
/* queue must be initializes, because l3-thread may send messages during open_layer3() */
|
||||||
mqueue_init(&isdn_ep->upqueue);
|
mqueue_init(&isdn_ep->upqueue);
|
||||||
isdn_ep->upqueue_initialized = 1;
|
isdn_ep->upqueue_initialized = 1;
|
||||||
|
rc = pipe(isdn_ep->upqueue_pipe);
|
||||||
|
if (rc < 0) {
|
||||||
|
PDEBUG(DISDN, DEBUG_ERROR, "Failed to create pipe errno=%d:%s. (Please fix!)\n", errno, strerror(errno));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
isdn_ep->upqueue_ofd.fd = isdn_ep->upqueue_pipe[0];
|
||||||
|
isdn_ep->upqueue_ofd.cb = isdn_upqueue_cb;
|
||||||
|
isdn_ep->upqueue_ofd.data = isdn_ep;
|
||||||
|
isdn_ep->upqueue_ofd.when = OSMO_FD_READ;
|
||||||
|
osmo_fd_register(&isdn_ep->upqueue_ofd);
|
||||||
|
|
||||||
/* port number given ? */
|
/* port number given ? */
|
||||||
for (i = 0; i < (int)strlen(portname); i++){
|
for (i = 0; i < (int)strlen(portname); i++){
|
||||||
|
@ -1878,6 +1901,8 @@ int isdn_open(isdn_t *isdn_ep)
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timer_init(&isdn_ep->clock_timer, clock_timeout, isdn_ep);
|
||||||
|
|
||||||
timer_init(&isdn_ep->l2establish_timer, l2establish_timeout, isdn_ep);
|
timer_init(&isdn_ep->l2establish_timer, l2establish_timeout, isdn_ep);
|
||||||
|
|
||||||
isdn_ep->l1link = -1;
|
isdn_ep->l1link = -1;
|
||||||
|
@ -1975,7 +2000,7 @@ void isdn_close(isdn_t *isdn_ep)
|
||||||
|
|
||||||
/* free bchannels */
|
/* free bchannels */
|
||||||
for (i = 0; i < isdn_ep->b_num; i++) {
|
for (i = 0; i < isdn_ep->b_num; i++) {
|
||||||
if (isdn_ep->b_sock[i] > 0) {
|
if (isdn_ep->b_sock[i].ofd.fd > 0) {
|
||||||
bchannel_destroy(isdn_ep, i);
|
bchannel_destroy(isdn_ep, i);
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "freeing %s port %s bchannel (index %d).\n", (isdn_ep->ntmode) ? "NT" : "TE", isdn_ep->portname, i);
|
PDEBUG(DISDN, DEBUG_DEBUG, "freeing %s port %s bchannel (index %d).\n", (isdn_ep->ntmode) ? "NT" : "TE", isdn_ep->portname, i);
|
||||||
}
|
}
|
||||||
|
@ -1988,9 +2013,18 @@ void isdn_close(isdn_t *isdn_ep)
|
||||||
close_layer3(isdn_ep->ml3);
|
close_layer3(isdn_ep->ml3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* purge upqueue */
|
/* purge and remove upqueue */
|
||||||
if (isdn_ep->upqueue_initialized)
|
if (isdn_ep->upqueue_initialized)
|
||||||
mqueue_purge(&isdn_ep->upqueue);
|
mqueue_purge(&isdn_ep->upqueue);
|
||||||
|
if (isdn_ep->upqueue_pipe[0] > 0) {
|
||||||
|
osmo_fd_unregister(&isdn_ep->upqueue_ofd);
|
||||||
|
close(isdn_ep->upqueue_pipe[0]);
|
||||||
|
isdn_ep->upqueue_pipe[0] = 0;
|
||||||
|
}
|
||||||
|
if (isdn_ep->upqueue_pipe[1] > 0) {
|
||||||
|
close(isdn_ep->upqueue_pipe[1]);
|
||||||
|
isdn_ep->upqueue_pipe[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (isdn_ep->portname) {
|
if (isdn_ep->portname) {
|
||||||
free(isdn_ep->portname);
|
free(isdn_ep->portname);
|
||||||
|
@ -2009,116 +2043,120 @@ void isdn_close(isdn_t *isdn_ep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* receive message from ISDN protocol stack (out of queue) */
|
/* receive message from ISDN protocol stack (out of the upqueue) */
|
||||||
int isdn_dchannel_work(isdn_t *isdn_ep)
|
static int isdn_upqueue_cb(struct osmo_fd *ofd, unsigned __attribute__((unused)) int what)
|
||||||
{
|
{
|
||||||
|
isdn_t *isdn_ep = ofd->data;
|
||||||
struct mbuffer *mb;
|
struct mbuffer *mb;
|
||||||
struct l3_msg *l3m;
|
struct l3_msg *l3m;
|
||||||
int w = 0;
|
|
||||||
|
|
||||||
|
char wakeup = 0;
|
||||||
|
read(ofd->fd, &wakeup, 1);
|
||||||
|
|
||||||
|
again:
|
||||||
/* handle queued up-messages (d-channel) */
|
/* handle queued up-messages (d-channel) */
|
||||||
pthread_mutex_lock(&isdn_ep->upqueue_lock);
|
pthread_mutex_lock(&isdn_ep->upqueue_lock);
|
||||||
mb = mdequeue(&isdn_ep->upqueue);
|
mb = mdequeue(&isdn_ep->upqueue);
|
||||||
pthread_mutex_unlock(&isdn_ep->upqueue_lock);
|
pthread_mutex_unlock(&isdn_ep->upqueue_lock);
|
||||||
if (mb) {
|
if (!mb)
|
||||||
w |= 1;
|
return 0;
|
||||||
l3m = &mb->l3;
|
|
||||||
switch(l3m->type) {
|
|
||||||
case MPH_ACTIVATE_IND:
|
|
||||||
if (isdn_ep->l1link != 1) {
|
|
||||||
PDEBUG(DISDN, DEBUG_INFO, "layer 1 becomes active\n");
|
|
||||||
isdn_ep->l1link = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MPH_DEACTIVATE_IND:
|
|
||||||
if (isdn_ep->l1link != 0) {
|
|
||||||
PDEBUG(DISDN, DEBUG_INFO, "layer 1 becomes inactive\n");
|
|
||||||
isdn_ep->l1link = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MPH_INFORMATION_IND:
|
l3m = &mb->l3;
|
||||||
switch (l3m->pid) {
|
switch(l3m->type) {
|
||||||
case L1_SIGNAL_LOS_ON:
|
case MPH_ACTIVATE_IND:
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "received LOS\n");
|
if (isdn_ep->l1link != 1) {
|
||||||
isdn_ep->los = 1;
|
PDEBUG(DISDN, DEBUG_INFO, "layer 1 becomes active\n");
|
||||||
break;
|
isdn_ep->l1link = 1;
|
||||||
case L1_SIGNAL_LOS_OFF:
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "LOS is gone\n");
|
|
||||||
isdn_ep->los = 0;
|
|
||||||
break;
|
|
||||||
case L1_SIGNAL_AIS_ON:
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "received AIS\n");
|
|
||||||
isdn_ep->ais = 1;
|
|
||||||
break;
|
|
||||||
case L1_SIGNAL_AIS_OFF:
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "AIS is gone\n");
|
|
||||||
isdn_ep->ais = 0;
|
|
||||||
break;
|
|
||||||
case L1_SIGNAL_RDI_ON:
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "received RDI\n");
|
|
||||||
isdn_ep->rdi = 1;
|
|
||||||
break;
|
|
||||||
case L1_SIGNAL_RDI_OFF:
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "RDI is gone\n");
|
|
||||||
isdn_ep->rdi = 0;
|
|
||||||
break;
|
|
||||||
case L1_SIGNAL_SLIP_TX:
|
|
||||||
isdn_ep->slip_tx++;
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "received TX slip #%d\n", isdn_ep->slip_tx);
|
|
||||||
break;
|
|
||||||
case L1_SIGNAL_SLIP_RX:
|
|
||||||
isdn_ep->slip_rx++;
|
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "received RX slip #%d\n", isdn_ep->slip_rx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MT_L2ESTABLISH:
|
|
||||||
PDEBUG(DISDN, DEBUG_INFO, "layer 2 becomes active (tei = %d)\n", l3m->pid);
|
|
||||||
isdn_ep->l2link = 1;
|
|
||||||
if (l3m->pid < 128)
|
|
||||||
isdn_ep->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
|
|
||||||
if ((!isdn_ep->ntmode || isdn_ep->ptp) && l3m->pid < 127) {
|
|
||||||
if (timer_running(&isdn_ep->l2establish_timer))
|
|
||||||
timer_stop(&isdn_ep->l2establish_timer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MT_L2RELEASE:
|
|
||||||
if (l3m->pid < 128)
|
|
||||||
isdn_ep->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
|
|
||||||
if (!timer_running(&isdn_ep->l2establish_timer)) {
|
|
||||||
PDEBUG(DISDN, DEBUG_INFO, "layer 2 becomes inactive (tei = %d)\n", l3m->pid);
|
|
||||||
/* down if not nt-ptmp */
|
|
||||||
if (!isdn_ep->ntmode || isdn_ep->ptp)
|
|
||||||
isdn_ep->l2link = 0;
|
|
||||||
}
|
|
||||||
if ((!isdn_ep->ntmode || isdn_ep->ptp) && l3m->pid < 127) {
|
|
||||||
if (!timer_running(&isdn_ep->l2establish_timer) && isdn_ep->l2hold) {
|
|
||||||
timer_start(&isdn_ep->l2establish_timer, 5.0); /* 5 seconds */
|
|
||||||
isdn_ep->ml3->to_layer3(isdn_ep->ml3, MT_L2ESTABLISH, 0, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/* l3-data is sent to DSS1 handling */
|
|
||||||
dss1_receive(isdn_ep, l3m->type, l3m->pid, l3m);
|
|
||||||
}
|
}
|
||||||
/* free message */
|
break;
|
||||||
free_l3_msg(l3m);
|
|
||||||
}
|
|
||||||
|
|
||||||
return w;
|
case MPH_DEACTIVATE_IND:
|
||||||
|
if (isdn_ep->l1link != 0) {
|
||||||
|
PDEBUG(DISDN, DEBUG_INFO, "layer 1 becomes inactive\n");
|
||||||
|
isdn_ep->l1link = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MPH_INFORMATION_IND:
|
||||||
|
switch (l3m->pid) {
|
||||||
|
case L1_SIGNAL_LOS_ON:
|
||||||
|
PDEBUG(DISDN, DEBUG_DEBUG, "received LOS\n");
|
||||||
|
isdn_ep->los = 1;
|
||||||
|
break;
|
||||||
|
case L1_SIGNAL_LOS_OFF:
|
||||||
|
PDEBUG(DISDN, DEBUG_DEBUG, "LOS is gone\n");
|
||||||
|
isdn_ep->los = 0;
|
||||||
|
break;
|
||||||
|
case L1_SIGNAL_AIS_ON:
|
||||||
|
PDEBUG(DISDN, DEBUG_DEBUG, "received AIS\n");
|
||||||
|
isdn_ep->ais = 1;
|
||||||
|
break;
|
||||||
|
case L1_SIGNAL_AIS_OFF:
|
||||||
|
PDEBUG(DISDN, DEBUG_DEBUG, "AIS is gone\n");
|
||||||
|
isdn_ep->ais = 0;
|
||||||
|
break;
|
||||||
|
case L1_SIGNAL_RDI_ON:
|
||||||
|
PDEBUG(DISDN, DEBUG_DEBUG, "received RDI\n");
|
||||||
|
isdn_ep->rdi = 1;
|
||||||
|
break;
|
||||||
|
case L1_SIGNAL_RDI_OFF:
|
||||||
|
PDEBUG(DISDN, DEBUG_DEBUG, "RDI is gone\n");
|
||||||
|
isdn_ep->rdi = 0;
|
||||||
|
break;
|
||||||
|
case L1_SIGNAL_SLIP_TX:
|
||||||
|
isdn_ep->slip_tx++;
|
||||||
|
PDEBUG(DISDN, DEBUG_DEBUG, "received TX slip #%d\n", isdn_ep->slip_tx);
|
||||||
|
break;
|
||||||
|
case L1_SIGNAL_SLIP_RX:
|
||||||
|
isdn_ep->slip_rx++;
|
||||||
|
PDEBUG(DISDN, DEBUG_DEBUG, "received RX slip #%d\n", isdn_ep->slip_rx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MT_L2ESTABLISH:
|
||||||
|
PDEBUG(DISDN, DEBUG_INFO, "layer 2 becomes active (tei = %d)\n", l3m->pid);
|
||||||
|
isdn_ep->l2link = 1;
|
||||||
|
if (l3m->pid < 128)
|
||||||
|
isdn_ep->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
|
||||||
|
if ((!isdn_ep->ntmode || isdn_ep->ptp) && l3m->pid < 127) {
|
||||||
|
if (timer_running(&isdn_ep->l2establish_timer))
|
||||||
|
timer_stop(&isdn_ep->l2establish_timer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MT_L2RELEASE:
|
||||||
|
if (l3m->pid < 128)
|
||||||
|
isdn_ep->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
|
||||||
|
if (!timer_running(&isdn_ep->l2establish_timer)) {
|
||||||
|
PDEBUG(DISDN, DEBUG_INFO, "layer 2 becomes inactive (tei = %d)\n", l3m->pid);
|
||||||
|
/* down if not nt-ptmp */
|
||||||
|
if (!isdn_ep->ntmode || isdn_ep->ptp)
|
||||||
|
isdn_ep->l2link = 0;
|
||||||
|
}
|
||||||
|
if ((!isdn_ep->ntmode || isdn_ep->ptp) && l3m->pid < 127) {
|
||||||
|
if (!timer_running(&isdn_ep->l2establish_timer) && isdn_ep->l2hold) {
|
||||||
|
timer_start(&isdn_ep->l2establish_timer, 5.0); /* 5 seconds */
|
||||||
|
isdn_ep->ml3->to_layer3(isdn_ep->ml3, MT_L2ESTABLISH, 0, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* l3-data is sent to DSS1 handling */
|
||||||
|
dss1_receive(isdn_ep, l3m->type, l3m->pid, l3m);
|
||||||
|
}
|
||||||
|
/* free message */
|
||||||
|
free_l3_msg(l3m);
|
||||||
|
|
||||||
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* l2 establish timer fires */
|
/* l2 establish timer fires */
|
||||||
static void l2establish_timeout(struct timer *timer)
|
static void l2establish_timeout(void *data)
|
||||||
{
|
{
|
||||||
isdn_t *isdn_ep = timer->priv;
|
isdn_t *isdn_ep = data;
|
||||||
|
|
||||||
if (isdn_ep->l2hold && (isdn_ep->ptp || !isdn_ep->ntmode)) {
|
if (isdn_ep->l2hold && (isdn_ep->ptp || !isdn_ep->ntmode)) {
|
||||||
PDEBUG(DISDN, DEBUG_DEBUG, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", isdn_ep->portnum);
|
PDEBUG(DISDN, DEBUG_DEBUG, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", isdn_ep->portnum);
|
||||||
|
@ -2127,25 +2165,20 @@ static void l2establish_timeout(struct timer *timer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void isdn_bchannel_work(isdn_t *isdn_ep)
|
/*
|
||||||
{
|
* local clock to generate hold tone
|
||||||
int w, i;
|
*/
|
||||||
|
|
||||||
for (i = 0; i < isdn_ep->b_num; i++) {
|
|
||||||
do {
|
|
||||||
if (isdn_ep->b_sock[i] > 0)
|
|
||||||
w = bchannel_kernel_sock_receive(isdn_ep, i);
|
|
||||||
else
|
|
||||||
w = 0;
|
|
||||||
} while (w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define COMFORT_NOISE (0.02 * SPEECH_LEVEL) /* audio level of comfort noise (relative to ISDN level) */
|
#define COMFORT_NOISE (0.02 * SPEECH_LEVEL) /* audio level of comfort noise (relative to ISDN level) */
|
||||||
|
#define CHUNK_DURATION 0.020
|
||||||
|
#define CHUNK_LENGTH 160
|
||||||
|
|
||||||
void hold_clock(isdn_t *isdn_ep, int len)
|
static void clock_timeout(void *data)
|
||||||
{
|
{
|
||||||
|
isdn_t *isdn_ep = data;
|
||||||
|
int len = CHUNK_LENGTH;
|
||||||
call_t *call;
|
call_t *call;
|
||||||
|
int any = 0;
|
||||||
|
|
||||||
call = isdn_ep->call_list;
|
call = isdn_ep->call_list;
|
||||||
while (call) {
|
while (call) {
|
||||||
|
@ -2165,7 +2198,40 @@ void hold_clock(isdn_t *isdn_ep, int len)
|
||||||
g711_encode_ulaw_flipped((uint8_t *)noise, len * 2, &data, &len, NULL);
|
g711_encode_ulaw_flipped((uint8_t *)noise, len * 2, &data, &len, NULL);
|
||||||
osmo_cc_rtp_send(call->codec, data, len, 0, 1, len, call);
|
osmo_cc_rtp_send(call->codec, data, len, 0, 1, len, call);
|
||||||
free(data);
|
free(data);
|
||||||
|
any = 1;
|
||||||
}
|
}
|
||||||
call = call->next;
|
call = call->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* restart clock if there is still any call that requires it */
|
||||||
|
if (any) {
|
||||||
|
double now;
|
||||||
|
|
||||||
|
/* restart timer to wait for next 20ms */
|
||||||
|
now = get_time();
|
||||||
|
/* if there is too much jitter or if last_time_clock is not set */
|
||||||
|
if (now - isdn_ep->last_time_clock >= 0.1)
|
||||||
|
isdn_ep->last_time_clock = now;
|
||||||
|
/* advance clock */
|
||||||
|
isdn_ep->last_time_clock += CHUNK_DURATION;
|
||||||
|
/* if there is too much jitter */
|
||||||
|
if (isdn_ep->last_time_clock < now)
|
||||||
|
isdn_ep->last_time_clock = now;
|
||||||
|
timer_start(&isdn_ep->clock_timer, isdn_ep->last_time_clock - now);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void enable_hold_clock(isdn_t *isdn_ep)
|
||||||
|
{
|
||||||
|
double now;
|
||||||
|
|
||||||
|
/* already running, so keep running without restart */
|
||||||
|
if (timer_running(&isdn_ep->clock_timer))
|
||||||
|
return;
|
||||||
|
/* start timer to wait for 20ms */
|
||||||
|
now = get_time();
|
||||||
|
isdn_ep->last_time_clock = now + CHUNK_DURATION;
|
||||||
|
timer_start(&isdn_ep->clock_timer, CHUNK_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include "../libtimer/timer.h"
|
#include "../libtimer/timer.h"
|
||||||
|
#include "../libselect/select.h"
|
||||||
#include "../libosmocc/endpoint.h"
|
#include "../libosmocc/endpoint.h"
|
||||||
#include "../libosmocc/helper.h"
|
#include "../libosmocc/helper.h"
|
||||||
#include "../libsample/sample.h"
|
#include "../libsample/sample.h"
|
||||||
|
@ -65,6 +66,14 @@ struct select_channel {
|
||||||
int channel;
|
int channel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct isdn;
|
||||||
|
|
||||||
|
struct isdn_b_sock {
|
||||||
|
int index;
|
||||||
|
struct isdn *isdn_ep;
|
||||||
|
struct osmo_fd ofd;
|
||||||
|
};
|
||||||
|
|
||||||
struct call_list;
|
struct call_list;
|
||||||
|
|
||||||
typedef struct isdn {
|
typedef struct isdn {
|
||||||
|
@ -98,6 +107,8 @@ typedef struct isdn {
|
||||||
pthread_mutex_t upqueue_lock;
|
pthread_mutex_t upqueue_lock;
|
||||||
struct mqueue upqueue;
|
struct mqueue upqueue;
|
||||||
int upqueue_initialized;
|
int upqueue_initialized;
|
||||||
|
int upqueue_pipe[2];
|
||||||
|
struct osmo_fd upqueue_ofd;
|
||||||
struct mlayer3 *ml3;
|
struct mlayer3 *ml3;
|
||||||
int los, ais, rdi, slip_rx, slip_tx;
|
int los, ais, rdi, slip_rx, slip_tx;
|
||||||
int l1link; /* current state */
|
int l1link; /* current state */
|
||||||
|
@ -107,7 +118,7 @@ typedef struct isdn {
|
||||||
int b_reserved;
|
int b_reserved;
|
||||||
int b_mode[128];
|
int b_mode[128];
|
||||||
int b_state[128];
|
int b_state[128];
|
||||||
int b_sock[128];
|
struct isdn_b_sock b_sock[128];
|
||||||
struct call_list *b_call[128];
|
struct call_list *b_call[128];
|
||||||
struct timer b_timer[128];
|
struct timer b_timer[128];
|
||||||
struct b_timer_inst b_timer_inst[128];
|
struct b_timer_inst b_timer_inst[128];
|
||||||
|
@ -119,6 +130,10 @@ typedef struct isdn {
|
||||||
int bridge_possible;
|
int bridge_possible;
|
||||||
int bridge_cardnum;
|
int bridge_cardnum;
|
||||||
int bridge_portnum;
|
int bridge_portnum;
|
||||||
|
|
||||||
|
/* clock for tone on hold */
|
||||||
|
struct timer clock_timer;
|
||||||
|
double last_time_clock;
|
||||||
} isdn_t;
|
} isdn_t;
|
||||||
|
|
||||||
typedef struct call_list {
|
typedef struct call_list {
|
||||||
|
@ -193,9 +208,6 @@ int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const cha
|
||||||
int isdn_open(isdn_t *isdn_ep);
|
int isdn_open(isdn_t *isdn_ep);
|
||||||
void isdn_close(isdn_t *isdn_ep);
|
void isdn_close(isdn_t *isdn_ep);
|
||||||
void isdn_add_msn(isdn_t *isdn_ep, const char *msn);
|
void isdn_add_msn(isdn_t *isdn_ep, const char *msn);
|
||||||
int isdn_dchannel_work(isdn_t *isdn_ep);
|
|
||||||
void isdn_bchannel_work(isdn_t *isdn_ep);
|
|
||||||
void isdn_rtp_work(isdn_t *isdn_ep);
|
|
||||||
|
|
||||||
/* call instance */
|
/* call instance */
|
||||||
call_t *call_create(isdn_t *isdn_ep, int direction, int channel, int exclusive, int mode);
|
call_t *call_create(isdn_t *isdn_ep, int direction, int channel, int exclusive, int mode);
|
||||||
|
@ -209,5 +221,5 @@ void bchannel_event(isdn_t *isdn_ep, int index, int event);
|
||||||
int seize_bchannel(call_t *call, int channel, int exclusive);
|
int seize_bchannel(call_t *call, int channel, int exclusive);
|
||||||
void drop_bchannel(call_t *call);
|
void drop_bchannel(call_t *call);
|
||||||
void rtp_receive(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 rtp_receive(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 hold_clock(isdn_t *isdn_ep, int len);
|
void enable_hold_clock(isdn_t *isdn_ep);
|
||||||
|
|
||||||
|
|
|
@ -307,7 +307,6 @@ static int mISDNlib_debug(const char *file, int line, const char *func, int __at
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
double last_time_call = 0, now;
|
|
||||||
int argi, rc;
|
int argi, rc;
|
||||||
int misdn_initialized = 0;
|
int misdn_initialized = 0;
|
||||||
int ph_drv_initialized = 0;
|
int ph_drv_initialized = 0;
|
||||||
|
@ -340,7 +339,7 @@ int main(int argc, char *argv[])
|
||||||
/* start bridge server */
|
/* start bridge server */
|
||||||
if (use_hfc_bridging) {
|
if (use_hfc_bridging) {
|
||||||
brigde_socket_server(pcm_slots);
|
brigde_socket_server(pcm_slots);
|
||||||
bridge_socket_client();
|
bridge_socket_client(isdn_ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!misdn_kernel && !misdn_user) {
|
if (!misdn_kernel && !misdn_user) {
|
||||||
|
@ -412,37 +411,30 @@ int main(int argc, char *argv[])
|
||||||
signal(SIGPIPE, sighandler);
|
signal(SIGPIPE, sighandler);
|
||||||
|
|
||||||
while (!quit) {
|
while (!quit) {
|
||||||
int w;
|
int work;
|
||||||
|
double timeout, misdn_timeout = 0.0;
|
||||||
|
|
||||||
/* send clock calls to provide audio to suspended/helt calls */
|
|
||||||
now = get_time();
|
|
||||||
if (now - last_time_call >= 0.1)
|
|
||||||
last_time_call = now;
|
|
||||||
if (now - last_time_call >= 0.020) {
|
|
||||||
last_time_call += 0.020;
|
|
||||||
/* call hold-clock every 20ms */
|
|
||||||
hold_clock(isdn_ep, 160);
|
|
||||||
}
|
|
||||||
|
|
||||||
process_timer();
|
|
||||||
isdn_bchannel_work(isdn_ep);
|
|
||||||
isdn_rtp_work(isdn_ep);
|
|
||||||
bridge_socket_client_work(isdn_ep);
|
|
||||||
if (misdn_user) {
|
|
||||||
/* run workers of mISDN stacks in user space */
|
|
||||||
mISDN_work();
|
|
||||||
}
|
|
||||||
do {
|
do {
|
||||||
w = 0;
|
work = 0;
|
||||||
w |= osmo_cc_handle();
|
work |= osmo_cc_handle();
|
||||||
w |= isdn_dchannel_work(isdn_ep);
|
|
||||||
if (misdn_user) {
|
if (misdn_user) {
|
||||||
/* run workers of mISDN stacks in user space */
|
/* run workers of mISDN stacks in user space */
|
||||||
w |= ph_socket_work(&ph_drv.ph_socket);
|
work |= mISDN_work();
|
||||||
w |= work_layer3(isdn_ep->ml3);
|
work |= work_layer3(isdn_ep->ml3, &misdn_timeout);
|
||||||
}
|
}
|
||||||
} while (w);
|
} while (work);
|
||||||
usleep(1000);
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
signal(SIGINT, SIG_DFL);
|
signal(SIGINT, SIG_DFL);
|
||||||
|
@ -459,7 +451,7 @@ int main(int argc, char *argv[])
|
||||||
schedp.sched_priority = 0;
|
schedp.sched_priority = 0;
|
||||||
sched_setscheduler(0, SCHED_OTHER, &schedp);
|
sched_setscheduler(0, SCHED_OTHER, &schedp);
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (isdn_ep) {
|
if (isdn_ep) {
|
||||||
osmo_cc_delete(&isdn_ep->cc_ep);
|
osmo_cc_delete(&isdn_ep->cc_ep);
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "../libtimer/timer.h"
|
||||||
|
#include "../libselect/select.h"
|
||||||
#include "../libph_socket/ph_socket.h"
|
#include "../libph_socket/ph_socket.h"
|
||||||
#include "ph_driver.h"
|
#include "ph_driver.h"
|
||||||
#define __MISDNL1L2__
|
#define __MISDNL1L2__
|
||||||
|
@ -171,7 +174,7 @@ static void ph_socket_rx_msg(ph_socket_t *s, int channel, uint8_t prim, uint8_t
|
||||||
/* init instance of PH-socket driver */
|
/* init instance of PH-socket driver */
|
||||||
int init_ph_socket_driver(struct ph_socket_driver *drv, void *priv, const char *socket_name, int pri, int nt, uint32_t debug)
|
int init_ph_socket_driver(struct ph_socket_driver *drv, void *priv, const char *socket_name, int pri, int nt, uint32_t debug)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int rc = 0;
|
||||||
struct dchannel *dch;
|
struct dchannel *dch;
|
||||||
|
|
||||||
|
|
||||||
|
@ -180,13 +183,10 @@ int init_ph_socket_driver(struct ph_socket_driver *drv, void *priv, const char *
|
||||||
drv->pri = pri;
|
drv->pri = pri;
|
||||||
drv->nt = nt;
|
drv->nt = nt;
|
||||||
|
|
||||||
/* socket client */
|
|
||||||
ph_socket_init(&drv->ph_socket, ph_socket_rx_msg, drv, socket_name, 0);
|
|
||||||
|
|
||||||
/* allocate dchannel structure */
|
/* allocate dchannel structure */
|
||||||
dch = kzalloc(sizeof(*dch), GFP_KERNEL);
|
dch = kzalloc(sizeof(*dch), GFP_KERNEL);
|
||||||
if (!dch) {
|
if (!dch) {
|
||||||
ret = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,21 +215,30 @@ int init_ph_socket_driver(struct ph_socket_driver *drv, void *priv, const char *
|
||||||
dch->dev.nrbchan = 0;
|
dch->dev.nrbchan = 0;
|
||||||
|
|
||||||
/* register dchannel to mISDN */
|
/* register dchannel to mISDN */
|
||||||
ret = mISDN_register_device(&dch->dev, NULL, socket_name);
|
rc = mISDN_register_device(&dch->dev, NULL, socket_name);
|
||||||
if (ret) {
|
if (rc) {
|
||||||
kfree(dch);
|
goto error;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* link */
|
/* link */
|
||||||
drv->dch = dch;
|
drv->dch = dch;
|
||||||
|
|
||||||
|
/* socket client, must be initialized here, because driver will receive PH_PRIM_CTRL_IND message during init */
|
||||||
|
rc = ph_socket_init(&drv->ph_socket, ph_socket_rx_msg, drv, socket_name, 0);
|
||||||
|
if (rc < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
if (dch) {
|
||||||
|
kfree(dch);
|
||||||
|
dch = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
exit_ph_socket_driver(drv);
|
exit_ph_socket_driver(drv);
|
||||||
|
|
||||||
return ret;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* destroy instance of PH-socket driver */
|
/* destroy instance of PH-socket driver */
|
||||||
|
|
|
@ -416,13 +416,16 @@ void mISDN_cleanup(void)
|
||||||
printk(KERN_DEBUG "mISDNcore unloaded\n");
|
printk(KERN_DEBUG "mISDNcore unloaded\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void mISDN_work(void)
|
int mISDN_work(void)
|
||||||
{
|
{
|
||||||
struct mISDNdevice *dev;
|
struct mISDNdevice *dev;
|
||||||
|
int work = 0;
|
||||||
|
|
||||||
hlist_for_each_entry(dev, &dev_list.head, list) {
|
hlist_for_each_entry(dev, &dev_list.head, list) {
|
||||||
work_stack(dev);
|
work |= work_stack(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return work;
|
||||||
}
|
}
|
||||||
|
|
||||||
//module_init(mISDNInit);
|
//module_init(mISDNInit);
|
||||||
|
|
|
@ -73,5 +73,5 @@ extern void mISDN_init_clock(u_int *);
|
||||||
|
|
||||||
extern int mISDNInit(uint debug);
|
extern int mISDNInit(uint debug);
|
||||||
extern void mISDN_cleanup(void);
|
extern void mISDN_cleanup(void);
|
||||||
extern void mISDN_work(void);
|
extern int mISDN_work(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -92,9 +92,9 @@ mISDN_FsmChangeState(struct FsmInst *fi, int newstate)
|
||||||
EXPORT_SYMBOL(mISDN_FsmChangeState);
|
EXPORT_SYMBOL(mISDN_FsmChangeState);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FsmExpireTimer(struct timer *t)
|
FsmExpireTimer(void *data)
|
||||||
{
|
{
|
||||||
struct FsmTimer *ft = t->priv;
|
struct FsmTimer *ft = data;
|
||||||
#if FSM_TIMER_DEBUG
|
#if FSM_TIMER_DEBUG
|
||||||
if (ft->fi->debug)
|
if (ft->fi->debug)
|
||||||
ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
|
ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
|
||||||
|
|
|
@ -190,6 +190,7 @@ int
|
||||||
work_stack(struct mISDNdevice *dev)
|
work_stack(struct mISDNdevice *dev)
|
||||||
{
|
{
|
||||||
struct mISDNstack *st = dev->D.st;
|
struct mISDNstack *st = dev->D.st;
|
||||||
|
int work = 0;
|
||||||
#if 0
|
#if 0
|
||||||
#ifdef MISDN_MSG_STATS
|
#ifdef MISDN_MSG_STATS
|
||||||
u64 utime, stime;
|
u64 utime, stime;
|
||||||
|
@ -229,6 +230,7 @@ work_stack(struct mISDNdevice *dev)
|
||||||
test_and_set_bit(mISDN_STACK_WORK,
|
test_and_set_bit(mISDN_STACK_WORK,
|
||||||
&st->status);
|
&st->status);
|
||||||
}
|
}
|
||||||
|
work = 1;
|
||||||
#ifdef MISDN_MSG_STATS
|
#ifdef MISDN_MSG_STATS
|
||||||
st->msg_cnt++;
|
st->msg_cnt++;
|
||||||
#endif
|
#endif
|
||||||
|
@ -322,7 +324,7 @@ work_stack(struct mISDNdevice *dev)
|
||||||
st->notify = NULL;
|
st->notify = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return work;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -171,7 +171,7 @@ extern void init_l3(layer3_t *);
|
||||||
extern void release_l3(layer3_t *);
|
extern void release_l3(layer3_t *);
|
||||||
extern int l3_start(struct _layer3 *);
|
extern int l3_start(struct _layer3 *);
|
||||||
extern void l3_stop(struct _layer3 *);
|
extern void l3_stop(struct _layer3 *);
|
||||||
extern int layer3_work(struct _layer3 *l3);
|
extern int layer3_work(struct _layer3 *l3, double *misdn_timeout);
|
||||||
extern void mISDNl3New(void);
|
extern void mISDNl3New(void);
|
||||||
extern void mISDNl3Free(void);
|
extern void mISDNl3Free(void);
|
||||||
|
|
||||||
|
|
|
@ -231,7 +231,7 @@ extern void close_layer3(struct mlayer3 *);
|
||||||
* run stack for one loop
|
* run stack for one loop
|
||||||
* parameter1 - stack struct
|
* parameter1 - stack struct
|
||||||
*/
|
*/
|
||||||
extern int work_layer3(struct mlayer3 *);
|
extern int work_layer3(struct mlayer3 *, double *);
|
||||||
|
|
||||||
extern unsigned int request_new_pid(struct mlayer3 *);
|
extern unsigned int request_new_pid(struct mlayer3 *);
|
||||||
extern int mISDN_get_pcm_slots(struct mlayer3 *, int, int *, int *);
|
extern int mISDN_get_pcm_slots(struct mlayer3 *, int, int *, int *);
|
||||||
|
|
|
@ -41,6 +41,6 @@ extern int init_timer(struct mtimer *, struct timer_base *, void *, mtimer_fun
|
||||||
extern int add_timer(struct mtimer *, int);
|
extern int add_timer(struct mtimer *, int);
|
||||||
extern int del_timer(struct mtimer *);
|
extern int del_timer(struct mtimer *);
|
||||||
extern int timer_pending(struct mtimer *);
|
extern int timer_pending(struct mtimer *);
|
||||||
extern int expire_timer(struct timer_base *, int);
|
extern int expire_timer(struct timer_base *, int, double *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -888,7 +888,7 @@ to_l2(layer3_t *l3, struct l3_msg *l3m)
|
||||||
|
|
||||||
/* one shot */
|
/* one shot */
|
||||||
int
|
int
|
||||||
layer3_work(struct _layer3 *l3)
|
layer3_work(struct _layer3 *l3, double *misdn_timeout)
|
||||||
{
|
{
|
||||||
fd_set rfd;
|
fd_set rfd;
|
||||||
struct mbuffer *mb;
|
struct mbuffer *mb;
|
||||||
|
@ -916,14 +916,14 @@ again:
|
||||||
eprint("%s read timer error %s\n", __FUNCTION__, strerror(errno));
|
eprint("%s read timer error %s\n", __FUNCTION__, strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
if (ret == sizeof(id) && id) {
|
if (ret == sizeof(id) && id) {
|
||||||
work |= expire_timer(&l3->tbase, id);
|
work |= expire_timer(&l3->tbase, id, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (l3->l2inst) {
|
if (l3->l2inst) {
|
||||||
/* loops through all timers until there is no expired timer anymore */
|
/* loops through all timers until there is no expired timer anymore */
|
||||||
work |= expire_timer(&l3->tbase, -1);
|
work |= expire_timer(&l3->tbase, -1, misdn_timeout);
|
||||||
}
|
}
|
||||||
/* check rdf when using kernel mISDN, poll when using user space mISDN */
|
/* check rdf when using kernel mISDN, poll when using user space mISDN */
|
||||||
if ((l3->l2sock && FD_ISSET(l3->l2sock, &rfd))
|
if ((l3->l2sock && FD_ISSET(l3->l2sock, &rfd))
|
||||||
|
@ -1014,7 +1014,7 @@ layer3_thread(void *arg)
|
||||||
struct _layer3 *l3 = arg;
|
struct _layer3 *l3 = arg;
|
||||||
|
|
||||||
while(!test_bit(FLG_ABORT, &l3->ml3.options)) {
|
while(!test_bit(FLG_ABORT, &l3->ml3.options)) {
|
||||||
layer3_work(l3);
|
layer3_work(l3, NULL);
|
||||||
if (test_bit(FLG_RUN_WAIT, &l3->ml3.options)) {
|
if (test_bit(FLG_RUN_WAIT, &l3->ml3.options)) {
|
||||||
test_and_clear_bit(FLG_RUN_WAIT, &l3->ml3.options);
|
test_and_clear_bit(FLG_RUN_WAIT, &l3->ml3.options);
|
||||||
pthread_mutex_unlock(&l3->run);
|
pthread_mutex_unlock(&l3->run);
|
||||||
|
|
|
@ -316,12 +316,12 @@ close_layer3(struct mlayer3 *ml3)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
work_layer3(struct mlayer3 *ml3)
|
work_layer3(struct mlayer3 *ml3, double *misdn_timeout)
|
||||||
{
|
{
|
||||||
struct _layer3 *l3;
|
struct _layer3 *l3;
|
||||||
|
|
||||||
l3 = container_of(ml3, struct _layer3, ml3);
|
l3 = container_of(ml3, struct _layer3, ml3);
|
||||||
return layer3_work(l3);
|
return layer3_work(l3, misdn_timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -106,7 +106,8 @@ del_timer(struct mtimer *mt)
|
||||||
#endif
|
#endif
|
||||||
if (mt->id) {
|
if (mt->id) {
|
||||||
list_del(&mt->list);
|
list_del(&mt->list);
|
||||||
ret = ioctl(mt->tb->tdev, IMDELTIMER, (long)&mt->id);
|
if (mt->tb->tdev)
|
||||||
|
ret = ioctl(mt->tb->tdev, IMDELTIMER, (long)&mt->id);
|
||||||
mt->id = 0;
|
mt->id = 0;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_TIMERS
|
#ifdef DEBUG_TIMERS
|
||||||
|
@ -122,11 +123,12 @@ timer_pending(struct mtimer *mt)
|
||||||
return mt->id;
|
return mt->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int expire_timer(struct timer_base *tb, int id)
|
int expire_timer(struct timer_base *tb, int id, double *misdn_timeout)
|
||||||
{
|
{
|
||||||
struct mtimer *mt;
|
struct mtimer *mt;
|
||||||
double now = 0.0;
|
double now = 0.0;
|
||||||
int work = 0;
|
int work = 0;
|
||||||
|
double timeout = 0.0;
|
||||||
|
|
||||||
/* if id is < 0, then check for expired timer */
|
/* if id is < 0, then check for expired timer */
|
||||||
if (id < 0) {
|
if (id < 0) {
|
||||||
|
@ -170,6 +172,17 @@ again:
|
||||||
#endif
|
#endif
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
/* we look for the next unexpired timer */
|
||||||
|
if (!timeout || (mt->expires - now) < timeout)
|
||||||
|
timeout = mt->expires - now;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if no timer has expired, also present the timeout for the next timer */
|
||||||
|
if (misdn_timeout) {
|
||||||
|
if (work)
|
||||||
|
*misdn_timeout = 0.0;
|
||||||
|
else
|
||||||
|
*misdn_timeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
return work;
|
return work;
|
||||||
|
|
Loading…
Reference in New Issue