diff options
Diffstat (limited to 'src/libgsmd')
-rw-r--r-- | src/libgsmd/lgsm_internals.h | 9 | ||||
-rw-r--r-- | src/libgsmd/libgsmd.c | 45 | ||||
-rw-r--r-- | src/libgsmd/libgsmd_passthrough.c | 65 |
3 files changed, 117 insertions, 2 deletions
diff --git a/src/libgsmd/lgsm_internals.h b/src/libgsmd/lgsm_internals.h index 66fd5fe..0601959 100644 --- a/src/libgsmd/lgsm_internals.h +++ b/src/libgsmd/lgsm_internals.h @@ -1,4 +1,13 @@ +#ifndef _LGSM_INTERNALS_H +#define _LGSM_INTERNALS_H + +#include <gsmd/usock.h> + +typedef int lgsm_msg_handler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh); struct lgsm_handle { int fd; + lgsm_msg_handler *handler[__NUM_GSMD_MSGS]; }; + +#endif /* _LGSM_INTERNALS_H */ diff --git a/src/libgsmd/libgsmd.c b/src/libgsmd/libgsmd.c index 77b8499..104a8b3 100644 --- a/src/libgsmd/libgsmd.c +++ b/src/libgsmd/libgsmd.c @@ -36,7 +36,6 @@ static int lgsm_get_packet(struct lgsm_handle *lh) return 0; } - static int lgsm_open_backend(struct lgsm_handle *lh, const char *device) { int rc; @@ -52,7 +51,6 @@ static int lgsm_open_backend(struct lgsm_handle *lh, const char *device) memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; memcpy(sun.sun_path, GSMD_UNIX_SOCKET, sizeof(GSMD_UNIX_SOCKET)); - printf("sizeof(GSMD_UNIX_SOCKET) = %u\n", sizeof(GSMD_UNIX_SOCKET)); rc = connect(lh->fd, (struct sockaddr *)&sun, sizeof(sun)); if (rc < 0) { @@ -66,6 +64,49 @@ static int lgsm_open_backend(struct lgsm_handle *lh, const char *device) return 0; } +/* handle a packet that was received on the gsmd socket */ +int lgsm_handle_packet(struct lgsm_handle *lh, char *buf, int len) +{ + struct gsmd_msg_hdr *gmh = (struct gsmd_msg_hdr *)buf; + if (len < sizeof(*gmh)) + return -EINVAL; + + if (len - sizeof(*gmh) < gmh->len) + return -EINVAL; + + if (gmh->msg_type >= __NUM_GSMD_MSGS) + return -EINVAL; + + return lh->handler[gmh->msg_type](lh, gmh); +} + +/* blocking read and processing of packets until packet matching 'id' is found */ +int lgsm_blocking_wait_packet(struct lgsm_handle *lh, u_int16_t id, + struct gsmd_msg_hdr *gmh, int rlen) +{ + int rc; + fd_set readset; + + FD_ZERO(&readset); + + while (1) { + FD_SET(lh->fd, &readset); + rc = select(lh->fd+1, &readset, NULL, NULL, NULL); + if (rc <= 0) + return rc; + + rc = read(lh->fd, (char *)gmh, rlen); + if (rc <= 0) + return rc; + + if (gmh->id == id) { + /* we've found the matching packet, return to calling function */ + return rc; + } else + rc = lgsm_handle_packet(lh, (char *)gmh, rc); + } +} + int lgsm_fd(struct lgsm_handle *lh) { return lh->fd; diff --git a/src/libgsmd/libgsmd_passthrough.c b/src/libgsmd/libgsmd_passthrough.c new file mode 100644 index 0000000..45ce066 --- /dev/null +++ b/src/libgsmd/libgsmd_passthrough.c @@ -0,0 +1,65 @@ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <sys/types.h> + +#include <gsmd/usock.h> +#include <libgsmd/libgsmd.h> + +#include "lgsm_internals.h" + +static u_int16_t next_msg_id; + +static int lgsm_send(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh) +{ + gmh->id = next_msg_id++; + return send(lh->fd, (char *) gmh, sizeof(*gmh) + gmh->len); +} + +#define PT_BUF_SIZE 1024 +static char passthrough_buf[sizeof(struct gsmd_msg_hdr)+PT_BUF_SIZE]; +static char passthrough_rbuf[sizeof(struct gsmd_msg_hdr)+PT_BUF_SIZE]; + +int lgsm_passthrough(struct lgsm_handle *lh, const char *tx, char *rx, unsigned int *rx_len) +{ + struct gsmd_msg_hdr *gmh = (struct gsmd_msg_hdr *)passthrough_buf; + struct gsmd_msg_hdr *rgmh = (struct gsmd_msg_hdr *)passthrough_rbuf; + char *tx_buf = (char *)gmh + sizeof(*gmh); + char *rx_buf = (char *)rgmh + sizeof(*rgmh); + int len = strlen(tx); + int rc; + + if (len > PT_BUF_SIZE) + return -EINVAL; + + gmh->version = GSMD_PROTO_VERSION; + gmh->msg_type = GSMD_MSG_PASSTHROUGH; + gmh->msg_subtype = GSMD_PASSTHROUGH_REQUEST; + gmh->len = len; + strcpy(tx_buf, tx); + + rc = lgsm_send(lh, gmh); + if (rc < len+sizeof(*gmh)) + return rc; + + /* since we synchronously want to wait for a response, we need to _internally_ loop over + * incoming packets and call the callbacks for intermediate messages (if applicable) */ + rc = lgsm_blocking_wait_packet(lh, gmh->id, passthrough_rbuf, sizeof(passthrough_rbuf)); + if (rc <= 0) + return rc; + + if (rc < sizeof(*rgmh)) + return -EINVAL; + + if (rc < sizeof(*rgmh) + rgmh->len) + return -EINVAL; + + /* FIXME: make sure rx_buf is zero-terminated */ + strcpy(rx, rx_buf); + *rx_len = rgmh->len; + + return rx_len; +} |