SMPP: move read/write callbacks to libsmpputil
Related: OS#5568 Change-Id: I875eb5249004d3a960aee46c5099592d18fcaa76
This commit is contained in:
parent
8e896a9e5b
commit
f80a2ef21b
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <osmocom/msc/gsm_data.h>
|
#include <osmocom/msc/gsm_data.h>
|
||||||
|
|
||||||
/* Length limits according to SMPP 3.4 spec including NUL-byte: */
|
/* Length limits according to SMPP 3.4 spec including NUL-byte: */
|
||||||
|
@ -46,9 +47,30 @@ struct esme {
|
||||||
(resp)->command_status = ESME_ROK; \
|
(resp)->command_status = ESME_ROK; \
|
||||||
(resp)->sequence_number = (req)->sequence_number; }
|
(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)
|
||||||
|
|
||||||
void esme_init(struct esme *esme);
|
void esme_init(struct esme *esme);
|
||||||
uint32_t smpp_msgb_cmdid(struct msgb *msg);
|
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);
|
||||||
uint32_t esme_inc_seq_nr(struct esme *esme);
|
uint32_t esme_inc_seq_nr(struct esme *esme);
|
||||||
|
uint32_t smpp_msgb_cmdid(struct msgb *msg);
|
||||||
int pack_and_send(struct esme *esme, uint32_t type, void *ptr);
|
int pack_and_send(struct esme *esme, uint32_t type, void *ptr);
|
||||||
int smpp_openbsc_alloc_init(void *ctx);
|
int smpp_openbsc_alloc_init(void *ctx);
|
||||||
int smpp_openbsc_start(struct gsm_network *net);
|
int smpp_openbsc_start(struct gsm_network *net);
|
||||||
|
|
|
@ -160,9 +160,7 @@ void smpp_acl_delete(struct osmo_smpp_acl *acl)
|
||||||
/* kill any active ESMEs */
|
/* kill any active ESMEs */
|
||||||
if (acl->esme) {
|
if (acl->esme) {
|
||||||
struct esme *esme = acl->esme->esme;
|
struct esme *esme = acl->esme->esme;
|
||||||
osmo_fd_unregister(&esme->wqueue.bfd);
|
esme_queue_reset(esme);
|
||||||
close(esme->wqueue.bfd.fd);
|
|
||||||
esme->wqueue.bfd.fd = -1;
|
|
||||||
acl->esme = NULL;
|
acl->esme = NULL;
|
||||||
smpp_esme_put(acl->esme);
|
smpp_esme_put(acl->esme);
|
||||||
}
|
}
|
||||||
|
@ -240,8 +238,7 @@ static void esme_destroy(struct osmo_esme *esme)
|
||||||
{
|
{
|
||||||
osmo_wqueue_clear(&esme->esme->wqueue);
|
osmo_wqueue_clear(&esme->esme->wqueue);
|
||||||
if (esme->esme->wqueue.bfd.fd >= 0) {
|
if (esme->esme->wqueue.bfd.fd >= 0) {
|
||||||
osmo_fd_unregister(&esme->esme->wqueue.bfd);
|
esme_queue_reset(esme->esme);
|
||||||
close(esme->esme->wqueue.bfd.fd);
|
|
||||||
}
|
}
|
||||||
smpp_cmd_flush_pending(esme);
|
smpp_cmd_flush_pending(esme);
|
||||||
llist_del(&esme->list);
|
llist_del(&esme->list);
|
||||||
|
@ -761,113 +758,41 @@ static int smpp_pdu_rx(struct osmo_esme *esme, struct msgb *msg __uses)
|
||||||
return rc;
|
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 */
|
/* !\brief call-back when per-ESME TCP socket has some data to be read */
|
||||||
static int esme_link_read_cb(struct osmo_fd *ofd)
|
static int esme_link_read_cb(struct osmo_fd *ofd)
|
||||||
{
|
{
|
||||||
struct osmo_esme *e = ofd->data;
|
struct osmo_esme *e = ofd->data;
|
||||||
struct esme *esme = e->esme;
|
struct esme *esme = e->esme;
|
||||||
uint32_t len;
|
int rc = esme_read_callback(esme, ofd->fd);
|
||||||
uint8_t *lenptr = (uint8_t *) &len;
|
|
||||||
uint8_t *cur;
|
|
||||||
struct msgb *msg;
|
|
||||||
ssize_t rdlen, rc;
|
|
||||||
|
|
||||||
switch (esme->read_state) {
|
switch (rc) {
|
||||||
case READ_ST_IN_LEN:
|
case 1:
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(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);
|
rc = smpp_pdu_rx(e, esme->read_msg);
|
||||||
msgb_free(esme->read_msg);
|
esme_read_state_reset(esme);
|
||||||
esme->read_msg = NULL;
|
|
||||||
esme->read_idx = 0;
|
|
||||||
esme->read_len = 0;
|
|
||||||
esme->read_state = READ_ST_IN_LEN;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
case -EBADF:
|
||||||
|
|
||||||
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)
|
if (e->acl)
|
||||||
e->acl->esme = NULL;
|
e->acl->esme = NULL;
|
||||||
smpp_esme_put(e);
|
smpp_esme_put(e);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
return -EBADF;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call-back of write queue once it wishes to write a message to the socket */
|
/* 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)
|
static int esme_link_write_cb(struct osmo_fd *ofd, struct msgb *msg)
|
||||||
{
|
{
|
||||||
struct osmo_esme *esme = ofd->data;
|
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) {
|
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)
|
if (esme->acl)
|
||||||
esme->acl->esme = NULL;
|
esme->acl->esme = NULL;
|
||||||
smpp_esme_put(esme);
|
smpp_esme_put(esme);
|
||||||
} else if (rc < msgb_length(msg)) {
|
} else if (rc == -1) {
|
||||||
LOGPESME(esme->esme, LOGL_ERROR, "Short write\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,11 +20,114 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/msgb.h>
|
||||||
|
#include <osmocom/core/write_queue.h>
|
||||||
#include <osmocom/core/logging.h>
|
#include <osmocom/core/logging.h>
|
||||||
#include <osmocom/netif/stream.h>
|
#include <osmocom/netif/stream.h>
|
||||||
|
#include <osmocom/msc/debug.h>
|
||||||
|
#include <osmocom/smpp/smpp.h>
|
||||||
#include <osmocom/smpp/smpp_smsc.h>
|
#include <osmocom/smpp/smpp_smsc.h>
|
||||||
|
|
||||||
|
#include <smpp34.h>
|
||||||
|
#include <smpp34_structs.h>
|
||||||
|
#include <smpp34_params.h>
|
||||||
|
|
||||||
|
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 retrieve SMPP command ID from a msgb */
|
/*! \brief retrieve SMPP command ID from a msgb */
|
||||||
uint32_t smpp_msgb_cmdid(struct msgb *msg)
|
uint32_t smpp_msgb_cmdid(struct msgb *msg)
|
||||||
{
|
{
|
||||||
|
|
|
@ -143,98 +143,30 @@ static int smpp_pdu_rx(struct esme *esme, struct msgb *msg)
|
||||||
return rc;
|
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)
|
static int esme_read_cb(struct osmo_fd *ofd)
|
||||||
{
|
{
|
||||||
struct esme *esme = ofd->data;
|
struct esme *esme = ofd->data;
|
||||||
uint32_t len;
|
int rc = esme_read_callback(esme, ofd->fd);
|
||||||
uint8_t *lenptr = (uint8_t *) &len;
|
|
||||||
uint8_t *cur;
|
|
||||||
struct msgb *msg;
|
|
||||||
int rdlen;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
switch (esme->read_state) {
|
switch (rc) {
|
||||||
case READ_ST_IN_LEN:
|
case 1:
|
||||||
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);
|
|
||||||
}
|
|
||||||
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);
|
rc = smpp_pdu_rx(esme, esme->read_msg);
|
||||||
esme_read_state_reset(esme);
|
esme_read_state_reset(esme);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
case -EBADF:
|
||||||
|
|
||||||
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);
|
exit(2342);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int esme_write_cb(struct osmo_fd *ofd, struct msgb *msg)
|
static int esme_write_cb(struct osmo_fd *ofd, struct msgb *msg)
|
||||||
{
|
{
|
||||||
struct esme *esme = ofd->data;
|
if (esme_write_callback(ofd->data, ofd->fd, msg) == 0)
|
||||||
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;
|
|
||||||
exit(99);
|
exit(99);
|
||||||
} else if (rc < msgb_length(msg)) {
|
|
||||||
LOGPESME(esme, LOGL_ERROR, "Short write\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue