1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "librpc/rpc.h"
4#include "librpc/rpc_client.h"
5#include "librpc/rpc_server.h"
6
7#include <librpc/internal.h>
8#include <mos/syscall/usermode.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13#define RPC_TEST_SERVERNAME "testserver"
14
15enum
16{
17 TESTSERVER_PING = 0,
18 TESTSERVER_ECHO = 1,
19 TESTSERVER_CALCULATE = 2,
20 TESTSERVER_CLOSE = 3,
21};
22
23enum
24{
25 CALC_ADD = 0,
26 CALC_SUB = 1,
27 CALC_MUL = 2,
28 CALC_DIV = 3,
29};
30
31static rpc_result_code_t testserver_ping(rpc_context_t *context)
32{
33 MOS_UNUSED(context);
34 printf(format: "!!!!!!!!!!! ping !!!!!!!!!!!\n");
35 return 0;
36}
37
38static rpc_result_code_t testserver_echo(rpc_context_t *context)
39{
40 size_t arg1_size = 0;
41 const char *arg1 = rpc_arg_next(args: context, size: &arg1_size);
42 printf(format: "echo server: received '%.*s'\n", (int) arg1_size, arg1);
43 rpc_write_result(context, data: arg1, size: arg1_size);
44
45 return 0;
46}
47
48static rpc_result_code_t testserver_calculation(rpc_context_t *context)
49{
50 size_t arg1_size;
51 const int *a = rpc_arg_next(args: context, size: &arg1_size);
52 size_t arg2_size;
53 const int *b = rpc_arg_next(args: context, size: &arg2_size);
54 size_t arg3_size;
55 const int *c = rpc_arg_next(args: context, size: &arg3_size);
56
57 int result = 0;
58 switch (*b)
59 {
60 case CALC_ADD: result = *a + *c; break;
61 case CALC_SUB: result = *a - *c; break;
62 case CALC_MUL: result = *a * *c; break;
63 case CALC_DIV: result = *a / *c; break;
64 }
65
66 static const char op_names[] = { '+', '-', '*', '/' };
67 printf(format: "calculation server: %d %c %d = %d\n", *a, op_names[*b], *c, result);
68
69 rpc_write_result(context, data: &result, size: sizeof(result));
70 return 0;
71}
72
73static rpc_result_code_t rpc_server_do_close(rpc_context_t *context)
74{
75 puts(string: "rpc_server_close");
76 rpc_server_close(server: rpc_context_get_server(context));
77 return 0;
78}
79
80void run_server(void)
81{
82 static const rpc_function_info_t testserver_functions[] = {
83 { TESTSERVER_PING, testserver_ping, 0, .args_type = { 0 } },
84 { TESTSERVER_ECHO, testserver_echo, 1, .args_type = { RPC_ARGTYPE_STRING } },
85 { TESTSERVER_CALCULATE, testserver_calculation, 3, .args_type = { RPC_ARGTYPE_INT32, RPC_ARGTYPE_INT32, RPC_ARGTYPE_INT32 } },
86 { TESTSERVER_CLOSE, rpc_server_do_close, 0, .args_type = { 0 } },
87 };
88
89 rpc_server_t *server = rpc_server_create(RPC_TEST_SERVERNAME, NULL);
90 rpc_server_register_functions(server, functions: testserver_functions, MOS_ARRAY_SIZE(testserver_functions));
91 rpc_server_exec(server);
92
93 printf(format: "rpc_server_destroy\n");
94 rpc_server_destroy(server);
95 printf(format: "rpc_server_destroy done\n");
96}
97
98void run_client(void)
99{
100 rpc_server_stub_t *stub = rpc_client_create(RPC_TEST_SERVERNAME);
101
102 if (!stub)
103 {
104 printf(format: "rpc_client_create failed\n");
105 return;
106 }
107
108 // ping
109 {
110 rpc_call_t *ping_call = rpc_call_create(server: stub, function_id: TESTSERVER_PING);
111 rpc_call_exec(call: ping_call, NULL, NULL);
112 rpc_call_destroy(call: ping_call);
113 }
114
115 // echo
116 {
117 rpc_call_t *echo_call = rpc_call_create(server: stub, function_id: TESTSERVER_ECHO);
118 rpc_call_arg_string(call: echo_call, arg: "hello world");
119
120 char *result;
121 size_t result_size;
122 rpc_call_exec(call: echo_call, result_data: (void *) &result, result_size: &result_size);
123 rpc_call_destroy(call: echo_call);
124
125 printf(format: "echo client: received '%.*s'\n", (int) result_size, result);
126 free(pointer: result);
127 }
128
129 // calculation
130 {
131 rpc_call_t *calc_call = rpc_call_create(server: stub, function_id: TESTSERVER_CALCULATE);
132 int a = 10;
133 int b = CALC_ADD;
134 int c = 5;
135 rpc_call_arg_s32(call: calc_call, arg: a);
136 rpc_call_arg_s32(call: calc_call, arg: b);
137 rpc_call_arg_s32(call: calc_call, arg: c);
138
139 int *result;
140 size_t result_size;
141 rpc_call_exec(call: calc_call, result_data: (void *) &result, result_size: &result_size);
142 rpc_call_destroy(call: calc_call);
143
144 printf(format: "calculation client: received '%d'\n", *result);
145 free(pointer: result);
146
147 rpc_call_t *calc_call2 = rpc_call_create(server: stub, function_id: TESTSERVER_CALCULATE);
148 a = 10;
149 b = CALC_SUB;
150 c = 5;
151 rpc_call_arg_s32(call: calc_call2, arg: a);
152 rpc_call_arg_s32(call: calc_call2, arg: b);
153 rpc_call_arg_s32(call: calc_call2, arg: c);
154
155 rpc_call_exec(call: calc_call2, result_data: (void *) &result, result_size: &result_size);
156 rpc_call_destroy(call: calc_call2);
157
158 printf(format: "calculation client: received '%d'\n", *result);
159 free(pointer: result);
160 }
161
162 // calculation using argspec
163 {
164 rpc_result_t result;
165 rpc_result_code_t result_code = rpc_simple_call(stub, funcid: TESTSERVER_CALCULATE, result: (void *) &result, argspec: "iii", 10, CALC_MUL, 5);
166 printf(format: "calculation client (spec): received '%d' (result_code=%d)\n", *(int *) result.data, result_code);
167 }
168
169 // close
170 {
171 rpc_simple_call(stub, funcid: TESTSERVER_CLOSE, NULL, argspec: "");
172 }
173
174 rpc_client_destroy(server: stub);
175 puts(string: "all done");
176}
177
178int main()
179{
180 pid_t child = syscall_fork();
181 if (child != 0)
182 {
183 run_server();
184 }
185 else
186 {
187 run_client();
188 }
189
190 return 0;
191}
192