Many open source projects have moved to using SPDX identifiers to specify license information, reducing the amount of boilerplate code in every source file. This patch replaces the bulk of SPDK .c, .cpp and Makefiles with the BSD-3-Clause identifier. Almost all of these files share the exact same license text, and this patch only modifies the files that contain the most common license text. There can be slight variations because the third clause contains company names - most say "Intel Corporation", but there are instances for Nvidia, Samsung, Eideticom and even "the copyright holder". Used a bash script to automate replacement of the license text with SPDX identifier which is checked into scripts/spdx.sh. Signed-off-by: Jim Harris <james.r.harris@intel.com> Change-Id: Iaa88ab5e92ea471691dc298cfe41ebfb5d169780 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/12904 Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com> Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com> Reviewed-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-by: Dong Yi <dongx.yi@intel.com> Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com> Reviewed-by: Paul Luse <paul.e.luse@intel.com> Reviewed-by: <qun.wan@intel.com>
425 lines
10 KiB
C
425 lines
10 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (c) Intel Corporation.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include "spdk/stdinc.h"
|
|
#include "spdk/event.h"
|
|
#include "spdk/jsonrpc.h"
|
|
#include "spdk/util.h"
|
|
#include "spdk/rpc.h"
|
|
|
|
|
|
#define RPC_MAX_METHODS 200
|
|
#define JOIN_TIMEOUT_S 1
|
|
|
|
static const char *g_rpcsock_addr = SPDK_DEFAULT_RPC_ADDR;
|
|
static int g_addr_family = AF_UNIX;
|
|
|
|
#define RPC_MAX_METHODS 200
|
|
|
|
struct get_jsonrpc_methods_resp {
|
|
char *method_names[RPC_MAX_METHODS];
|
|
size_t method_num;
|
|
};
|
|
|
|
static int
|
|
_rpc_client_wait_for_response(struct spdk_jsonrpc_client *client)
|
|
{
|
|
int rc;
|
|
|
|
do {
|
|
rc = spdk_jsonrpc_client_poll(client, 1);
|
|
} while (rc == 0 || rc == -ENOTCONN);
|
|
|
|
if (rc <= 0) {
|
|
SPDK_ERRLOG("Failed to get response: %d\n", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
get_jsonrpc_method_json_parser(struct get_jsonrpc_methods_resp *resp,
|
|
const struct spdk_json_val *result)
|
|
{
|
|
return spdk_json_decode_array(result, spdk_json_decode_string, resp->method_names,
|
|
RPC_MAX_METHODS, &resp->method_num, sizeof(char *));
|
|
}
|
|
|
|
static int
|
|
spdk_jsonrpc_client_check_rpc_method(struct spdk_jsonrpc_client *client, char *method_name)
|
|
{
|
|
int rc, i;
|
|
struct spdk_jsonrpc_client_response *json_resp = NULL;
|
|
struct get_jsonrpc_methods_resp resp = {};
|
|
struct spdk_json_write_ctx *w;
|
|
struct spdk_jsonrpc_client_request *request;
|
|
|
|
request = spdk_jsonrpc_client_create_request();
|
|
if (request == NULL) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
w = spdk_jsonrpc_begin_request(request, 1, "rpc_get_methods");
|
|
spdk_jsonrpc_end_request(request, w);
|
|
spdk_jsonrpc_client_send_request(client, request);
|
|
|
|
rc = _rpc_client_wait_for_response(client);
|
|
if (rc <= 0) {
|
|
goto out;
|
|
}
|
|
|
|
json_resp = spdk_jsonrpc_client_get_response(client);
|
|
if (json_resp == NULL) {
|
|
SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
|
|
rc = -1;
|
|
goto out;
|
|
|
|
}
|
|
|
|
/* Check for error response */
|
|
if (json_resp->error != NULL) {
|
|
SPDK_ERRLOG("Unexpected error response\n");
|
|
rc = -1;
|
|
goto out;
|
|
}
|
|
|
|
assert(json_resp->result);
|
|
|
|
rc = get_jsonrpc_method_json_parser(&resp, json_resp->result);
|
|
if (rc) {
|
|
SPDK_ERRLOG("get_jsonrpc_method_json_parser() failed\n");
|
|
goto out;
|
|
}
|
|
|
|
for (i = 0; i < (int)resp.method_num; i++) {
|
|
if (strcmp(method_name, resp.method_names[i]) == 0) {
|
|
rc = 0;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
rc = -1;
|
|
SPDK_ERRLOG("Method '%s' not found in response\n", method_name);
|
|
|
|
out:
|
|
for (i = 0; i < (int)resp.method_num; i++) {
|
|
SPDK_NOTICELOG("%s\n", resp.method_names[i]);
|
|
free(resp.method_names[i]);
|
|
}
|
|
|
|
spdk_jsonrpc_client_free_response(json_resp);
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
spdk_jsonrpc_client_check_null_params_method(struct spdk_jsonrpc_client *client)
|
|
{
|
|
int rc;
|
|
bool res = false;
|
|
struct spdk_jsonrpc_client_response *json_resp = NULL;
|
|
struct spdk_json_write_ctx *w;
|
|
struct spdk_jsonrpc_client_request *request;
|
|
|
|
request = spdk_jsonrpc_client_create_request();
|
|
if (request == NULL) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
w = spdk_jsonrpc_begin_request(request, 1, "test_null_params");
|
|
spdk_json_write_name(w, "params");
|
|
spdk_json_write_null(w);
|
|
spdk_jsonrpc_end_request(request, w);
|
|
spdk_jsonrpc_client_send_request(client, request);
|
|
|
|
rc = _rpc_client_wait_for_response(client);
|
|
if (rc <= 0) {
|
|
goto out;
|
|
}
|
|
|
|
json_resp = spdk_jsonrpc_client_get_response(client);
|
|
if (json_resp == NULL) {
|
|
SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
|
|
rc = -1;
|
|
goto out;
|
|
|
|
}
|
|
|
|
/* Check for error response */
|
|
if (json_resp->error != NULL) {
|
|
SPDK_ERRLOG("Unexpected error response\n");
|
|
rc = -1;
|
|
goto out;
|
|
}
|
|
|
|
assert(json_resp->result);
|
|
|
|
if (spdk_json_decode_bool(json_resp->result, &res) != 0 || res != true) {
|
|
SPDK_ERRLOG("Response is not a boolean or it is not 'true'\n");
|
|
rc = -EINVAL;
|
|
goto out;
|
|
} else {
|
|
rc = 0;
|
|
}
|
|
|
|
out:
|
|
spdk_jsonrpc_client_free_response(json_resp);
|
|
return rc;
|
|
}
|
|
|
|
static void
|
|
rpc_test_method_startup(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
|
|
{
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"rpc_test_method_startup(): Method body not implemented");
|
|
}
|
|
SPDK_RPC_REGISTER("test_method_startup", rpc_test_method_startup, SPDK_RPC_STARTUP)
|
|
|
|
static void
|
|
rpc_test_method_runtime(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
|
|
{
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"rpc_test_method_runtime(): Method body not implemented");
|
|
}
|
|
SPDK_RPC_REGISTER("test_method_runtime", rpc_test_method_runtime, SPDK_RPC_RUNTIME)
|
|
|
|
static void
|
|
rpc_test_method_null_params(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
if (params != NULL) {
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"rpc_test_method_null_params(): Parameters are not NULL");
|
|
return;
|
|
}
|
|
|
|
spdk_jsonrpc_send_bool_response(request, true);
|
|
}
|
|
SPDK_RPC_REGISTER("test_null_params", rpc_test_method_null_params, SPDK_RPC_RUNTIME)
|
|
|
|
static bool g_conn_close_detected;
|
|
|
|
static void
|
|
rpc_test_conn_close_cb(struct spdk_jsonrpc_server_conn *conn, void *ctx)
|
|
{
|
|
assert((intptr_t)ctx == 42);
|
|
g_conn_close_detected = true;
|
|
}
|
|
|
|
static void
|
|
rpc_hook_conn_close(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
|
|
{
|
|
struct spdk_jsonrpc_server_conn *conn = spdk_jsonrpc_get_conn(request);
|
|
int rc;
|
|
|
|
rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
|
|
if (rc != 0) {
|
|
|
|
rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
|
|
assert(rc == -ENOSPC);
|
|
}
|
|
|
|
rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
|
|
if (rc != -EEXIST) {
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"rpc_test_method_conn_close_detect(): rc != -EEXIST");
|
|
return;
|
|
}
|
|
|
|
rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(43));
|
|
if (rc != -ENOSPC) {
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"rpc_test_method_conn_close_detect(): rc != -ENOSPC");
|
|
return;
|
|
}
|
|
|
|
spdk_jsonrpc_send_bool_response(request, true);
|
|
}
|
|
SPDK_RPC_REGISTER("hook_conn_close", rpc_hook_conn_close, SPDK_RPC_RUNTIME | SPDK_RPC_STARTUP)
|
|
|
|
static int
|
|
spdk_jsonrpc_client_hook_conn_close(struct spdk_jsonrpc_client *client)
|
|
{
|
|
int rc;
|
|
bool res = false;
|
|
struct spdk_jsonrpc_client_response *json_resp = NULL;
|
|
struct spdk_json_write_ctx *w;
|
|
struct spdk_jsonrpc_client_request *request;
|
|
|
|
request = spdk_jsonrpc_client_create_request();
|
|
if (request == NULL) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
w = spdk_jsonrpc_begin_request(request, 1, "hook_conn_close");
|
|
spdk_jsonrpc_end_request(request, w);
|
|
spdk_jsonrpc_client_send_request(client, request);
|
|
|
|
rc = _rpc_client_wait_for_response(client);
|
|
if (rc <= 0) {
|
|
goto out;
|
|
}
|
|
|
|
json_resp = spdk_jsonrpc_client_get_response(client);
|
|
if (json_resp == NULL) {
|
|
SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
|
|
rc = -errno;
|
|
goto out;
|
|
|
|
}
|
|
|
|
/* Check for error response */
|
|
if (json_resp->error != NULL) {
|
|
SPDK_ERRLOG("Unexpected error response: %.*s\n", json_resp->error->len,
|
|
(char *)json_resp->error->start);
|
|
rc = -EIO;
|
|
goto out;
|
|
}
|
|
|
|
assert(json_resp->result);
|
|
if (spdk_json_decode_bool(json_resp->result, &res) != 0 || res != true) {
|
|
SPDK_ERRLOG("Response is not and boolean or if not 'true'\n");
|
|
rc = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
rc = 0;
|
|
out:
|
|
spdk_jsonrpc_client_free_response(json_resp);
|
|
return rc;
|
|
}
|
|
|
|
volatile int g_rpc_server_th_stop;
|
|
static sem_t g_rpc_server_th_listening;
|
|
|
|
static void *
|
|
rpc_server_th(void *arg)
|
|
{
|
|
int rc;
|
|
|
|
rc = spdk_rpc_listen(g_rpcsock_addr);
|
|
if (rc) {
|
|
fprintf(stderr, "spdk_rpc_listen() failed: %d\n", rc);
|
|
sem_post(&g_rpc_server_th_listening);
|
|
goto out;
|
|
}
|
|
|
|
sem_post(&g_rpc_server_th_listening);
|
|
|
|
while (!g_rpc_server_th_stop) {
|
|
spdk_rpc_accept();
|
|
usleep(50);
|
|
}
|
|
|
|
spdk_rpc_close();
|
|
out:
|
|
return (void *)(intptr_t)rc;
|
|
}
|
|
|
|
static void *
|
|
rpc_client_th(void *arg)
|
|
{
|
|
struct spdk_jsonrpc_client *client = NULL;
|
|
char *method_name = "rpc_get_methods";
|
|
int rc;
|
|
|
|
|
|
rc = sem_wait(&g_rpc_server_th_listening);
|
|
if (rc == -1) {
|
|
fprintf(stderr, "Timeout waiting for server thread to start listening: rc=%d errno=%d\n", rc,
|
|
errno);
|
|
goto out;
|
|
}
|
|
|
|
client = spdk_jsonrpc_client_connect(g_rpcsock_addr, g_addr_family);
|
|
if (!client) {
|
|
fprintf(stderr, "spdk_jsonrpc_client_connect() failed: %d\n", errno);
|
|
rc = -1;
|
|
goto out;
|
|
}
|
|
|
|
rc = spdk_jsonrpc_client_check_rpc_method(client, method_name);
|
|
if (rc) {
|
|
fprintf(stderr, "spdk_jsonrpc_client_check_rpc_method() failed: rc=%d errno=%d\n", rc, errno);
|
|
goto out;
|
|
}
|
|
|
|
rc = spdk_jsonrpc_client_check_null_params_method(client);
|
|
if (rc) {
|
|
fprintf(stderr, "spdk_jsonrpc_client_null_params_method() failed: rc=%d errno=%d\n", rc, errno);
|
|
goto out;
|
|
}
|
|
|
|
rc = spdk_jsonrpc_client_hook_conn_close(client);
|
|
if (rc) {
|
|
fprintf(stderr, "spdk_jsonrpc_client_hook_conn_close() failed: rc=%d errno=%d\n", rc, errno);
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
if (client) {
|
|
spdk_jsonrpc_client_close(client);
|
|
}
|
|
|
|
return (void *)(intptr_t)rc;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
pthread_t srv_tid, client_tid;
|
|
int srv_tid_valid;
|
|
int client_tid_valid = -1;
|
|
intptr_t th_rc = INTPTR_MIN;
|
|
int rc = 0, err_cnt = 0;
|
|
|
|
sem_init(&g_rpc_server_th_listening, 0, 0);
|
|
|
|
srv_tid_valid = pthread_create(&srv_tid, NULL, rpc_server_th, NULL);
|
|
if (srv_tid_valid != 0) {
|
|
fprintf(stderr, "pthread_create() failed to create server thread: %d\n", srv_tid_valid);
|
|
goto out;
|
|
}
|
|
|
|
client_tid_valid = pthread_create(&client_tid, NULL, rpc_client_th, NULL);
|
|
if (client_tid_valid != 0) {
|
|
fprintf(stderr, "pthread_create(): failed to create client thread: %d\n", client_tid_valid);
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
if (client_tid_valid == 0) {
|
|
rc = pthread_join(client_tid, (void **)&th_rc);
|
|
if (rc) {
|
|
fprintf(stderr, "pthread_join() on client thread failed (rc: %d)\n", rc);
|
|
err_cnt++;
|
|
} else if (th_rc) {
|
|
fprintf(stderr, "client thread failed reported failure(thread rc: %d)\n", (int)th_rc);
|
|
err_cnt++;
|
|
}
|
|
}
|
|
|
|
g_rpc_server_th_stop = 1;
|
|
|
|
if (srv_tid_valid == 0) {
|
|
rc = pthread_join(srv_tid, (void **)&th_rc);
|
|
if (rc) {
|
|
fprintf(stderr, "pthread_join() on server thread failed (rc: %d)\n", rc);
|
|
err_cnt++;
|
|
} else if (th_rc) {
|
|
fprintf(stderr, "server thread failed reported failure(thread rc: %d)\n", (int)th_rc);
|
|
err_cnt++;
|
|
}
|
|
}
|
|
|
|
if (g_conn_close_detected == false) {
|
|
fprintf(stderr, "Connection close not detected\n");
|
|
err_cnt++;
|
|
}
|
|
|
|
sem_destroy(&g_rpc_server_th_listening);
|
|
|
|
fprintf(stderr, "%s\n", err_cnt == 0 ? "OK" : "FAILED");
|
|
return err_cnt ? EXIT_FAILURE : 0;
|
|
}
|