aboutsummaryrefslogtreecommitdiffstats
path: root/src/libph_socket/ph_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libph_socket/ph_socket.c')
-rw-r--r--src/libph_socket/ph_socket.c339
1 files changed, 0 insertions, 339 deletions
diff --git a/src/libph_socket/ph_socket.c b/src/libph_socket/ph_socket.c
deleted file mode 100644
index 28ec30f..0000000
--- a/src/libph_socket/ph_socket.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/* PH-socket, a lightweight ISDN physical layer interface
- *
- * (C) 2022 by Andreas Eversberg <jolly@eversberg.eu>
- * All Rights Reserved
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "../libtimer/timer.h"
-#include "../libselect/select.h"
-#include "../libdebug/debug.h"
-#include "ph_socket.h"
-
-static int ph_socket_listen_cb(struct osmo_fd *ofd, unsigned int __attribute__((unused)) what);
-static int ph_socket_connect_cb(struct osmo_fd *ofd, unsigned int __attribute__((unused)) what);
-static void ph_socket_timeout_cb(void *data);
-
-static void open_connection(ph_socket_t *s)
-{
- uint8_t enable = PH_CTRL_UNBLOCK;
- int rc, flags;
-
- if (s->connect_ofd.fd > 0)
- return;
-
- LOGP(DPH, LOGL_DEBUG, "Trying to connect to PH-socket server.\n");
- rc = socket(PF_UNIX, SOCK_STREAM, 0);
- if (rc < 0) {
- LOGP(DPH, LOGL_ERROR, "Failed to create UNIX socket.\n");
- osmo_timer_schedule(&s->retry_timer, SOCKET_RETRY_TIMER, 0);
- return;
- }
- s->connect_ofd.fd = rc;
- s->connect_ofd.data = s;
- s->connect_ofd.when = BSC_FD_READ;
- s->connect_ofd.cb = ph_socket_connect_cb;
- osmo_fd_register(&s->connect_ofd);
- /* set nonblocking io, because we do multiple reads when handling read event */
- flags = fcntl(s->connect_ofd.fd, F_GETFL);
- flags |= O_NONBLOCK;
- fcntl(s->connect_ofd.fd, F_SETFL, flags);
- /* connect */
- rc = connect(s->connect_ofd.fd, (struct sockaddr *)&s->sock_address, sizeof(s->sock_address));
- if (rc < 0 && errno != EAGAIN) {
- if (!s->connect_failed)
- LOGP(DPH, LOGL_NOTICE, "Failed to connect UNIX socket, retrying...\n");
- close(s->connect_ofd.fd);
- s->connect_failed = 1;
- osmo_fd_unregister(&s->connect_ofd);
- s->connect_ofd.fd = 0;
- osmo_timer_schedule(&s->retry_timer, SOCKET_RETRY_TIMER, 0);
- return;
- }
- s->connect_failed = 0;
- LOGP(DPH, LOGL_INFO, "Connection to PH-socket server.\n");
- /* reset rx buffer */
- s->rx_header_index = 0;
- s->rx_data_index = 0;
- /* indicate established socket connection */
- s->ph_socket_rx_msg(s, 0, PH_PRIM_CTRL_IND, &enable, 1);
-}
-
-static void close_connection(ph_socket_t *s)
-{
- struct socket_msg_list *ml;
- uint8_t disable = PH_CTRL_BLOCK;
-
- if (s->connect_ofd.fd <= 0)
- return;
-
- LOGP(DPH, LOGL_INFO, "Connection from PH-socket closed.\n");
-
- /* indicate loss of socket connection */
- s->ph_socket_rx_msg(s, 0, (s->listen_ofd.fd > 0) ? PH_PRIM_CTRL_REQ : PH_PRIM_CTRL_IND, &disable, 1);
-
- osmo_fd_unregister(&s->connect_ofd);
- close(s->connect_ofd.fd);
- s->connect_ofd.fd = 0;
-
- while ((ml = s->tx_list)) {
- s->tx_list = ml->next;
- free(ml);
- }
- s->tx_list_tail = &s->tx_list;
- if (s->rx_msg) {
- free(s->rx_msg);
- s->rx_msg = NULL;
- }
-
- if (s->listen_ofd.fd <= 0) {
- /* set timer, so that retry is delayed */
- osmo_timer_schedule(&s->retry_timer, SOCKET_RETRY_TIMER, 0);
- }
-}
-
-int ph_socket_init(ph_socket_t *s, void (*ph_socket_rx_msg)(ph_socket_t *s, int channel, uint8_t prim, uint8_t *data,
- int length), void *priv, const char *socket_name, int server)
-{
- int rc;
-
- memset(s, 0, sizeof(*s));
- s->name = socket_name;
- s->ph_socket_rx_msg = ph_socket_rx_msg;
- s->priv = priv;
- s->tx_list_tail = &s->tx_list;
-
- memset(&s->sock_address, 0, sizeof(s->sock_address));
- s->sock_address.sun_family = AF_UNIX;
- strcpy(s->sock_address.sun_path+1, socket_name);
-
- s->retry_timer.data = s;
- s->retry_timer.cb = ph_socket_timeout_cb;
-
- if (server) {
- rc = socket(PF_UNIX, SOCK_STREAM, 0);
- if (rc < 0) {
- LOGP(DPH, LOGL_ERROR, "Failed to create UNIX socket.\n");
- return rc;
- }
- s->listen_ofd.fd = rc;
- s->listen_ofd.data = s;
- s->listen_ofd.when = BSC_FD_READ;
- s->listen_ofd.cb = ph_socket_listen_cb;
- osmo_fd_register(&s->listen_ofd);
-
- rc = bind(s->listen_ofd.fd, (struct sockaddr *)(&s->sock_address), sizeof(s->sock_address));
- if (rc < 0) {
- LOGP(DPH, LOGL_ERROR, "Failed to bind UNIX socket with path '%s' (errno = %d (%s)).\n",
- s->name, errno, strerror(errno));
- return rc;
- }
-
- rc = listen(s->listen_ofd.fd, 1);
- if (rc < 0) {
- LOGP(DPH, LOGL_ERROR, "Failed to listen to UNIX socket with path '%s' (errno = %d (%s)).\n",
- s->name, errno, strerror(errno));
- return rc;
- }
- } else
- open_connection(s);
-
- LOGP(DPH, LOGL_INFO, "Created PH-socket at '%s'.\n", s->name);
-
- return 0;
-}
-
-void ph_socket_exit(ph_socket_t *s)
-{
- LOGP(DPH, LOGL_INFO, "Destroyed PH-socket.\n");
-
- close_connection(s);
- if (s->listen_ofd.fd > 0) {
- osmo_fd_unregister(&s->listen_ofd);
- close(s->listen_ofd.fd);
- s->listen_ofd.fd = 0;
- }
-
- if (osmo_timer_pending(&s->retry_timer))
- osmo_timer_del(&s->retry_timer);
-}
-
-static int ph_socket_listen_cb(struct osmo_fd *ofd, unsigned int __attribute__((unused)) what)
-{
- ph_socket_t *s = ofd->data;
- struct sockaddr_un sock_address;
- uint8_t enable = PH_CTRL_UNBLOCK;
- int rc, flags;
-
- socklen_t sock_len = sizeof(sock_address);
- /* see if there is an incoming connection */
- rc = accept(s->listen_ofd.fd, (struct sockaddr *)&sock_address, &sock_len);
- if (rc > 0) {
- if (s->connect_ofd.fd > 0) {
- LOGP(DPH, LOGL_ERROR, "Rejecting incoming connection, because we already have a client "
- "connected!\n");
- close(rc);
- } else {
- LOGP(DPH, LOGL_INFO, "Connection from PH-socket client.\n");
- s->connect_ofd.fd = rc;
- s->connect_ofd.data = s;
- s->connect_ofd.when = BSC_FD_READ;
- s->connect_ofd.cb = ph_socket_connect_cb;
- osmo_fd_register(&s->connect_ofd);
- /* set nonblocking io, because we do multiple reads when handling read event */
- flags = fcntl(s->connect_ofd.fd, F_GETFL);
- flags |= O_NONBLOCK;
- fcntl(s->connect_ofd.fd, F_SETFL, flags);
- /* reset rx buffer */
- s->rx_header_index = 0;
- s->rx_data_index = 0;
- /* indicate established socket connection */
- s->ph_socket_rx_msg(s, 0, PH_PRIM_CTRL_REQ, &enable, 1);
- }
- }
-
- return 0;
-}
-
-static int ph_socket_connect_cb(struct osmo_fd *ofd, unsigned __attribute__((unused)) int what)
-{
- ph_socket_t *s = ofd->data;
- int rc;
-
- if (what & BSC_FD_READ) {
-rx_again:
- if (!s->rx_msg)
- s->rx_msg = calloc(1, sizeof(*s->rx_msg));
- if (s->rx_header_index < (int)sizeof(s->rx_msg->msg.header)) {
- /* read header until complete */
- rc = recv(s->connect_ofd.fd, ((uint8_t *)&s->rx_msg->msg.header) + s->rx_header_index,
- sizeof(s->rx_msg->msg.header) - s->rx_header_index, 0);
- if (rc > 0) {
- s->rx_header_index += rc;
- goto rx_again;
- } else if (rc == 0 || errno != EAGAIN) {
- close_connection(s);
- return 0;
- }
- } else if (s->rx_data_index < s->rx_msg->msg.header.length) {
- /* read data until complete */
- rc = recv(s->connect_ofd.fd, s->rx_msg->msg.data + s->rx_data_index,
- s->rx_msg->msg.header.length - s->rx_data_index, 0);
- if (rc > 0) {
- s->rx_data_index += rc;
- goto rx_again;
- } else if (rc == 0 || errno != EAGAIN) {
- close_connection(s);
- return 0;
- }
- } else {
- /* process and free message */
- if (s->rx_msg->msg.header.prim != PH_PRIM_DATA_REQ
- && s->rx_msg->msg.header.prim != PH_PRIM_DATA_IND
- && s->rx_msg->msg.header.prim != PH_PRIM_DATA_CNF) {
- LOGP(DPH, LOGL_DEBUG, "message 0x%02x channel %d from socket\n",
- s->rx_msg->msg.header.prim, s->rx_msg->msg.header.channel);
- if (s->rx_msg->msg.header.length)
- LOGP(DPH, LOGL_DEBUG, " -> data:%s\n", osmo_hexdump(s->rx_msg->msg.data,
- s->rx_msg->msg.header.length));
- }
- s->ph_socket_rx_msg(s, s->rx_msg->msg.header.channel, s->rx_msg->msg.header.prim,
- s->rx_msg->msg.data, s->rx_msg->msg.header.length);
- free(s->rx_msg);
- s->rx_msg = NULL;
- /* reset rx buffer */
- s->rx_header_index = 0;
- s->rx_data_index = 0;
- }
- }
-
- if (what & BSC_FD_WRITE) {
- if (s->tx_list) {
- /* some frame in tx list, so try sending it */
- rc = send(s->connect_ofd.fd, ((uint8_t *)&s->tx_list->msg.header),
- sizeof(s->tx_list->msg.header) + s->tx_list->msg.header.length, 0);
- if (rc > 0) {
- struct socket_msg_list *ml;
- if (rc != (int)sizeof(s->tx_list->msg.header) + s->tx_list->msg.header.length) {
- LOGP(DPH, LOGL_ERROR, "Short write, please fix handling!\n");
- }
- /* remove list entry */
- ml = s->tx_list;
- s->tx_list = ml->next;
- if (s->tx_list == NULL)
- s->tx_list_tail = &s->tx_list;
- free(ml);
- } else if (rc == 0 || errno != EAGAIN) {
- close_connection(s);
- return 0;
- }
- } else
- s->connect_ofd.when &= ~BSC_FD_WRITE;
- }
-
- return 0;
-}
-
-static void ph_socket_timeout_cb(void *data)
-{
- ph_socket_t *s = data;
-
- open_connection(s);
-}
-
-void ph_socket_tx_msg(ph_socket_t *s, int channel, uint8_t prim, uint8_t *data, int length)
-{
- struct socket_msg_list *tx_msg;
-
- if (prim != PH_PRIM_DATA_REQ
- && prim != PH_PRIM_DATA_IND
- && prim != PH_PRIM_DATA_CNF) {
- LOGP(DPH, LOGL_DEBUG, "message 0x%02x channel %d to socket\n", prim, channel);
- if (length)
- LOGP(DPH, LOGL_DEBUG, " -> data:%s\n", osmo_hexdump(data, length));
- }
-
- if (length > (int)sizeof(tx_msg->msg.data)) {
- LOGP(DPH, LOGL_NOTICE, "Frame from HDLC process too large for socket, dropping!\n");
- return;
- }
-
- if (s->connect_ofd.fd <= 0) {
- LOGP(DPH, LOGL_NOTICE, "Dropping message for socket, socket is closed!\n");
- return;
- }
-
- tx_msg = calloc(1, sizeof(*tx_msg));
- tx_msg->msg.header.channel = channel;
- tx_msg->msg.header.prim = prim;
- if (length) {
- tx_msg->msg.header.length = length;
- memcpy(tx_msg->msg.data, data, length);
- }
- /* move message to list */
- *s->tx_list_tail = tx_msg;
- s->tx_list_tail = &tx_msg->next;
- s->connect_ofd.when |= BSC_FD_WRITE;
-}
-