diff --git a/.gitignore b/.gitignore index 48dec50..6dfb660 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/configure.ac b/configure.ac index a7b8f30..8383c2e 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index a6c9d87..464280a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,6 +5,7 @@ SUBDIRS = \ libdebug \ libsample \ libtimer \ + libselect \ libjitter \ libosmocc \ libg711 \ diff --git a/src/isdn/Makefile.am b/src/isdn/Makefile.am index 564dc82..e67590a 100644 --- a/src/isdn/Makefile.am +++ b/src/isdn/Makefile.am @@ -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 \ diff --git a/src/isdn/bridge.c b/src/isdn/bridge.c index eb0d5c8..d481bb9 100644 --- a/src/isdn/bridge.c +++ b/src/isdn/bridge.c @@ -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) diff --git a/src/isdn/bridge.h b/src/isdn/bridge.h index c2cef5c..b16e7fb 100644 --- a/src/isdn/bridge.h +++ b/src/isdn/bridge.h @@ -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); diff --git a/src/isdn/dss1.c b/src/isdn/dss1.c index 169fde2..d575df1 100644 --- a/src/isdn/dss1.c +++ b/src/isdn/dss1.c @@ -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(); diff --git a/src/isdn/isdn.c b/src/isdn/isdn.c index bfd2c2b..5076c6b 100644 --- a/src/isdn/isdn.c +++ b/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; - - case MPH_DEACTIVATE_IND: - if (isdn_ep->l1link != 0) { - PDEBUG(DISDN, DEBUG_INFO, "layer 1 becomes inactive\n"); - isdn_ep->l1link = 0; - } - break; + if (!mb) + return 0; - 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); +} + + diff --git a/src/isdn/isdn.h b/src/isdn/isdn.h index 8fe2ad4..5ca723e 100644 --- a/src/isdn/isdn.h +++ b/src/isdn/isdn.h @@ -1,6 +1,7 @@ #include #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); diff --git a/src/isdn/main.c b/src/isdn/main.c index 98f0b9d..2f4ea5d 100644 --- a/src/isdn/main.c +++ b/src/isdn/main.c @@ -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); @@ -459,7 +451,7 @@ int main(int argc, char *argv[]) schedp.sched_priority = 0; sched_setscheduler(0, SCHED_OTHER, &schedp); } - + error: if (isdn_ep) { osmo_cc_delete(&isdn_ep->cc_ep); diff --git a/src/isdn/ph_driver.c b/src/isdn/ph_driver.c index 06fb187..7daed8a 100644 --- a/src/isdn/ph_driver.c +++ b/src/isdn/ph_driver.c @@ -20,6 +20,9 @@ #include #include +#include +#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 */ diff --git a/src/libmisdn/core.c b/src/libmisdn/core.c index 618004d..8c7d8ba 100644 --- a/src/libmisdn/core.c +++ b/src/libmisdn/core.c @@ -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); diff --git a/src/libmisdn/core.h b/src/libmisdn/core.h index c5c3ccb..94fe16f 100644 --- a/src/libmisdn/core.h +++ b/src/libmisdn/core.h @@ -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 diff --git a/src/libmisdn/fsm.c b/src/libmisdn/fsm.c index ac29e47..e24ca4f 100644 --- a/src/libmisdn/fsm.c +++ b/src/libmisdn/fsm.c @@ -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); diff --git a/src/libmisdn/stack.c b/src/libmisdn/stack.c index a906f89..825267a 100644 --- a/src/libmisdn/stack.c +++ b/src/libmisdn/stack.c @@ -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 diff --git a/src/libmisdnuser/include/layer3.h b/src/libmisdnuser/include/layer3.h index 840fb5d..a25c0d5 100644 --- a/src/libmisdnuser/include/layer3.h +++ b/src/libmisdnuser/include/layer3.h @@ -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); diff --git a/src/libmisdnuser/include/mISDN/mlayer3.h b/src/libmisdnuser/include/mISDN/mlayer3.h index 9484300..6d67802 100644 --- a/src/libmisdnuser/include/mISDN/mlayer3.h +++ b/src/libmisdnuser/include/mISDN/mlayer3.h @@ -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 *); diff --git a/src/libmisdnuser/include/mtimer.h b/src/libmisdnuser/include/mtimer.h index 48d0ef5..f966285 100644 --- a/src/libmisdnuser/include/mtimer.h +++ b/src/libmisdnuser/include/mtimer.h @@ -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 diff --git a/src/libmisdnuser/layer3/layer3.c b/src/libmisdnuser/layer3/layer3.c index a1d9399..8519d0a 100644 --- a/src/libmisdnuser/layer3/layer3.c +++ b/src/libmisdnuser/layer3/layer3.c @@ -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); diff --git a/src/libmisdnuser/layer3/mlayer3.c b/src/libmisdnuser/layer3/mlayer3.c index d3cdc37..be22a94 100755 --- a/src/libmisdnuser/layer3/mlayer3.c +++ b/src/libmisdnuser/layer3/mlayer3.c @@ -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 diff --git a/src/libmisdnuser/misc/mtimer.c b/src/libmisdnuser/misc/mtimer.c index eae1be5..c163a91 100644 --- a/src/libmisdnuser/misc/mtimer.c +++ b/src/libmisdnuser/misc/mtimer.c @@ -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;