Replace polling by select and timer events

This commit is contained in:
Andreas Eversberg 2023-01-21 18:11:20 +01:00
parent 3e970cbc48
commit 8c10ee4a26
21 changed files with 469 additions and 342 deletions

1
.gitignore vendored
View File

@ -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

View File

@ -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

View File

@ -5,6 +5,7 @@ SUBDIRS = \
libdebug \
libsample \
libtimer \
libselect \
libjitter \
libosmocc \
libg711 \

View File

@ -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 \

View File

@ -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)

View File

@ -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);

View File

@ -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();

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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 *);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;