IPA: remove automatic reconnect logic
When an IPA link is in client (BTS) mode, we should not automatically
re-connect in the lowest (ipa) layer. Instead, we properly close the
socket if the link is dead, and we call link->updown_cb() to notify
the user that the link is down.
The e1inp/ipaccess layer translates this into a line->sign_link_down()
callback that propagates up to the user.
diff --git a/include/osmocom/abis/ipa.h b/include/osmocom/abis/ipa.h
index 397cf9c..d577d74 100644
--- a/include/osmocom/abis/ipa.h
+++ b/include/osmocom/abis/ipa.h
@@ -49,13 +49,13 @@
enum ipa_client_conn_state state;
const char *addr;
uint16_t port;
- int (*connect_cb)(struct ipa_client_conn *link);
+ void (*updown_cb)(struct ipa_client_conn *link, int up);
int (*read_cb)(struct ipa_client_conn *link, struct msgb *msg);
int (*write_cb)(struct ipa_client_conn *link);
void *data;
};
-struct ipa_client_conn *ipa_client_conn_create(void *ctx, struct e1inp_ts *ts, int priv_nr, const char *addr, uint16_t port, int (*connect)(struct ipa_client_conn *link), int (*read_cb)(struct ipa_client_conn *link, struct msgb *msgb), int (*write_cb)(struct ipa_client_conn *link), void *data);
+struct ipa_client_conn *ipa_client_conn_create(void *ctx, struct e1inp_ts *ts, int priv_nr, const char *addr, uint16_t port, void (*updown)(struct ipa_client_conn *link, int), int (*read_cb)(struct ipa_client_conn *link, struct msgb *msgb), int (*write_cb)(struct ipa_client_conn *link), void *data);
void ipa_client_conn_destroy(struct ipa_client_conn *link);
int ipa_client_conn_open(struct ipa_client_conn *link);
diff --git a/src/input/ipa.c b/src/input/ipa.c
index 8c6f603..ba92163 100644
--- a/src/input/ipa.c
+++ b/src/input/ipa.c
@@ -95,17 +95,6 @@
return ret;
}
-void ipa_client_conn_close(struct ipa_client_conn *link);
-
-static void ipa_client_retry(struct ipa_client_conn *link)
-{
- LOGP(DLINP, LOGL_NOTICE, "connection closed\n");
- ipa_client_conn_close(link);
- LOGP(DLINP, LOGL_NOTICE, "retrying in 5 seconds...\n");
- osmo_timer_schedule(&link->timer, 5, 0);
- link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
-}
-
void ipa_client_conn_close(struct ipa_client_conn *link)
{
/* be safe against multiple calls */
@@ -129,11 +118,15 @@
if (errno == EPIPE || errno == ECONNRESET) {
LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
}
- ipa_client_retry(link);
+ ipa_client_conn_close(link);
+ if (link->updown_cb)
+ link->updown_cb(link, 0);
return;
} else if (ret == 0) {
LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
- ipa_client_retry(link);
+ ipa_client_conn_close(link);
+ if (link->updown_cb)
+ link->updown_cb(link, 0);
return;
}
if (link->read_cb)
@@ -166,7 +159,9 @@
ret = send(link->ofd->fd, msg->data, msg->len, 0);
if (ret < 0) {
if (errno == EPIPE || errno == ENOTCONN) {
- ipa_client_retry(link);
+ ipa_client_conn_close(link);
+ if (link->updown_cb)
+ link->updown_cb(link, 0);
}
LOGP(DLINP, LOGL_ERROR, "error to send\n");
}
@@ -184,14 +179,16 @@
case IPA_CLIENT_LINK_STATE_CONNECTING:
ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
if (ret >= 0 && error > 0) {
- ipa_client_retry(link);
+ ipa_client_conn_close(link);
+ if (link->updown_cb)
+ link->updown_cb(link, 0);
return 0;
}
ofd->when &= ~BSC_FD_WRITE;
LOGP(DLINP, LOGL_NOTICE, "connection done.\n");
link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
- if (link->connect_cb)
- link->connect_cb(link);
+ if (link->updown_cb)
+ link->updown_cb(link, 1);
break;
case IPA_CLIENT_LINK_STATE_CONNECTED:
if (what & BSC_FD_READ) {
@@ -209,12 +206,10 @@
return 0;
}
-static void ipa_link_timer_cb(void *data);
-
struct ipa_client_conn *
ipa_client_conn_create(void *ctx, struct e1inp_ts *ts,
int priv_nr, const char *addr, uint16_t port,
- int (*connect_cb)(struct ipa_client_conn *link),
+ void (*updown_cb)(struct ipa_client_conn *link, int up),
int (*read_cb)(struct ipa_client_conn *link,
struct msgb *msgb),
int (*write_cb)(struct ipa_client_conn *link),
@@ -244,12 +239,11 @@
ipa_link->ofd->priv_nr = priv_nr;
ipa_link->ofd->cb = ipa_client_fd_cb;
ipa_link->ofd->data = ipa_link;
+ ipa_link->ofd->fd = -1;
ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
- ipa_link->timer.cb = ipa_link_timer_cb;
- ipa_link->timer.data = ipa_link;
ipa_link->addr = talloc_strdup(ipa_link, addr);
ipa_link->port = port;
- ipa_link->connect_cb = connect_cb;
+ ipa_link->updown_cb = updown_cb;
ipa_link->read_cb = read_cb;
/* default to generic write callback if not set. */
if (write_cb == NULL)
@@ -284,26 +278,13 @@
link->ofd->fd = ret;
if (osmo_fd_register(link->ofd) < 0) {
close(ret);
+ link->ofd->fd = -1;
return -EIO;
}
+
return 0;
}
-static void ipa_link_timer_cb(void *data)
-{
- struct ipa_client_conn *link = data;
-
- LOGP(DLINP, LOGL_NOTICE, "reconnecting.\n");
-
- switch(link->state) {
- case IPA_CLIENT_LINK_STATE_CONNECTING:
- ipa_client_conn_open(link);
- break;
- default:
- break;
- }
-}
-
void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg)
{
msgb_enqueue(&link->tx_queue, msg);
diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c
index 6663b9f..cf0cc15 100644
--- a/src/input/ipaccess.c
+++ b/src/input/ipaccess.c
@@ -800,6 +800,17 @@
return nmsg2;
}
+static void ipaccess_bts_updown_cb(struct ipa_client_conn *link, int up)
+{
+ struct e1inp_line *line = link->line;
+
+ if (up)
+ return;
+
+ if (line->ops->sign_link_down)
+ line->ops->sign_link_down(line);
+}
+
static int ipaccess_bts_read_cb(struct ipa_client_conn *link, struct msgb *msg)
{
struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
@@ -973,7 +984,7 @@
E1INP_SIGN_OML,
line->ops->cfg.ipa.addr,
IPA_TCP_PORT_OML,
- NULL,
+ ipaccess_bts_updown_cb,
ipaccess_bts_read_cb,
ipaccess_bts_write_cb,
line);
@@ -1007,7 +1018,7 @@
&line->ts[E1INP_SIGN_RSL-1],
E1INP_SIGN_RSL,
rem_addr, rem_port,
- NULL,
+ ipaccess_bts_updown_cb,
ipaccess_bts_read_cb,
ipaccess_bts_write_cb,
line);