aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax <msuraev@sysmocom.de>2022-07-30 17:55:47 +0700
committerMax <msuraev@sysmocom.de>2022-07-30 18:41:14 +0700
commit6c4f23df5e70e3499965f80c0277deb3a0d54f36 (patch)
treed51db8039b6bfb5a2a03395348d91220e068e5b0
parentf80621540f3638e9bef7c54df6e0e9c00d95e511 (diff)
SMPP: move read/write callbacks to libsmpputil
-rw-r--r--include/osmocom/msc/smpp.h21
-rw-r--r--src/libmsc/smpp_smsc.c105
-rw-r--r--src/libmsc/smpp_utils.c92
-rw-r--r--src/utils/smpp_mirror.c88
4 files changed, 138 insertions, 168 deletions
diff --git a/include/osmocom/msc/smpp.h b/include/osmocom/msc/smpp.h
index b2c711421..c30812f82 100644
--- a/include/osmocom/msc/smpp.h
+++ b/include/osmocom/msc/smpp.h
@@ -47,6 +47,27 @@ struct esme {
(resp)->command_status = ESME_ROK; \
(resp)->sequence_number = (req)->sequence_number; }
+/* This macro should be called after a call to read() in the read_cb of an
+ * osmo_fd to properly check for errors.
+ * rc is the return value of read, err_label is the label to jump to in case of
+ * an error. The code there should handle closing the connection.
+ * FIXME: This code should go in libosmocore utils.h so it can be used by other
+ * projects as well.
+ * */
+#define OSMO_FD_CHECK_READ(rc, err_label) do { \
+ if (rc < 0) { \
+ /* EINTR is a non-fatal error, just try again */ \
+ if (errno == EINTR) \
+ return 0; \
+ goto err_label; \
+ } else if (rc == 0) { \
+ goto err_label; \
+ } } while (0)
+
uint32_t smpp_msgb_cmdid(struct msgb *msg);
uint32_t esme_inc_seq_nr(struct esme *esme);
+void esme_read_state_reset(struct esme *esme);
+void esme_queue_reset(struct esme *esme);
+int esme_write_callback(struct esme *esme, int fd, struct msgb *msg);
+int esme_read_callback(struct esme *esme, int fd);
int pack_and_send(struct esme *esme, uint32_t type, void *ptr);
diff --git a/src/libmsc/smpp_smsc.c b/src/libmsc/smpp_smsc.c
index 4f7854f0a..604156bd7 100644
--- a/src/libmsc/smpp_smsc.c
+++ b/src/libmsc/smpp_smsc.c
@@ -161,9 +161,7 @@ void smpp_acl_delete(struct osmo_smpp_acl *acl)
/* kill any active ESMEs */
if (acl->esme) {
struct esme *esme = acl->esme->esme;
- osmo_fd_unregister(&esme->wqueue.bfd);
- close(esme->wqueue.bfd.fd);
- esme->wqueue.bfd.fd = -1;
+ esme_queue_reset(esme);
acl->esme = NULL;
smpp_esme_put(acl->esme);
}
@@ -241,8 +239,7 @@ static void esme_destroy(struct osmo_esme *esme)
{
osmo_wqueue_clear(&esme->esme->wqueue);
if (esme->esme->wqueue.bfd.fd >= 0) {
- osmo_fd_unregister(&esme->esme->wqueue.bfd);
- close(esme->esme->wqueue.bfd.fd);
+ esme_queue_reset(esme->esme);
}
smpp_cmd_flush_pending(esme);
llist_del(&esme->list);
@@ -722,113 +719,41 @@ static int smpp_pdu_rx(struct osmo_esme *esme, struct msgb *msg __uses)
return rc;
}
-/* This macro should be called after a call to read() in the read_cb of an
- * osmo_fd to properly check for errors.
- * rc is the return value of read, err_label is the label to jump to in case of
- * an error. The code there should handle closing the connection.
- * FIXME: This code should go in libosmocore utils.h so it can be used by other
- * projects as well.
- * */
-#define OSMO_FD_CHECK_READ(rc, err_label) \
- if (rc < 0) { \
- /* EINTR is a non-fatal error, just try again */ \
- if (errno == EINTR) \
- return 0; \
- goto err_label; \
- } else if (rc == 0) { \
- goto err_label; \
- }
-
/* !\brief call-back when per-ESME TCP socket has some data to be read */
static int esme_link_read_cb(struct osmo_fd *ofd)
{
struct osmo_esme *e = ofd->data;
struct esme *esme = e->esme;
- uint32_t len;
- uint8_t *lenptr = (uint8_t *) &len;
- uint8_t *cur;
- struct msgb *msg;
- ssize_t rdlen, rc;
-
- switch (esme->read_state) {
- case READ_ST_IN_LEN:
- rdlen = sizeof(uint32_t) - esme->read_idx;
- rc = read(ofd->fd, lenptr + esme->read_idx, rdlen);
- if (rc < 0)
- LOGPESME(esme, LOGL_ERROR, "read returned %zd (%s)\n", rc, strerror(errno));
- OSMO_FD_CHECK_READ(rc, dead_socket);
-
- esme->read_idx += rc;
-
- if (esme->read_idx >= sizeof(uint32_t)) {
- esme->read_len = ntohl(len);
- if (esme->read_len < 8 || esme->read_len > UINT16_MAX) {
- LOGPESME(esme, LOGL_ERROR, "length invalid %u\n", esme->read_len);
- goto dead_socket;
- }
+ int rc = esme_read_callback(esme, ofd->fd);
- msg = msgb_alloc(esme->read_len, "SMPP Rx");
- if (!msg)
- return -ENOMEM;
- esme->read_msg = msg;
- cur = msgb_put(msg, sizeof(uint32_t));
- memcpy(cur, lenptr, sizeof(uint32_t));
- esme->read_state = READ_ST_IN_MSG;
- esme->read_idx = sizeof(uint32_t);
- }
+ switch (rc) {
+ case 1:
+ rc = smpp_pdu_rx(e, esme->read_msg);
+ esme_read_state_reset(esme);
break;
- case READ_ST_IN_MSG:
- msg = esme->read_msg;
- rdlen = esme->read_len - esme->read_idx;
- rc = read(ofd->fd, msg->tail, OSMO_MIN(rdlen, msgb_tailroom(msg)));
- if (rc < 0)
- LOGPESME(esme, LOGL_ERROR, "read returned %zd (%s)\n",
- rc, strerror(errno));
- OSMO_FD_CHECK_READ(rc, dead_socket);
-
- esme->read_idx += rc;
- msgb_put(msg, rc);
-
- if (esme->read_idx >= esme->read_len) {
- rc = smpp_pdu_rx(e, esme->read_msg);
- msgb_free(esme->read_msg);
- esme->read_msg = NULL;
- esme->read_idx = 0;
- esme->read_len = 0;
- esme->read_state = READ_ST_IN_LEN;
- }
+ case -EBADF:
+ if (e->acl)
+ e->acl->esme = NULL;
+ smpp_esme_put(e);
break;
+ default:
+ return rc;
}
return 0;
-dead_socket:
- msgb_free(esme->read_msg);
- osmo_fd_unregister(&esme->wqueue.bfd);
- close(esme->wqueue.bfd.fd);
- esme->wqueue.bfd.fd = -1;
- if (e->acl)
- e->acl->esme = NULL;
- smpp_esme_put(e);
-
- return -EBADF;
}
/* call-back of write queue once it wishes to write a message to the socket */
static int esme_link_write_cb(struct osmo_fd *ofd, struct msgb *msg)
{
struct osmo_esme *esme = ofd->data;
- int rc;
+ int rc = esme_write_callback(esme->esme, ofd->fd, msg);
- rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));
if (rc == 0) {
- osmo_fd_unregister(&esme->esme->wqueue.bfd);
- close(esme->esme->wqueue.bfd.fd);
- esme->esme->wqueue.bfd.fd = -1;
if (esme->acl)
esme->acl->esme = NULL;
smpp_esme_put(esme);
- } else if (rc < msgb_length(msg)) {
- LOGPESME(esme->esme, LOGL_ERROR, "Short write\n");
+ } else if (rc == -1) {
return -1;
}
diff --git a/src/libmsc/smpp_utils.c b/src/libmsc/smpp_utils.c
index e70ea0585..adf1206c6 100644
--- a/src/libmsc/smpp_utils.c
+++ b/src/libmsc/smpp_utils.c
@@ -21,6 +21,7 @@
#include <time.h>
#include <errno.h>
+#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
@@ -50,6 +51,97 @@ uint32_t esme_inc_seq_nr(struct esme *esme)
return esme->own_seq_nr;
}
+void esme_read_state_reset(struct esme *esme)
+{
+ if (esme->read_msg) {
+ msgb_free(esme->read_msg);
+ esme->read_msg = NULL;
+ }
+ esme->read_idx = 0;
+ esme->read_len = 0;
+ esme->read_state = READ_ST_IN_LEN;
+}
+
+void esme_queue_reset(struct esme *esme)
+{
+ osmo_fd_unregister(&esme->wqueue.bfd);
+ close(esme->wqueue.bfd.fd);
+ esme->wqueue.bfd.fd = -1;
+}
+
+/* !\brief call-back when per-ESME TCP socket has some data to be read */
+int esme_read_callback(struct esme *esme, int fd)
+{
+ uint32_t len;
+ uint8_t *lenptr = (uint8_t *) &len;
+ uint8_t *cur;
+ struct msgb *msg;
+ ssize_t rdlen, rc;
+
+ switch (esme->read_state) {
+ case READ_ST_IN_LEN:
+ rdlen = sizeof(uint32_t) - esme->read_idx;
+ rc = read(fd, lenptr + esme->read_idx, rdlen);
+ if (rc < 0)
+ LOGPESME(esme, LOGL_ERROR, "read returned %zd (%s)\n", rc, strerror(errno));
+ OSMO_FD_CHECK_READ(rc, dead_socket);
+
+ esme->read_idx += rc;
+
+ if (esme->read_idx >= sizeof(uint32_t)) {
+ esme->read_len = ntohl(len);
+ if (esme->read_len < 8 || esme->read_len > UINT16_MAX) {
+ LOGPESME(esme, LOGL_ERROR, "length invalid %u\n", esme->read_len);
+ goto dead_socket;
+ }
+
+ msg = msgb_alloc(esme->read_len, "SMPP Rx");
+ if (!msg)
+ return -ENOMEM;
+ esme->read_msg = msg;
+ cur = msgb_put(msg, sizeof(uint32_t));
+ memcpy(cur, lenptr, sizeof(uint32_t));
+ esme->read_state = READ_ST_IN_MSG;
+ esme->read_idx = sizeof(uint32_t);
+ }
+ break;
+ case READ_ST_IN_MSG:
+ msg = esme->read_msg;
+ rdlen = esme->read_len - esme->read_idx;
+ rc = read(fd, msg->tail, OSMO_MIN(rdlen, msgb_tailroom(msg)));
+ if (rc < 0)
+ LOGPESME(esme, LOGL_ERROR, "read returned %zd (%s)\n", rc, strerror(errno));
+ OSMO_FD_CHECK_READ(rc, dead_socket);
+
+ esme->read_idx += rc;
+ msgb_put(msg, rc);
+
+ if (esme->read_idx >= esme->read_len)
+ return 1;
+ break;
+ }
+
+ return 0;
+dead_socket:
+ esme_queue_reset(esme);
+ esme_read_state_reset(esme);
+ return -EBADF;
+}
+
+int esme_write_callback(struct esme *esme, int fd, struct msgb *msg)
+{
+ int rc = write(fd, msgb_data(msg), msgb_length(msg));
+ if (rc == 0) {
+ esme_queue_reset(esme);
+ return 0;
+ } else if (rc < msgb_length(msg)) {
+ LOGPESME(esme, LOGL_ERROR, "Short write\n");
+ return -1;
+ }
+
+ return rc;
+}
+
/*! \brief pack a libsmpp34 data strcutrure and send it to the ESME */
int pack_and_send(struct esme *esme, uint32_t type, void *ptr)
{
diff --git a/src/utils/smpp_mirror.c b/src/utils/smpp_mirror.c
index a7a7e61d0..9dc6dd689 100644
--- a/src/utils/smpp_mirror.c
+++ b/src/utils/smpp_mirror.c
@@ -143,98 +143,30 @@ static int smpp_pdu_rx(struct esme *esme, struct msgb *msg)
return rc;
}
-static void esme_read_state_reset(struct esme *esme)
-{
- esme->read_msg = NULL;
- esme->read_idx = 0;
- esme->read_len = 0;
- esme->read_state = READ_ST_IN_LEN;
-}
-
-/* FIXME: merge with smpp_smsc.c */
static int esme_read_cb(struct osmo_fd *ofd)
{
struct esme *esme = ofd->data;
- uint32_t len;
- uint8_t *lenptr = (uint8_t *) &len;
- uint8_t *cur;
- struct msgb *msg;
- int rdlen;
- int rc;
+ int rc = esme_read_callback(esme, ofd->fd);
- switch (esme->read_state) {
- case READ_ST_IN_LEN:
- rdlen = sizeof(uint32_t) - esme->read_idx;
- rc = read(ofd->fd, lenptr + esme->read_idx, rdlen);
- if (rc < 0) {
- LOGPESME(esme, LOGL_ERROR, "read returned %d\n", rc);
- } else if (rc == 0) {
- goto dead_socket;
- } else
- esme->read_idx += rc;
- if (esme->read_idx >= sizeof(uint32_t)) {
- esme->read_len = ntohl(len);
- if (esme->read_len > 65535) {
- /* unrealistic */
- goto dead_socket;
- }
- msg = msgb_alloc(esme->read_len, "SMPP Rx");
- if (!msg)
- return -ENOMEM;
- esme->read_msg = msg;
- cur = msgb_put(msg, sizeof(uint32_t));
- memcpy(cur, lenptr, sizeof(uint32_t));
- esme->read_state = READ_ST_IN_MSG;
- esme->read_idx = sizeof(uint32_t);
- }
+ switch (rc) {
+ case 1:
+ rc = smpp_pdu_rx(esme, esme->read_msg);
+ esme_read_state_reset(esme);
break;
- case READ_ST_IN_MSG:
- msg = esme->read_msg;
- rdlen = esme->read_len - esme->read_idx;
- rc = read(ofd->fd, msg->tail, OSMO_MIN(rdlen, msgb_tailroom(msg)));
- if (rc < 0) {
- LOGPESME(esme, LOGL_ERROR, "read returned %d\n", rc);
- } else if (rc == 0) {
- goto dead_socket;
- } else {
- esme->read_idx += rc;
- msgb_put(msg, rc);
- }
-
- if (esme->read_idx >= esme->read_len) {
- rc = smpp_pdu_rx(esme, esme->read_msg);
- esme_read_state_reset(esme);
- }
+ case -EBADF:
+ exit(2342);
break;
+ default:
+ return rc;
}
return 0;
-dead_socket:
- msgb_free(esme->read_msg);
- osmo_fd_unregister(&esme->wqueue.bfd);
- close(esme->wqueue.bfd.fd);
- esme->wqueue.bfd.fd = -1;
- esme_read_state_reset(esme);
- exit(2342);
-
- return 0;
}
static int esme_write_cb(struct osmo_fd *ofd, struct msgb *msg)
{
- struct esme *esme = ofd->data;
- int rc;
-
- rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));
- if (rc == 0) {
- osmo_fd_unregister(&esme->wqueue.bfd);
- close(esme->wqueue.bfd.fd);
- esme->wqueue.bfd.fd = -1;
+ if (esme_write_callback(ofd->data, ofd->fd, msg) == 0)
exit(99);
- } else if (rc < msgb_length(msg)) {
- LOGPESME(esme, LOGL_ERROR, "Short write\n");
- return 0;
- }
return 0;
}