ipa: Use enhanced ipa_msg_recv_buffered() to cope with partioned IPA messages

The old ipa_msg_recv() implementation didn't support partial receive,
so IPA connections got disconnected when this happened.

This patch adds the handling of the temporary message buffers and uses
ipa_msg_recv_buffered().

It has been successfully tested by jerlbeck with osmo-nitb and
osmo-bsc.

Ticket: OW#768
Sponsored-by: On-Waves ehf
This commit is contained in:
Jacob Erlbeck 2014-03-31 13:42:11 +02:00 committed by Holger Hans Peter Freyther
parent 8a158bb1ea
commit e827812051
9 changed files with 50 additions and 10 deletions

View File

@ -25,7 +25,7 @@ AC_SUBST(LIBRARY_DL)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.6.4) PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.6.4)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0) PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.6.0) PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.6.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.1.0) PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.2.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.6.4) PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.6.4)
# Enabke/disable the NAT? # Enabke/disable the NAT?

View File

@ -48,6 +48,8 @@ struct bsc_msc_connection {
void (*connected) (struct bsc_msc_connection *); void (*connected) (struct bsc_msc_connection *);
struct osmo_timer_list reconnect_timer; struct osmo_timer_list reconnect_timer;
struct osmo_timer_list timeout_timer; struct osmo_timer_list timeout_timer;
struct msgb *pending_msg;
}; };
struct bsc_msc_connection *bsc_msc_create(void *ctx, struct llist_head *dest); struct bsc_msc_connection *bsc_msc_create(void *ctx, struct llist_head *dest);

View File

@ -97,6 +97,9 @@ struct bsc_connection {
/* the fd we use to communicate */ /* the fd we use to communicate */
struct osmo_wqueue write_queue; struct osmo_wqueue write_queue;
/* incoming message buffer */
struct msgb *pending_msg;
/* the BSS associated */ /* the BSS associated */
struct bsc_config *cfg; struct bsc_config *cfg;
@ -343,6 +346,8 @@ struct bsc_nat_ussd_con {
struct bsc_nat *nat; struct bsc_nat *nat;
int authorized; int authorized;
struct msgb *pending_msg;
struct osmo_timer_list auth_timeout; struct osmo_timer_list auth_timeout;
}; };

View File

@ -39,6 +39,9 @@ struct ctrl_connection {
/* The queue for sending data back */ /* The queue for sending data back */
struct osmo_wqueue write_queue; struct osmo_wqueue write_queue;
/* Buffer for partial input data */
struct msgb *pending_msg;
/* Callback if the connection was closed */ /* Callback if the connection was closed */
void (*closed_cb)(struct ctrl_connection *conn); void (*closed_cb)(struct ctrl_connection *conn);

View File

@ -42,6 +42,13 @@ static void connection_loss(struct bsc_msc_connection *con)
fd = &con->write_queue.bfd; fd = &con->write_queue.bfd;
if (con->pending_msg) {
LOGP(DMSC, LOGL_ERROR,
"MSC(%s) dropping incomplete message.\n", con->name);
msgb_free(con->pending_msg);
con->pending_msg = NULL;
}
close(fd->fd); close(fd->fd);
fd->fd = -1; fd->fd = -1;
fd->cb = osmo_wqueue_bfd_cb; fd->cb = osmo_wqueue_bfd_cb;
@ -162,6 +169,9 @@ int bsc_msc_connect(struct bsc_msc_connection *con)
con->is_connected = 0; con->is_connected = 0;
msgb_free(con->pending_msg);
con->pending_msg = NULL;
fd = &con->write_queue.bfd; fd = &con->write_queue.bfd;
fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
fd->priv_nr = 1; fd->priv_nr = 1;

View File

@ -123,6 +123,7 @@ static void control_close_conn(struct ctrl_connection *ccon)
llist_del(&ccon->list_entry); llist_del(&ccon->list_entry);
if (ccon->closed_cb) if (ccon->closed_cb)
ccon->closed_cb(ccon); ccon->closed_cb(ccon);
msgb_free(ccon->pending_msg);
talloc_free(ccon); talloc_free(ccon);
} }
@ -140,8 +141,10 @@ static int handle_control_read(struct osmo_fd * bfd)
queue = container_of(bfd, struct osmo_wqueue, bfd); queue = container_of(bfd, struct osmo_wqueue, bfd);
ccon = container_of(queue, struct ctrl_connection, write_queue); ccon = container_of(queue, struct ctrl_connection, write_queue);
ret = ipa_msg_recv(bfd->fd, &msg); ret = ipa_msg_recv_buffered(bfd->fd, &msg, &ccon->pending_msg);
if (ret <= 0) { if (ret <= 0) {
if (ret == -EAGAIN)
return 0;
if (ret == 0) if (ret == 0)
LOGP(DCTRL, LOGL_INFO, "The control connection was closed\n"); LOGP(DCTRL, LOGL_INFO, "The control connection was closed\n");
else else

View File

@ -247,13 +247,15 @@ static void osmo_ext_handle(struct osmo_msc_data *msc, struct msgb *msg)
static int ipaccess_a_fd_cb(struct osmo_fd *bfd) static int ipaccess_a_fd_cb(struct osmo_fd *bfd)
{ {
struct msgb *msg; struct msgb *msg = NULL;
struct ipaccess_head *hh; struct ipaccess_head *hh;
struct osmo_msc_data *data = (struct osmo_msc_data *) bfd->data; struct osmo_msc_data *data = (struct osmo_msc_data *) bfd->data;
int ret; int ret;
ret = ipa_msg_recv(bfd->fd, &msg); ret = ipa_msg_recv_buffered(bfd->fd, &msg, &data->msc_con->pending_msg);
if (ret <= 0) { if (ret <= 0) {
if (ret == -EAGAIN)
return 0;
if (ret == 0) { if (ret == 0) {
LOGP(DMSC, LOGL_ERROR, "The connection to the MSC was lost.\n"); LOGP(DMSC, LOGL_ERROR, "The connection to the MSC was lost.\n");
bsc_msc_lost(data->msc_con); bsc_msc_lost(data->msc_con);

View File

@ -796,14 +796,16 @@ static void msc_send_reset(struct bsc_msc_connection *msc_con)
static int ipaccess_msc_read_cb(struct osmo_fd *bfd) static int ipaccess_msc_read_cb(struct osmo_fd *bfd)
{ {
struct bsc_msc_connection *msc_con; struct bsc_msc_connection *msc_con;
struct msgb *msg; struct msgb *msg = NULL;
struct ipaccess_head *hh; struct ipaccess_head *hh;
int ret; int ret;
msc_con = (struct bsc_msc_connection *) bfd->data; msc_con = (struct bsc_msc_connection *) bfd->data;
ret = ipa_msg_recv(bfd->fd, &msg); ret = ipa_msg_recv_buffered(bfd->fd, &msg, &msc_con->pending_msg);
if (ret <= 0) { if (ret <= 0) {
if (ret == -EAGAIN)
return 0;
if (ret == 0) if (ret == 0)
LOGP(DNAT, LOGL_FATAL, LOGP(DNAT, LOGL_FATAL,
"The connection the MSC(%s) was lost, exiting\n", "The connection the MSC(%s) was lost, exiting\n",
@ -912,6 +914,13 @@ void bsc_close_connection(struct bsc_connection *connection)
osmo_wqueue_clear(&connection->write_queue); osmo_wqueue_clear(&connection->write_queue);
llist_del(&connection->list_entry); llist_del(&connection->list_entry);
if (connection->pending_msg) {
LOGP(DNAT, LOGL_ERROR, "Dropping partial message on connection %d.\n",
connection->cfg->nr);
msgb_free(connection->pending_msg);
connection->pending_msg = NULL;
}
talloc_free(connection); talloc_free(connection);
} }
@ -1206,13 +1215,15 @@ exit3:
static int ipaccess_bsc_read_cb(struct osmo_fd *bfd) static int ipaccess_bsc_read_cb(struct osmo_fd *bfd)
{ {
struct bsc_connection *bsc = bfd->data; struct bsc_connection *bsc = bfd->data;
struct msgb *msg; struct msgb *msg = NULL;
struct ipaccess_head *hh; struct ipaccess_head *hh;
struct ipaccess_head_ext *hh_ext; struct ipaccess_head_ext *hh_ext;
int ret; int ret;
ret = ipa_msg_recv(bfd->fd, &msg); ret = ipa_msg_recv_buffered(bfd->fd, &msg, &bsc->pending_msg);
if (ret <= 0) { if (ret <= 0) {
if (ret == -EAGAIN)
return 0;
if (ret == 0) if (ret == 0)
LOGP(DNAT, LOGL_ERROR, LOGP(DNAT, LOGL_ERROR,
"The connection to the BSC Nr: %d was lost. Cleaning it\n", "The connection to the BSC Nr: %d was lost. Cleaning it\n",

View File

@ -66,6 +66,8 @@ static void bsc_nat_ussd_destroy(struct bsc_nat_ussd_con *con)
osmo_fd_unregister(&con->queue.bfd); osmo_fd_unregister(&con->queue.bfd);
osmo_timer_del(&con->auth_timeout); osmo_timer_del(&con->auth_timeout);
osmo_wqueue_clear(&con->queue); osmo_wqueue_clear(&con->queue);
msgb_free(con->pending_msg);
talloc_free(con); talloc_free(con);
} }
@ -117,12 +119,14 @@ static int forward_sccp(struct bsc_nat *nat, struct msgb *msg)
static int ussd_read_cb(struct osmo_fd *bfd) static int ussd_read_cb(struct osmo_fd *bfd)
{ {
struct bsc_nat_ussd_con *conn = bfd->data; struct bsc_nat_ussd_con *conn = bfd->data;
struct msgb *msg; struct msgb *msg = NULL;
struct ipaccess_head *hh; struct ipaccess_head *hh;
int ret; int ret;
ret = ipa_msg_recv(bfd->fd, &msg); ret = ipa_msg_recv_buffered(bfd->fd, &msg, &conn->pending_msg);
if (ret <= 0) { if (ret <= 0) {
if (ret == -EAGAIN)
return 0;
LOGP(DNAT, LOGL_ERROR, "USSD Connection was lost.\n"); LOGP(DNAT, LOGL_ERROR, "USSD Connection was lost.\n");
bsc_nat_ussd_destroy(conn); bsc_nat_ussd_destroy(conn);
return -1; return -1;