From 092997ab67eb2529c5b40556e1d301c8220c315d Mon Sep 17 00:00:00 2001 From: Jung-Sang Ahn Date: Tue, 24 Sep 2024 12:37:09 -0700 Subject: [PATCH] Add a callback to handle misbehaving messages from peer (#537) * Callback can decide whether to ignore or to die. --- include/libnuraft/callback.hxx | 21 +++++++++++++++++++++ src/handle_append_entries.cxx | 16 ++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/include/libnuraft/callback.hxx b/include/libnuraft/callback.hxx index de40f327..5c1ea581 100644 --- a/include/libnuraft/callback.hxx +++ b/include/libnuraft/callback.hxx @@ -18,6 +18,9 @@ limitations under the License. #ifndef _CALLBACK_H_ #define _CALLBACK_H_ +#include "req_msg.hxx" +#include "resp_msg.hxx" + #include #include #include @@ -214,6 +217,18 @@ public: * ctx: null. */ FollowerLost = 28, + + /** + * When the server receives a misbehaving message from a peer, + * the callback has the ability to either ignore the message + * or respond normally by adjusting ReqResp.resp as indicated by ctx. + * + * Furthermore, the callback can opt to terminate + * if the situation is deemed critical. + * + * ctx: pointer to `ReqResp` instance. + */ + ReceivedMisbehavingMessage = 29, }; struct Param { @@ -232,6 +247,12 @@ public: void* ctx; }; + struct ReqResp { + ReqResp() : req(nullptr), resp(nullptr) {} + req_msg* req; + ptr resp; + }; + enum ReturnCode { Ok = 0, ReturnNull = -1, diff --git a/src/handle_append_entries.cxx b/src/handle_append_entries.cxx index d23d97a8..a07d5b88 100644 --- a/src/handle_append_entries.cxx +++ b/src/handle_append_entries.cxx @@ -593,9 +593,21 @@ ptr raft_server::handle_append_entries(req_msg& req) become_follower(); } else if (role_ == srv_role::leader) { p_wn( "Receive AppendEntriesRequest from another leader (%d) " - "with same term, there must be a bug. Ignore it instead of exit.", + "with same term, there must be a bug. Invoking the callback.", req.get_src() ); - return nullptr; + + cb_func::Param param(id_, leader_, -1, &req); + cb_func::ReqResp req_resp; + req_resp.req = &req; + + ctx_->cb_func_.call(cb_func::ReceivedMisbehavingMessage, ¶m); + if (!req_resp.resp.get()) { + p_wn("callback function didn't return response, ignore this request"); + } else { + p_wn("callback function returned response, send it back"); + } + return req_resp.resp; + } else { update_target_priority(); // Modified by JungSang Ahn, Mar 28 2018: