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/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
|
||||
|
|
|
@ -84,6 +84,7 @@ AC_OUTPUT(
|
|||
src/libdebug/Makefile
|
||||
src/libsample/Makefile
|
||||
src/libtimer/Makefile
|
||||
src/libselect/Makefile
|
||||
src/libjitter/Makefile
|
||||
src/libosmocc/Makefile
|
||||
src/libg711/Makefile
|
||||
|
|
|
@ -5,6 +5,7 @@ SUBDIRS = \
|
|||
libdebug \
|
||||
libsample \
|
||||
libtimer \
|
||||
libselect \
|
||||
libjitter \
|
||||
libosmocc \
|
||||
libg711 \
|
||||
|
|
|
@ -18,6 +18,7 @@ osmo_cc_misdn_endpoint_LDADD = \
|
|||
../liboptions/liboptions.a \
|
||||
../libsample/libsample.a \
|
||||
../libtimer/libtimer.a \
|
||||
../libselect/libselect.a \
|
||||
../libjitter/libjitter.a \
|
||||
../libosmocc/libosmocc.a \
|
||||
../libg711/libg711.a \
|
||||
|
|
|
@ -113,7 +113,7 @@ static int num_slots;
|
|||
|
||||
struct conn {
|
||||
struct conn *next;
|
||||
int socket;
|
||||
struct osmo_fd ofd;
|
||||
int rx_index;
|
||||
struct msg_channel_info
|
||||
rx_msg;
|
||||
|
@ -137,7 +137,8 @@ struct channel {
|
|||
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 channel *channel_list = NULL;
|
||||
|
||||
|
@ -190,18 +191,20 @@ static void free_all_connections(void)
|
|||
while (c) {
|
||||
PDEBUG(DISDN, DEBUG_INFO, "Free pending bridge connection.\n");
|
||||
c2 = c;
|
||||
close(c->socket);
|
||||
osmo_fd_unregister(&c->ofd);
|
||||
close(c->ofd.fd);
|
||||
c = c->next;
|
||||
free(c2);
|
||||
}
|
||||
conn_list = NULL;
|
||||
}
|
||||
|
||||
static int bridge_socket_server_cb(struct osmo_fd *ofd, unsigned int when);
|
||||
|
||||
/* function to open the server socket */
|
||||
static int open_server_socket(int daemon)
|
||||
{
|
||||
struct sockaddr_un sock_address;
|
||||
int flags;
|
||||
int rc;
|
||||
|
||||
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");
|
||||
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 (!daemon || errno != EADDRINUSE)
|
||||
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;
|
||||
}
|
||||
|
||||
rc = listen(server_socket, 10);
|
||||
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));
|
||||
close(server_socket);
|
||||
osmo_fd_unregister(&server_ofd);
|
||||
close(server_ofd.fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* set nonblocking io */
|
||||
flags = fcntl(server_socket, F_GETFL);
|
||||
flags |= O_NONBLOCK;
|
||||
fcntl(server_socket, F_SETFL, flags);
|
||||
|
||||
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;
|
||||
socklen_t sock_len = sizeof(sock_address);
|
||||
struct conn *c;
|
||||
int flags;
|
||||
int rc;
|
||||
|
||||
rc = accept(server_socket, (struct sockaddr *)&sock_address, &sock_len);
|
||||
if (rc > 0) {
|
||||
PDEBUG(DISDN, DEBUG_INFO, "Connection from bridge socket client.\n");
|
||||
/* create connection */
|
||||
c = calloc(1, sizeof(*c));
|
||||
if (!c) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "No mem!\n");
|
||||
abort();
|
||||
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");
|
||||
/* create connection */
|
||||
c = calloc(1, sizeof(*c));
|
||||
if (!c) {
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
|
||||
|
@ -278,7 +287,7 @@ void close_server_connection(int socket)
|
|||
do {
|
||||
c = channel_list;
|
||||
while (c) {
|
||||
if (c->socket == socket)
|
||||
if (c->socket == ofd->fd)
|
||||
break;
|
||||
c = c->next;
|
||||
}
|
||||
|
@ -288,36 +297,41 @@ void close_server_connection(int socket)
|
|||
}
|
||||
} while (c);
|
||||
|
||||
close(socket);
|
||||
osmo_fd_unregister(ofd);
|
||||
close(ofd->fd);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* read message until complete */
|
||||
rc = recv(c->socket, ((uint8_t *)&c->rx_msg) + c->rx_index, sizeof(c->rx_msg) - c->rx_index, 0);
|
||||
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");
|
||||
/* 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");
|
||||
return;
|
||||
if ((when & OSMO_FD_READ)) {
|
||||
rc = recv(c->ofd.fd, ((uint8_t *)&c->rx_msg) + c->rx_index, sizeof(c->rx_msg) - c->rx_index, 0);
|
||||
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");
|
||||
/* 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");
|
||||
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 */
|
||||
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);
|
||||
c->rx_index = 0;
|
||||
return;
|
||||
} else if (rc == 0 || errno != EAGAIN) {
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "Close from bridge socket client.\n");
|
||||
close_server_connection(&c->ofd);
|
||||
/* 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)
|
||||
|
@ -325,11 +339,34 @@ static void sighandler(int 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 */
|
||||
void bridge_socket_server_child(int slots, int daemon)
|
||||
{
|
||||
struct conn *c, *c2;
|
||||
int count_ms = 0, delay_ms = 10;
|
||||
int rc;
|
||||
|
||||
num_slots = slots;
|
||||
|
@ -349,43 +386,27 @@ void bridge_socket_server_child(int slots, int daemon)
|
|||
signal(SIGPIPE, sighandler);
|
||||
}
|
||||
|
||||
while(42) {
|
||||
listen_server_socket();
|
||||
c = conn_list;
|
||||
if (daemon) {
|
||||
/* timeout after some time without a connection */
|
||||
if (!c) {
|
||||
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);
|
||||
if (daemon) {
|
||||
timer_init(&server_timer, server_exit_timeout, NULL);
|
||||
timer_start(&server_timer, 0.3);
|
||||
} else {
|
||||
timer_init(&server_timer, server_show_timeout, NULL);
|
||||
timer_start(&server_timer, 1.0);
|
||||
}
|
||||
|
||||
while(!quit) {
|
||||
double timeout;
|
||||
|
||||
timeout = process_timer();
|
||||
osmo_fd_select(timeout);
|
||||
}
|
||||
|
||||
timer_exit(&server_timer);
|
||||
|
||||
free_all_channels();
|
||||
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 */
|
||||
|
@ -599,15 +620,16 @@ void tx_bridge_order(int socket, int card, int port, int channel, int pcm_bridge
|
|||
* client
|
||||
*/
|
||||
|
||||
static int client_socket = -1;
|
||||
static struct osmo_fd client_ofd = { .fd = -1 };
|
||||
int client_rx_index = 0;
|
||||
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 */
|
||||
int bridge_socket_client(void)
|
||||
int bridge_socket_client(isdn_t *isdn_ep)
|
||||
{
|
||||
struct sockaddr_un sock_address;
|
||||
int flags;
|
||||
int rc;
|
||||
|
||||
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");
|
||||
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) {
|
||||
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);
|
||||
client_socket = 0;
|
||||
osmo_fd_unregister(&client_ofd);
|
||||
close(client_ofd.fd);
|
||||
client_ofd.fd = -1;
|
||||
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");
|
||||
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
|
||||
again:
|
||||
/* no client */
|
||||
if (client_socket <= 0)
|
||||
return;
|
||||
|
||||
/* read message until complete */
|
||||
rc = recv(client_socket, ((uint8_t *)&client_rx_msg) + client_rx_index, sizeof(client_rx_msg) - client_rx_index, 0);
|
||||
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");
|
||||
/* 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");
|
||||
return;
|
||||
if ((when & OSMO_FD_READ)) {
|
||||
/* read message until complete */
|
||||
rc = recv(client_ofd.fd, ((uint8_t *)&client_rx_msg) + client_rx_index, sizeof(client_rx_msg) - client_rx_index, 0);
|
||||
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");
|
||||
/* 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");
|
||||
return 0;
|
||||
}
|
||||
/* process message and reset buffer index */
|
||||
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);
|
||||
client_rx_index = 0;
|
||||
}
|
||||
/* process message and reset buffer index */
|
||||
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);
|
||||
client_rx_index = 0;
|
||||
goto again;
|
||||
} else if (rc == 0 || errno != EAGAIN) {
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "Close from bridge socket client.\n");
|
||||
osmo_fd_unregister(&client_ofd);
|
||||
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 */
|
||||
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;
|
||||
|
||||
/* no client */
|
||||
if (client_socket <= 0)
|
||||
if (client_ofd.fd <= 0)
|
||||
return;
|
||||
|
||||
PDEBUG(DISDN, DEBUG_INFO, "We got called with enable=%d\n", enable);
|
||||
|
@ -850,7 +871,7 @@ send:
|
|||
else
|
||||
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)
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
int brigde_socket_server(int slots);
|
||||
void bridge_socket_server_child(int slots, int daemon);
|
||||
|
||||
int bridge_socket_client(void);
|
||||
void bridge_socket_client_work(isdn_t *isdn_ep);
|
||||
int bridge_socket_client(isdn_t *isdn_ep);
|
||||
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 */
|
||||
jitter_reset(&call->tx_dejitter);
|
||||
|
||||
/* generate hold tone, using local clock */
|
||||
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);
|
||||
l3m = create_l3msg();
|
||||
|
@ -1078,6 +1081,9 @@ void suspend_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
|
|||
/* deactivate bchannel */
|
||||
drop_bchannel(call);
|
||||
|
||||
/* generate hold tone, using local clock */
|
||||
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);
|
||||
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->clock_timer);
|
||||
|
||||
free(isdn_ep);
|
||||
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "ISDN instance destroyed\n");
|
||||
}
|
||||
|
||||
static void clock_timeout(void *data);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
static int bchannel_kernel_sock_receive_cb(struct osmo_fd *ofd, unsigned int when);
|
||||
|
||||
/* create B-channel stack */
|
||||
static int bchannel_create(isdn_t *isdn_ep, int index)
|
||||
{
|
||||
int channel = index + 1 + (index >= 15);
|
||||
struct sockaddr_mISDN addr;
|
||||
int flags;
|
||||
int rc;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
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);
|
||||
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);
|
||||
return(0);
|
||||
}
|
||||
isdn_ep->b_sock[index] = rc;
|
||||
isdn_ep->b_sock[index].ofd.fd = rc;
|
||||
|
||||
/* set nonblocking io */
|
||||
flags = fcntl(isdn_ep->b_sock[index], F_GETFL);
|
||||
flags |= O_NONBLOCK;
|
||||
fcntl(isdn_ep->b_sock[index], F_SETFL, flags);
|
||||
/* register */
|
||||
isdn_ep->b_sock[index].isdn_ep = isdn_ep;
|
||||
isdn_ep->b_sock[index].index = index;
|
||||
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 */
|
||||
addr.family = AF_ISDN;
|
||||
addr.dev = isdn_ep->portnum;
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -932,14 +942,14 @@ static void bchannel_activate(isdn_t *isdn_ep, int index, int activate, int time
|
|||
int rc;
|
||||
|
||||
if (isdn_ep->l2sock) {
|
||||
if (isdn_ep->b_sock[index] <= 0)
|
||||
if (isdn_ep->b_sock[index].ofd.fd <= 0)
|
||||
return;
|
||||
|
||||
act.prim = (activate) ? PH_ACTIVATE_REQ : PH_DEACTIVATE_REQ;
|
||||
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)
|
||||
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) {
|
||||
|
@ -964,10 +974,10 @@ static void bchannel_configure(isdn_t *isdn_ep, int index)
|
|||
call_t *call;
|
||||
int handle;
|
||||
|
||||
if (isdn_ep->b_sock[index] <= 0)
|
||||
if (isdn_ep->b_sock[index].ofd.fd <= 0)
|
||||
return;
|
||||
|
||||
handle = isdn_ep->b_sock[index];
|
||||
handle = isdn_ep->b_sock[index].ofd.fd;
|
||||
call = isdn_ep->b_call[index];
|
||||
|
||||
/* set PCM bridge features */
|
||||
|
@ -1007,13 +1017,15 @@ static void bchannel_destroy(isdn_t *isdn_ep, int index)
|
|||
int channel = index + 1 + (index >= 15);
|
||||
|
||||
if (isdn_ep->l2sock) {
|
||||
if (isdn_ep->b_sock[index] <= 0)
|
||||
if (isdn_ep->b_sock[index].ofd.fd <= 0)
|
||||
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]);
|
||||
isdn_ep->b_sock[index] = 0;
|
||||
/* unregister and close */
|
||||
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) {
|
||||
|
@ -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);
|
||||
|
||||
/* 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);
|
||||
unsigned char buffer[2048+MISDN_HEADER_LEN];
|
||||
struct mISDNhead *hh = (struct mISDNhead *)buffer;
|
||||
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 (errno == EAGAIN)
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -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)
|
||||
ph_socket_tx_msg(call->isdn_ep->ph_socket, call->b_channel, PH_PRIM_DATA_REQ, buf + MISDN_HEADER_LEN, offset + len);
|
||||
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)
|
||||
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
|
||||
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 */
|
||||
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);
|
||||
pthread_mutex_unlock(&isdn_ep->upqueue_lock);
|
||||
|
||||
/* wake main thread */
|
||||
char wakeup = 0;
|
||||
write(isdn_ep->upqueue_pipe[1], &wakeup, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1745,7 +1757,8 @@ int mISDN_getportbyname(isdn_t *isdn_ep, int cnt, const char *portname)
|
|||
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 */
|
||||
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() */
|
||||
mqueue_init(&isdn_ep->upqueue);
|
||||
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 ? */
|
||||
for (i = 0; i < (int)strlen(portname); i++){
|
||||
|
@ -1878,6 +1901,8 @@ int isdn_open(isdn_t *isdn_ep)
|
|||
i++;
|
||||
}
|
||||
|
||||
timer_init(&isdn_ep->clock_timer, clock_timeout, isdn_ep);
|
||||
|
||||
timer_init(&isdn_ep->l2establish_timer, l2establish_timeout, isdn_ep);
|
||||
|
||||
isdn_ep->l1link = -1;
|
||||
|
@ -1975,7 +2000,7 @@ void isdn_close(isdn_t *isdn_ep)
|
|||
|
||||
/* free bchannels */
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
/* purge upqueue */
|
||||
/* purge and remove upqueue */
|
||||
if (isdn_ep->upqueue_initialized)
|
||||
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) {
|
||||
free(isdn_ep->portname);
|
||||
|
@ -2009,116 +2043,120 @@ void isdn_close(isdn_t *isdn_ep)
|
|||
}
|
||||
}
|
||||
|
||||
/* receive message from ISDN protocol stack (out of queue) */
|
||||
int isdn_dchannel_work(isdn_t *isdn_ep)
|
||||
/* receive message from ISDN protocol stack (out of the upqueue) */
|
||||
static int isdn_upqueue_cb(struct osmo_fd *ofd, unsigned __attribute__((unused)) int what)
|
||||
{
|
||||
isdn_t *isdn_ep = ofd->data;
|
||||
struct mbuffer *mb;
|
||||
struct l3_msg *l3m;
|
||||
int w = 0;
|
||||
|
||||
char wakeup = 0;
|
||||
read(ofd->fd, &wakeup, 1);
|
||||
|
||||
again:
|
||||
/* handle queued up-messages (d-channel) */
|
||||
pthread_mutex_lock(&isdn_ep->upqueue_lock);
|
||||
mb = mdequeue(&isdn_ep->upqueue);
|
||||
pthread_mutex_unlock(&isdn_ep->upqueue_lock);
|
||||
if (mb) {
|
||||
w |= 1;
|
||||
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;
|
||||
if (!mb)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
/* free message */
|
||||
free_l3_msg(l3m);
|
||||
}
|
||||
break;
|
||||
|
||||
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 */
|
||||
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)) {
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* local clock to generate hold tone
|
||||
*/
|
||||
|
||||
#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;
|
||||
int any = 0;
|
||||
|
||||
call = isdn_ep->call_list;
|
||||
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);
|
||||
osmo_cc_rtp_send(call->codec, data, len, 0, 1, len, call);
|
||||
free(data);
|
||||
any = 1;
|
||||
}
|
||||
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 "../libtimer/timer.h"
|
||||
#include "../libselect/select.h"
|
||||
#include "../libosmocc/endpoint.h"
|
||||
#include "../libosmocc/helper.h"
|
||||
#include "../libsample/sample.h"
|
||||
|
@ -65,6 +66,14 @@ struct select_channel {
|
|||
int channel;
|
||||
};
|
||||
|
||||
struct isdn;
|
||||
|
||||
struct isdn_b_sock {
|
||||
int index;
|
||||
struct isdn *isdn_ep;
|
||||
struct osmo_fd ofd;
|
||||
};
|
||||
|
||||
struct call_list;
|
||||
|
||||
typedef struct isdn {
|
||||
|
@ -98,6 +107,8 @@ typedef struct isdn {
|
|||
pthread_mutex_t upqueue_lock;
|
||||
struct mqueue upqueue;
|
||||
int upqueue_initialized;
|
||||
int upqueue_pipe[2];
|
||||
struct osmo_fd upqueue_ofd;
|
||||
struct mlayer3 *ml3;
|
||||
int los, ais, rdi, slip_rx, slip_tx;
|
||||
int l1link; /* current state */
|
||||
|
@ -107,7 +118,7 @@ typedef struct isdn {
|
|||
int b_reserved;
|
||||
int b_mode[128];
|
||||
int b_state[128];
|
||||
int b_sock[128];
|
||||
struct isdn_b_sock b_sock[128];
|
||||
struct call_list *b_call[128];
|
||||
struct timer b_timer[128];
|
||||
struct b_timer_inst b_timer_inst[128];
|
||||
|
@ -119,6 +130,10 @@ typedef struct isdn {
|
|||
int bridge_possible;
|
||||
int bridge_cardnum;
|
||||
int bridge_portnum;
|
||||
|
||||
/* clock for tone on hold */
|
||||
struct timer clock_timer;
|
||||
double last_time_clock;
|
||||
} isdn_t;
|
||||
|
||||
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);
|
||||
void isdn_close(isdn_t *isdn_ep);
|
||||
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_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);
|
||||
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 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[])
|
||||
{
|
||||
double last_time_call = 0, now;
|
||||
int argi, rc;
|
||||
int misdn_initialized = 0;
|
||||
int ph_drv_initialized = 0;
|
||||
|
@ -340,7 +339,7 @@ int main(int argc, char *argv[])
|
|||
/* start bridge server */
|
||||
if (use_hfc_bridging) {
|
||||
brigde_socket_server(pcm_slots);
|
||||
bridge_socket_client();
|
||||
bridge_socket_client(isdn_ep);
|
||||
}
|
||||
|
||||
if (!misdn_kernel && !misdn_user) {
|
||||
|
@ -412,37 +411,30 @@ int main(int argc, char *argv[])
|
|||
signal(SIGPIPE, sighandler);
|
||||
|
||||
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 {
|
||||
w = 0;
|
||||
w |= osmo_cc_handle();
|
||||
w |= isdn_dchannel_work(isdn_ep);
|
||||
work = 0;
|
||||
work |= osmo_cc_handle();
|
||||
if (misdn_user) {
|
||||
/* run workers of mISDN stacks in user space */
|
||||
w |= ph_socket_work(&ph_drv.ph_socket);
|
||||
w |= work_layer3(isdn_ep->ml3);
|
||||
work |= mISDN_work();
|
||||
work |= work_layer3(isdn_ep->ml3, &misdn_timeout);
|
||||
}
|
||||
} while (w);
|
||||
usleep(1000);
|
||||
} 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);
|
||||
}
|
||||
|
||||
signal(SIGINT, SIG_DFL);
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include "../libtimer/timer.h"
|
||||
#include "../libselect/select.h"
|
||||
#include "../libph_socket/ph_socket.h"
|
||||
#include "ph_driver.h"
|
||||
#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 */
|
||||
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;
|
||||
|
||||
|
||||
|
@ -180,13 +183,10 @@ int init_ph_socket_driver(struct ph_socket_driver *drv, void *priv, const char *
|
|||
drv->pri = pri;
|
||||
drv->nt = nt;
|
||||
|
||||
/* socket client */
|
||||
ph_socket_init(&drv->ph_socket, ph_socket_rx_msg, drv, socket_name, 0);
|
||||
|
||||
/* allocate dchannel structure */
|
||||
dch = kzalloc(sizeof(*dch), GFP_KERNEL);
|
||||
if (!dch) {
|
||||
ret = -ENOMEM;
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -215,21 +215,30 @@ int init_ph_socket_driver(struct ph_socket_driver *drv, void *priv, const char *
|
|||
dch->dev.nrbchan = 0;
|
||||
|
||||
/* register dchannel to mISDN */
|
||||
ret = mISDN_register_device(&dch->dev, NULL, socket_name);
|
||||
if (ret) {
|
||||
kfree(dch);
|
||||
return ret;
|
||||
rc = mISDN_register_device(&dch->dev, NULL, socket_name);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* link */
|
||||
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;
|
||||
|
||||
error:
|
||||
if (dch) {
|
||||
kfree(dch);
|
||||
dch = NULL;
|
||||
}
|
||||
|
||||
exit_ph_socket_driver(drv);
|
||||
|
||||
return ret;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* destroy instance of PH-socket driver */
|
||||
|
|
|
@ -416,13 +416,16 @@ void mISDN_cleanup(void)
|
|||
printk(KERN_DEBUG "mISDNcore unloaded\n");
|
||||
}
|
||||
|
||||
void mISDN_work(void)
|
||||
int mISDN_work(void)
|
||||
{
|
||||
struct mISDNdevice *dev;
|
||||
int work = 0;
|
||||
|
||||
hlist_for_each_entry(dev, &dev_list.head, list) {
|
||||
work_stack(dev);
|
||||
work |= work_stack(dev);
|
||||
}
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
//module_init(mISDNInit);
|
||||
|
|
|
@ -73,5 +73,5 @@ extern void mISDN_init_clock(u_int *);
|
|||
|
||||
extern int mISDNInit(uint debug);
|
||||
extern void mISDN_cleanup(void);
|
||||
extern void mISDN_work(void);
|
||||
extern int mISDN_work(void);
|
||||
#endif
|
||||
|
|
|
@ -92,9 +92,9 @@ mISDN_FsmChangeState(struct FsmInst *fi, int newstate)
|
|||
EXPORT_SYMBOL(mISDN_FsmChangeState);
|
||||
|
||||
static void
|
||||
FsmExpireTimer(struct timer *t)
|
||||
FsmExpireTimer(void *data)
|
||||
{
|
||||
struct FsmTimer *ft = t->priv;
|
||||
struct FsmTimer *ft = data;
|
||||
#if FSM_TIMER_DEBUG
|
||||
if (ft->fi->debug)
|
||||
ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
|
||||
|
|
|
@ -190,6 +190,7 @@ int
|
|||
work_stack(struct mISDNdevice *dev)
|
||||
{
|
||||
struct mISDNstack *st = dev->D.st;
|
||||
int work = 0;
|
||||
#if 0
|
||||
#ifdef MISDN_MSG_STATS
|
||||
u64 utime, stime;
|
||||
|
@ -229,6 +230,7 @@ work_stack(struct mISDNdevice *dev)
|
|||
test_and_set_bit(mISDN_STACK_WORK,
|
||||
&st->status);
|
||||
}
|
||||
work = 1;
|
||||
#ifdef MISDN_MSG_STATS
|
||||
st->msg_cnt++;
|
||||
#endif
|
||||
|
@ -322,7 +324,7 @@ work_stack(struct mISDNdevice *dev)
|
|||
st->notify = NULL;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
return work;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -171,7 +171,7 @@ extern void init_l3(layer3_t *);
|
|||
extern void release_l3(layer3_t *);
|
||||
extern int l3_start(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 mISDNl3Free(void);
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@ extern void close_layer3(struct mlayer3 *);
|
|||
* run stack for one loop
|
||||
* 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 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 del_timer(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
|
||||
|
|
|
@ -888,7 +888,7 @@ to_l2(layer3_t *l3, struct l3_msg *l3m)
|
|||
|
||||
/* one shot */
|
||||
int
|
||||
layer3_work(struct _layer3 *l3)
|
||||
layer3_work(struct _layer3 *l3, double *misdn_timeout)
|
||||
{
|
||||
fd_set rfd;
|
||||
struct mbuffer *mb;
|
||||
|
@ -916,14 +916,14 @@ again:
|
|||
eprint("%s read timer error %s\n", __FUNCTION__, strerror(errno));
|
||||
} else {
|
||||
if (ret == sizeof(id) && id) {
|
||||
work |= expire_timer(&l3->tbase, id);
|
||||
work |= expire_timer(&l3->tbase, id, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (l3->l2inst) {
|
||||
/* 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 */
|
||||
if ((l3->l2sock && FD_ISSET(l3->l2sock, &rfd))
|
||||
|
@ -1014,7 +1014,7 @@ layer3_thread(void *arg)
|
|||
struct _layer3 *l3 = arg;
|
||||
|
||||
while(!test_bit(FLG_ABORT, &l3->ml3.options)) {
|
||||
layer3_work(l3);
|
||||
layer3_work(l3, NULL);
|
||||
if (test_bit(FLG_RUN_WAIT, &l3->ml3.options)) {
|
||||
test_and_clear_bit(FLG_RUN_WAIT, &l3->ml3.options);
|
||||
pthread_mutex_unlock(&l3->run);
|
||||
|
|
|
@ -316,12 +316,12 @@ close_layer3(struct mlayer3 *ml3)
|
|||
}
|
||||
|
||||
int
|
||||
work_layer3(struct mlayer3 *ml3)
|
||||
work_layer3(struct mlayer3 *ml3, double *misdn_timeout)
|
||||
{
|
||||
struct _layer3 *l3;
|
||||
|
||||
l3 = container_of(ml3, struct _layer3, ml3);
|
||||
return layer3_work(l3);
|
||||
return layer3_work(l3, misdn_timeout);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -106,7 +106,8 @@ del_timer(struct mtimer *mt)
|
|||
#endif
|
||||
if (mt->id) {
|
||||
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;
|
||||
}
|
||||
#ifdef DEBUG_TIMERS
|
||||
|
@ -122,11 +123,12 @@ timer_pending(struct mtimer *mt)
|
|||
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;
|
||||
double now = 0.0;
|
||||
int work = 0;
|
||||
double timeout = 0.0;
|
||||
|
||||
/* if id is < 0, then check for expired timer */
|
||||
if (id < 0) {
|
||||
|
@ -170,6 +172,17 @@ again:
|
|||
#endif
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue