From b9fcdcdb198a7b8fd5a16e6cebaba343edbddc66 Mon Sep 17 00:00:00 2001 From: Bram Matthys Date: Fri, 13 Jan 2023 18:09:12 +0100 Subject: [PATCH] Make server.rehash for remote servers use two possible code paths: * If the remote server (and all servers in-between) support RRPC then forward the RPC request as RRPC and let remote handle the response. The response will be the verbose rehash response. * If not supported, then simply return boolean true as a response, and use oldskool :source_server REHASH dest_server over the wire --- include/h.h | 4 ++++ include/modules.h | 2 ++ src/api-efunctions.c | 4 ++++ src/misc.c | 14 ++++++++++++++ src/modules/rpc/rpc.c | 27 ++++++++++++++++++++++----- src/modules/rpc/server.c | 12 +++++++++++- 6 files changed, 57 insertions(+), 6 deletions(-) diff --git a/include/h.h b/include/h.h index 56c334c78..e03fc51ff 100644 --- a/include/h.h +++ b/include/h.h @@ -857,6 +857,8 @@ extern MODVAR void (*rpc_error)(Client *client, json_t *request, JsonRpcError er extern MODVAR void (*rpc_error_fmt)(Client *client, json_t *request, JsonRpcError error_code, FORMAT_STRING(const char *fmt), ...) __attribute__((format(printf,4,5))); extern MODVAR void (*rpc_send_request_to_remote)(Client *source, Client *target, json_t *request); extern MODVAR void (*rpc_send_response_to_remote)(Client *source, Client *target, json_t *request); +extern MODVAR int (*rrpc_supported_simple)(Client *target, char **problem_server); +extern MODVAR int (*rrpc_supported)(Client *target, const char *module, const char *minimum_version, char **problem_server); extern MODVAR int (*websocket_handle_websocket)(Client *client, WebRequest *web, const char *readbuf2, int length2, int callback(Client *client, char *buf, int len)); extern MODVAR int (*websocket_create_packet)(int opcode, char **buf, int *len); extern MODVAR int (*websocket_create_packet_ex)(int opcode, char **buf, int *len, char *sendbuf, size_t sendbufsize); @@ -905,6 +907,8 @@ extern void rpc_error_default_handler(Client *client, json_t *request, JsonRpcEr extern void rpc_error_fmt_default_handler(Client *client, json_t *request, JsonRpcError error_code, const char *fmt, ...); extern void rpc_send_request_to_remote_default_handler(Client *source, Client *target, json_t *request); extern void rpc_send_response_to_remote_default_handler(Client *source, Client *target, json_t *response); +extern int rrpc_supported_simple_default_handler(Client *target, char **problem_server); +extern int rrpc_supported_default_handler(Client *target, const char *module, const char *minimum_version, char **problem_server); extern int websocket_handle_websocket_default_handler(Client *client, WebRequest *web, const char *readbuf2, int length2, int callback(Client *client, char *buf, int len)); extern int websocket_create_packet_default_handler(int opcode, char **buf, int *len); extern int websocket_create_packet_ex_default_handler(int opcode, char **buf, int *len, char *sendbuf, size_t sendbufsize); diff --git a/include/modules.h b/include/modules.h index 71be819e3..a27f6de9a 100644 --- a/include/modules.h +++ b/include/modules.h @@ -2551,6 +2551,8 @@ enum EfunctionType { EFUNC_RPC_ERROR_FMT, EFUNC_RPC_SEND_REQUEST_TO_REMOTE, EFUNC_RPC_SEND_RESPONSE_TO_REMOTE, + EFUNC_RRPC_SUPPORTED, + EFUNC_RRPC_SUPPORTED_SIMPLE, EFUNC_WEBSOCKET_HANDLE_WEBSOCKET, EFUNC_WEBSOCKET_CREATE_PACKET, EFUNC_WEBSOCKET_CREATE_PACKET_EX, diff --git a/src/api-efunctions.c b/src/api-efunctions.c index f872f0bdf..601eb62b9 100644 --- a/src/api-efunctions.c +++ b/src/api-efunctions.c @@ -149,6 +149,8 @@ void (*rpc_error)(Client *client, json_t *request, JsonRpcError error_code, cons void (*rpc_error_fmt)(Client *client, json_t *request, JsonRpcError error_code, const char *fmt, ...); void (*rpc_send_request_to_remote)(Client *source, Client *target, json_t *request); void (*rpc_send_response_to_remote)(Client *source, Client *target, json_t *response); +int (*rrpc_supported_simple)(Client *target, char **problem_server); +int (*rrpc_supported)(Client *target, const char *module, const char *minimum_version, char **problem_server); int (*websocket_handle_websocket)(Client *client, WebRequest *web, const char *readbuf2, int length2, int callback(Client *client, char *buf, int len)); int (*websocket_create_packet)(int opcode, char **buf, int *len); int (*websocket_create_packet_ex)(int opcode, char **buf, int *len, char *sendbuf, size_t sendbufsize); @@ -437,6 +439,8 @@ void efunctions_init(void) efunc_init_function(EFUNC_RPC_ERROR_FMT, rpc_error_fmt, rpc_error_fmt_default_handler); efunc_init_function(EFUNC_RPC_SEND_REQUEST_TO_REMOTE, rpc_send_request_to_remote, rpc_send_request_to_remote_default_handler); efunc_init_function(EFUNC_RPC_SEND_RESPONSE_TO_REMOTE, rpc_send_response_to_remote, rpc_send_response_to_remote_default_handler); + efunc_init_function(EFUNC_RRPC_SUPPORTED, rrpc_supported, rrpc_supported_default_handler); + efunc_init_function(EFUNC_RRPC_SUPPORTED_SIMPLE, rrpc_supported_simple, rrpc_supported_simple_default_handler); efunc_init_function(EFUNC_WEBSOCKET_HANDLE_WEBSOCKET, websocket_handle_websocket, websocket_handle_websocket_default_handler); efunc_init_function(EFUNC_WEBSOCKET_CREATE_PACKET, websocket_create_packet, websocket_create_packet_default_handler); efunc_init_function(EFUNC_WEBSOCKET_CREATE_PACKET_EX, websocket_create_packet_ex, websocket_create_packet_ex_default_handler); diff --git a/src/misc.c b/src/misc.c index d24b579ad..7970bd406 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1447,6 +1447,20 @@ void rpc_send_response_to_remote_default_handler(Client *source, Client *target, { } +int rrpc_supported_simple_default_handler(Client *target, char **problem_server) +{ + if (problem_server) + *problem_server = me.name; + return 0; +} + +int rrpc_supported_default_handler(Client *target, const char *module, const char *minimum_version, char **problem_server) +{ + if (problem_server) + *problem_server = me.name; + return 0; +} + int websocket_handle_websocket_default_handler(Client *client, WebRequest *web, const char *readbuf2, int length2, int callback(Client *client, char *buf, int len)) { return -1; diff --git a/src/modules/rpc/rpc.c b/src/modules/rpc/rpc.c index 7237222c4..bf3a94d95 100644 --- a/src/modules/rpc/rpc.c +++ b/src/modules/rpc/rpc.c @@ -67,6 +67,8 @@ void _rpc_error(Client *client, json_t *request, JsonRpcError error_code, const void _rpc_error_fmt(Client *client, json_t *request, JsonRpcError error_code, FORMAT_STRING(const char *fmt), ...) __attribute__((format(printf,4,5))); void _rpc_send_request_to_remote(Client *source, Client *target, json_t *request); void _rpc_send_response_to_remote(Client *source, Client *target, json_t *response); +int _rrpc_supported_simple(Client *target, char **problem_server); +int _rrpc_supported(Client *target, const char *module, const char *minimum_version, char **problem_server); int rpc_handle_auth(Client *client, WebRequest *web); int rpc_parse_auth_basic_auth(Client *client, WebRequest *web, char **username, char **password); int rpc_parse_auth_uri(Client *client, WebRequest *web, char **username, char **password); @@ -101,8 +103,10 @@ MOD_TEST() EfunctionAddVoid(modinfo->handle, EFUNC_RPC_RESPONSE, _rpc_response); EfunctionAddVoid(modinfo->handle, EFUNC_RPC_ERROR, _rpc_error); EfunctionAddVoid(modinfo->handle, EFUNC_RPC_ERROR_FMT, TO_VOIDFUNC(_rpc_error_fmt)); - EfunctionAddVoid(modinfo->handle, EFUNC_RPC_SEND_REQUEST_TO_REMOTE, TO_VOIDFUNC(_rpc_send_request_to_remote)); - EfunctionAddVoid(modinfo->handle, EFUNC_RPC_SEND_RESPONSE_TO_REMOTE, TO_VOIDFUNC(_rpc_send_response_to_remote)); + EfunctionAddVoid(modinfo->handle, EFUNC_RPC_SEND_REQUEST_TO_REMOTE, _rpc_send_request_to_remote); + EfunctionAddVoid(modinfo->handle, EFUNC_RPC_SEND_RESPONSE_TO_REMOTE, _rpc_send_response_to_remote); + EfunctionAdd(modinfo->handle, EFUNC_RRPC_SUPPORTED, _rrpc_supported); + EfunctionAdd(modinfo->handle, EFUNC_RRPC_SUPPORTED_SIMPLE, _rrpc_supported_simple); /* Call MOD_INIT very early, since we manage sockets, but depend on websocket_common */ ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_INIT+1); @@ -1318,7 +1322,7 @@ void rpc_send_generic_to_remote(Client *source, Client *target, const char *requ safe_free(json_serialized); } -int verify_rrpc_in_link_path(Client *target, char **problem_server) +int _rrpc_supported_simple(Client *target, char **problem_server) { if (!moddata_client_get(target, "rrpc")) { @@ -1326,7 +1330,20 @@ int verify_rrpc_in_link_path(Client *target, char **problem_server) *problem_server = target->name; return 0; } - if ((target != target->direction) && !verify_rrpc_in_link_path(target->direction, problem_server)) + if ((target != target->direction) && !rrpc_supported_simple(target->direction, problem_server)) + return 0; + return 1; +} + +int _rrpc_supported(Client *target, const char *module, const char *minimum_version, char **problem_server) +{ + if (!moddata_client_get(target, "rrpc")) + { + if (problem_server) + *problem_server = target->name; + return 0; + } + if ((target != target->direction) && !rrpc_supported_simple(target->direction, problem_server)) return 0; return 1; } @@ -1352,7 +1369,7 @@ void _rpc_send_request_to_remote(Client *source, Client *target, json_t *request } /* If we already detect that next server cannot satisfy the request then stop it right now */ - if (!verify_rrpc_in_link_path(target, &problem_server)) + if (!rrpc_supported_simple(target, &problem_server)) { rpc_error_fmt(source, request, JSON_RPC_ERROR_REMOTE_SERVER_NO_RPC, "Server %s does not support remote JSON-RPC", problem_server); return; diff --git a/src/modules/rpc/server.c b/src/modules/rpc/server.c index b67ecde58..1eb8d8f3c 100644 --- a/src/modules/rpc/server.c +++ b/src/modules/rpc/server.c @@ -162,7 +162,17 @@ RPC_CALL_FUNC(rpc_server_rehash) if (acptr != &me) { /* Forward to remote */ - rpc_send_request_to_remote(client, acptr, request); + if (rrpc_supported_simple(acptr, NULL)) + { + /* Server supports RRPC and will handle the response */ + rpc_send_request_to_remote(client, acptr, request); + } else { + /* Server does not support RRPC, so we can only do best effort: */ + sendto_one(acptr, NULL, ":%s REHASH %s", me.id, acptr->name); + result = json_boolean(1); + rpc_response(client, request, result); + json_decref(result); + } return; }