packages/net/haproxy/patches/020-BUG-MEDIUM-peers-fix-a-case-where-peer-session-is-not-cleanly-reset-on-release.patch
Christian Lachner b7d6096f54 haproxy: Update all patches for HAProxy v1.8.19
- Add new patches (see https://www.haproxy.org/bugs/bugs-1.8.19.html)
- Raise PKG_RELEASE to 4

Signed-off-by: Christian Lachner <gladiac@gmail.com>
2019-04-26 08:56:27 +02:00

168 lines
5.5 KiB
Diff

commit 3bb33335816c1c9549d21bcc14bed29519b938a3
Author: Emeric Brun <ebrun@haproxy.com>
Date: Tue Apr 2 17:22:01 2019 +0200
BUG/MEDIUM: peers: fix a case where peer session is not cleanly reset on release.
The deinit took place in only peer_session_release, but in the a case of a
previous call to peer_session_forceshutdown, the session cursors
won't be reset, resulting in a bad state for new session of the same
peer. For instance, a table definition message could be dropped and
so all update messages will be dropped by the remote peer.
This patch move the deinit processing directly in the force shutdown
funtion. Killed session remains in "ST_END" state but ref on peer was
reset to NULL and deinit will be skipped on session release function.
The session release continue to assure the deinit for "active" sessions.
This patch should be backported on all stable version since proto
peers v2.
(cherry picked from commit 9ef2ad7844e577b505019695c59284f4a439fc33)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 14831989a081f3944cf891afd56e6d9f6086c3ed)
[cf: global variabled connected_peers and active_peers don't exist in 1.8]
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/peers.c b/src/peers.c
index 465ffe85..d7dc51d8 100644
--- a/src/peers.c
+++ b/src/peers.c
@@ -172,7 +172,7 @@ enum {
#define PEER_DWNGRD_MINOR_VER 0
struct peers *cfg_peers = NULL;
-static void peer_session_forceshutdown(struct appctx *appctx);
+static void peer_session_forceshutdown(struct peer *peer);
/* This function encode an uint64 to 'dynamic' length format.
The encoded value is written at address *str, and the
@@ -492,15 +492,53 @@ static int peer_prepare_ackmsg(struct shared_table *st, char *msg, size_t size)
return (cursor - msg) + datalen;
}
+/*
+ * Function to deinit connected peer
+ */
+void __peer_session_deinit(struct peer *peer)
+{
+ struct stream_interface *si;
+ struct stream *s;
+ struct peers *peers;
+
+ if (!peer->appctx)
+ return;
+
+ si = peer->appctx->owner;
+ if (!si)
+ return;
+
+ s = si_strm(si);
+ if (!s)
+ return;
+
+ peers = strm_fe(s)->parent;
+ if (!peers)
+ return;
+
+ /* Re-init current table pointers to force announcement on re-connect */
+ peer->remote_table = peer->last_local_table = NULL;
+ peer->appctx = NULL;
+ if (peer->flags & PEER_F_LEARN_ASSIGN) {
+ /* unassign current peer for learning */
+ peer->flags &= ~(PEER_F_LEARN_ASSIGN);
+ peers->flags &= ~(PEERS_F_RESYNC_ASSIGN|PEERS_F_RESYNC_PROCESS);
+
+ /* reschedule a resync */
+ peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(5000));
+ }
+ /* reset teaching and learning flags to 0 */
+ peer->flags &= PEER_TEACH_RESET;
+ peer->flags &= PEER_LEARN_RESET;
+ task_wakeup(peers->sync_task, TASK_WOKEN_MSG);
+}
+
/*
* Callback to release a session with a peer
*/
static void peer_session_release(struct appctx *appctx)
{
- struct stream_interface *si = appctx->owner;
- struct stream *s = si_strm(si);
struct peer *peer = appctx->ctx.peers.ptr;
- struct peers *peers = strm_fe(s)->parent;
/* appctx->ctx.peers.ptr is not a peer session */
if (appctx->st0 < PEER_SESS_ST_SENDSUCCESS)
@@ -509,24 +547,9 @@ static void peer_session_release(struct appctx *appctx)
/* peer session identified */
if (peer) {
HA_SPIN_LOCK(PEER_LOCK, &peer->lock);
- if (peer->appctx == appctx) {
- /* Re-init current table pointers to force announcement on re-connect */
- peer->remote_table = peer->last_local_table = NULL;
- peer->appctx = NULL;
- if (peer->flags & PEER_F_LEARN_ASSIGN) {
- /* unassign current peer for learning */
- peer->flags &= ~(PEER_F_LEARN_ASSIGN);
- peers->flags &= ~(PEERS_F_RESYNC_ASSIGN|PEERS_F_RESYNC_PROCESS);
-
- /* reschedule a resync */
- peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(5000));
- }
- /* reset teaching and learning flags to 0 */
- peer->flags &= PEER_TEACH_RESET;
- peer->flags &= PEER_LEARN_RESET;
- }
+ if (peer->appctx == appctx)
+ __peer_session_deinit(peer);
HA_SPIN_UNLOCK(PEER_LOCK, &peer->lock);
- task_wakeup(peers->sync_task, TASK_WOKEN_MSG);
}
}
@@ -704,7 +727,7 @@ switchstate:
* for a while.
*/
curpeer->reconnect = tick_add(now_ms, MS_TO_TICKS(50 + random() % 2000));
- peer_session_forceshutdown(curpeer->appctx);
+ peer_session_forceshutdown(curpeer);
}
if (maj_ver != (unsigned int)-1 && min_ver != (unsigned int)-1) {
if (min_ver == PEER_DWNGRD_MINOR_VER) {
@@ -1832,11 +1855,14 @@ static struct applet peer_applet = {
.release = peer_session_release,
};
+
/*
* Use this function to force a close of a peer session
*/
-static void peer_session_forceshutdown(struct appctx *appctx)
+static void peer_session_forceshutdown(struct peer *peer)
{
+ struct appctx *appctx = peer->appctx;
+
/* Note that the peer sessions which have just been created
* (->st0 == PEER_SESS_ST_CONNECT) must not
* be shutdown, if not, the TCP session will never be closed
@@ -1849,6 +1875,8 @@ static void peer_session_forceshutdown(struct appctx *appctx)
if (appctx->applet != &peer_applet)
return;
+ __peer_session_deinit(peer);
+
appctx->st0 = PEER_SESS_ST_END;
appctx_wakeup(appctx);
}
@@ -2094,8 +2122,7 @@ static struct task *process_peer_sync(struct task * task)
*/
ps->reconnect = tick_add(now_ms, MS_TO_TICKS(50 + random() % 2000));
if (ps->appctx) {
- peer_session_forceshutdown(ps->appctx);
- ps->appctx = NULL;
+ peer_session_forceshutdown(ps);
}
}
}