1 commit 3bb33335816c1c9549d21bcc14bed29519b938a3
2 Author: Emeric Brun <ebrun@haproxy.com>
3 Date: Tue Apr 2 17:22:01 2019 +0200
5 BUG/MEDIUM: peers: fix a case where peer session is not cleanly reset on release.
7 The deinit took place in only peer_session_release, but in the a case of a
8 previous call to peer_session_forceshutdown, the session cursors
9 won't be reset, resulting in a bad state for new session of the same
10 peer. For instance, a table definition message could be dropped and
11 so all update messages will be dropped by the remote peer.
13 This patch move the deinit processing directly in the force shutdown
14 funtion. Killed session remains in "ST_END" state but ref on peer was
15 reset to NULL and deinit will be skipped on session release function.
17 The session release continue to assure the deinit for "active" sessions.
19 This patch should be backported on all stable version since proto
22 (cherry picked from commit 9ef2ad7844e577b505019695c59284f4a439fc33)
23 Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
24 (cherry picked from commit 14831989a081f3944cf891afd56e6d9f6086c3ed)
25 [cf: global variabled connected_peers and active_peers don't exist in 1.8]
26 Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
28 diff --git a/src/peers.c b/src/peers.c
29 index 465ffe85..d7dc51d8 100644
32 @@ -172,7 +172,7 @@ enum {
33 #define PEER_DWNGRD_MINOR_VER 0
35 struct peers *cfg_peers = NULL;
36 -static void peer_session_forceshutdown(struct appctx *appctx);
37 +static void peer_session_forceshutdown(struct peer *peer);
39 /* This function encode an uint64 to 'dynamic' length format.
40 The encoded value is written at address *str, and the
41 @@ -492,15 +492,53 @@ static int peer_prepare_ackmsg(struct shared_table *st, char *msg, size_t size)
42 return (cursor - msg) + datalen;
46 + * Function to deinit connected peer
48 +void __peer_session_deinit(struct peer *peer)
50 + struct stream_interface *si;
52 + struct peers *peers;
57 + si = peer->appctx->owner;
65 + peers = strm_fe(s)->parent;
69 + /* Re-init current table pointers to force announcement on re-connect */
70 + peer->remote_table = peer->last_local_table = NULL;
71 + peer->appctx = NULL;
72 + if (peer->flags & PEER_F_LEARN_ASSIGN) {
73 + /* unassign current peer for learning */
74 + peer->flags &= ~(PEER_F_LEARN_ASSIGN);
75 + peers->flags &= ~(PEERS_F_RESYNC_ASSIGN|PEERS_F_RESYNC_PROCESS);
77 + /* reschedule a resync */
78 + peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(5000));
80 + /* reset teaching and learning flags to 0 */
81 + peer->flags &= PEER_TEACH_RESET;
82 + peer->flags &= PEER_LEARN_RESET;
83 + task_wakeup(peers->sync_task, TASK_WOKEN_MSG);
87 * Callback to release a session with a peer
89 static void peer_session_release(struct appctx *appctx)
91 - struct stream_interface *si = appctx->owner;
92 - struct stream *s = si_strm(si);
93 struct peer *peer = appctx->ctx.peers.ptr;
94 - struct peers *peers = strm_fe(s)->parent;
96 /* appctx->ctx.peers.ptr is not a peer session */
97 if (appctx->st0 < PEER_SESS_ST_SENDSUCCESS)
98 @@ -509,24 +547,9 @@ static void peer_session_release(struct appctx *appctx)
99 /* peer session identified */
101 HA_SPIN_LOCK(PEER_LOCK, &peer->lock);
102 - if (peer->appctx == appctx) {
103 - /* Re-init current table pointers to force announcement on re-connect */
104 - peer->remote_table = peer->last_local_table = NULL;
105 - peer->appctx = NULL;
106 - if (peer->flags & PEER_F_LEARN_ASSIGN) {
107 - /* unassign current peer for learning */
108 - peer->flags &= ~(PEER_F_LEARN_ASSIGN);
109 - peers->flags &= ~(PEERS_F_RESYNC_ASSIGN|PEERS_F_RESYNC_PROCESS);
111 - /* reschedule a resync */
112 - peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(5000));
114 - /* reset teaching and learning flags to 0 */
115 - peer->flags &= PEER_TEACH_RESET;
116 - peer->flags &= PEER_LEARN_RESET;
118 + if (peer->appctx == appctx)
119 + __peer_session_deinit(peer);
120 HA_SPIN_UNLOCK(PEER_LOCK, &peer->lock);
121 - task_wakeup(peers->sync_task, TASK_WOKEN_MSG);
125 @@ -704,7 +727,7 @@ switchstate:
128 curpeer->reconnect = tick_add(now_ms, MS_TO_TICKS(50 + random() % 2000));
129 - peer_session_forceshutdown(curpeer->appctx);
130 + peer_session_forceshutdown(curpeer);
132 if (maj_ver != (unsigned int)-1 && min_ver != (unsigned int)-1) {
133 if (min_ver == PEER_DWNGRD_MINOR_VER) {
134 @@ -1832,11 +1855,14 @@ static struct applet peer_applet = {
135 .release = peer_session_release,
140 * Use this function to force a close of a peer session
142 -static void peer_session_forceshutdown(struct appctx *appctx)
143 +static void peer_session_forceshutdown(struct peer *peer)
145 + struct appctx *appctx = peer->appctx;
147 /* Note that the peer sessions which have just been created
148 * (->st0 == PEER_SESS_ST_CONNECT) must not
149 * be shutdown, if not, the TCP session will never be closed
150 @@ -1849,6 +1875,8 @@ static void peer_session_forceshutdown(struct appctx *appctx)
151 if (appctx->applet != &peer_applet)
154 + __peer_session_deinit(peer);
156 appctx->st0 = PEER_SESS_ST_END;
157 appctx_wakeup(appctx);
159 @@ -2094,8 +2122,7 @@ static struct task *process_peer_sync(struct task * task)
161 ps->reconnect = tick_add(now_ms, MS_TO_TICKS(50 + random() % 2000));
163 - peer_session_forceshutdown(ps->appctx);
165 + peer_session_forceshutdown(ps);