aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libmsc/smpp_smsc.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/libmsc/smpp_smsc.c')
-rw-r--r--openbsc/src/libmsc/smpp_smsc.c57
1 files changed, 39 insertions, 18 deletions
diff --git a/openbsc/src/libmsc/smpp_smsc.c b/openbsc/src/libmsc/smpp_smsc.c
index 64ed2005f..048c1b802 100644
--- a/openbsc/src/libmsc/smpp_smsc.c
+++ b/openbsc/src/libmsc/smpp_smsc.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <stdint.h>
#include <errno.h>
+#include <limits.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -762,6 +763,23 @@ 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)
{
@@ -770,22 +788,27 @@ static int esme_link_read_cb(struct osmo_fd *ofd)
uint8_t *lenptr = (uint8_t *) &len;
uint8_t *cur;
struct msgb *msg;
- int rdlen;
- int rc;
+ 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) {
- LOGP(DSMPP, LOGL_ERROR, "[%s] read returned %d\n",
- esme->system_id, rc);
- } else if (rc == 0) {
- goto dead_socket;
- } else
- esme->read_idx += rc;
+ if (rc < 0)
+ LOGP(DSMPP, LOGL_ERROR, "[%s] read returned %zd (%s)\n",
+ esme->system_id, 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) {
+ LOGP(DSMPP, LOGL_ERROR, "[%s] length invalid %u\n",
+ esme->system_id, esme->read_len);
+ goto dead_socket;
+ }
+
msg = msgb_alloc(esme->read_len, "SMPP Rx");
if (!msg)
return -ENOMEM;
@@ -800,15 +823,13 @@ static int esme_link_read_cb(struct osmo_fd *ofd)
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) {
- LOGP(DSMPP, LOGL_ERROR, "[%s] read returned %d\n",
- esme->system_id, rc);
- } else if (rc == 0) {
- goto dead_socket;
- } else {
- esme->read_idx += rc;
- msgb_put(msg, rc);
- }
+ if (rc < 0)
+ LOGP(DSMPP, LOGL_ERROR, "[%s] read returned %zd (%s)\n",
+ esme->system_id, 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(esme, esme->read_msg);