simple-ipc: preparations for supporting binary messages.

Add `command_len` argument to the Simple IPC API. In my original Simple IPC API, I assumed that the request would always be a null-terminated string of text characters. The `command` argument was just a `const char *`. I found a caller that would like to pass a binary command to the daemon, so I am amending the Simple IPC API to receive `const char *command, size_t command_len` arguments. I considered changing the `command` argument to be a `void *`, but the IPC layer simply passes it to the pkt-line layer which takes a `const char *`, so to avoid confusion I left it as is. Note, the response side has always been a `struct strbuf` which includes the buffer and length, so we already support returning a binary answer. (Yes, it feels a little weird returning a binary buffer in a `strbuf`, but it works.) Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff Hostetler committed Sep 20, 2021 at 15:36 UTC a3e2033e04ae06ac4f1cda582ac83944df29830d
4 files changed +46 -23
compat/simple-ipc/ipc-unix-socket.c
+9 -5
@@ -168,7 +168,8 @@ void ipc_client_close_connection(struct ipc_client_connection *connection)
168
169 int ipc_client_send_command_to_connection(
170 struct ipc_client_connection *connection,
171 - const char *message, struct strbuf *answer)
171 + const char *message, size_t message_len,
172 + struct strbuf *answer)
173 {
174 int ret = 0;
175
@@ -176,7 +177,7 @@ int ipc_client_send_command_to_connection(
177
178 trace2_region_enter("ipc-client", "send-command", NULL);
179
179 - if (write_packetized_from_buf_no_flush(message, strlen(message),
180 + if (write_packetized_from_buf_no_flush(message, message_len,
181 connection->fd) < 0 ||
182 packet_flush_gently(connection->fd) < 0) {
183 ret = error(_("could not send IPC command"));
@@ -197,7 +198,8 @@ done:
198
199 int ipc_client_send_command(const char *path,
200 const struct ipc_client_connect_options *options,
200 - const char *message, struct strbuf *answer)
201 + const char *message, size_t message_len,
202 + struct strbuf *answer)
203 {
204 int ret = -1;
205 enum ipc_active_state state;
@@ -208,7 +210,9 @@ int ipc_client_send_command(const char *path,
210 if (state != IPC_STATE__LISTENING)
211 return ret;
212
211 - ret = ipc_client_send_command_to_connection(connection, message, answer);
213 + ret = ipc_client_send_command_to_connection(connection,
214 + message, message_len,
215 + answer);
216
217 ipc_client_close_connection(connection);
218
@@ -503,7 +507,7 @@ static int worker_thread__do_io(
507 if (ret >= 0) {
508 ret = worker_thread_data->server_data->application_cb(
509 worker_thread_data->server_data->application_data,
506 - buf.buf, do_io_reply_callback, &reply_data);
510 + buf.buf, buf.len, do_io_reply_callback, &reply_data);
511
512 packet_flush_gently(reply_data.fd);
513 }
compat/simple-ipc/ipc-win32.c
+9 -5
@@ -208,7 +208,8 @@ void ipc_client_close_connection(struct ipc_client_connection *connection)
208
209 int ipc_client_send_command_to_connection(
210 struct ipc_client_connection *connection,
211 - const char *message, struct strbuf *answer)
211 + const char *message, size_t message_len,
212 + struct strbuf *answer)
213 {
214 int ret = 0;
215
@@ -216,7 +217,7 @@ int ipc_client_send_command_to_connection(
217
218 trace2_region_enter("ipc-client", "send-command", NULL);
219
219 - if (write_packetized_from_buf_no_flush(message, strlen(message),
220 + if (write_packetized_from_buf_no_flush(message, message_len,
221 connection->fd) < 0 ||
222 packet_flush_gently(connection->fd) < 0) {
223 ret = error(_("could not send IPC command"));
@@ -239,7 +240,8 @@ done:
240
241 int ipc_client_send_command(const char *path,
242 const struct ipc_client_connect_options *options,
242 - const char *message, struct strbuf *response)
243 + const char *message, size_t message_len,
244 + struct strbuf *response)
245 {
246 int ret = -1;
247 enum ipc_active_state state;
@@ -250,7 +252,9 @@ int ipc_client_send_command(const char *path,
252 if (state != IPC_STATE__LISTENING)
253 return ret;
254
253 - ret = ipc_client_send_command_to_connection(connection, message, response);
255 + ret = ipc_client_send_command_to_connection(connection,
256 + message, message_len,
257 + response);
258
259 ipc_client_close_connection(connection);
260
@@ -458,7 +462,7 @@ static int do_io(struct ipc_server_thread_data *server_thread_data)
462 if (ret >= 0) {
463 ret = server_thread_data->server_data->application_cb(
464 server_thread_data->server_data->application_data,
461 - buf.buf, do_io_reply_callback, &reply_data);
465 + buf.buf, buf.len, do_io_reply_callback, &reply_data);
466
467 packet_flush_gently(reply_data.fd);
468
simple-ipc.h
+5 -2
@@ -107,7 +107,8 @@ void ipc_client_close_connection(struct ipc_client_connection *connection);
107 */
108 int ipc_client_send_command_to_connection(
109 struct ipc_client_connection *connection,
110 - const char *message, struct strbuf *answer);
110 + const char *message, size_t message_len,
111 + struct strbuf *answer);
112
113 /*
114 * Used by the client to synchronously connect and send and receive a
@@ -119,7 +120,8 @@ int ipc_client_send_command_to_connection(
120 */
121 int ipc_client_send_command(const char *path,
122 const struct ipc_client_connect_options *options,
122 - const char *message, struct strbuf *answer);
123 + const char *message, size_t message_len,
124 + struct strbuf *answer);
125
126 /*
127 * Simple IPC Server Side API.
@@ -144,6 +146,7 @@ typedef int (ipc_server_reply_cb)(struct ipc_server_reply_data *,
146 */
147 typedef int (ipc_server_application_cb)(void *application_data,
148 const char *request,
149 + size_t request_len,
150 ipc_server_reply_cb *reply_cb,
151 struct ipc_server_reply_data *reply_data);
152
t/helper/test-simple-ipc.c
+23 -11
@@ -112,7 +112,7 @@ static int app__slow_command(ipc_server_reply_cb *reply_cb,
112 /*
113 * The client sent a command followed by a (possibly very) large buffer.
114 */
115 -static int app__sendbytes_command(const char *received,
115 +static int app__sendbytes_command(const char *received, size_t received_len,
116 ipc_server_reply_cb *reply_cb,
117 struct ipc_server_reply_data *reply_data)
118 {
@@ -123,6 +123,13 @@ static int app__sendbytes_command(const char *received,
123 int errs = 0;
124 int ret;
125
126 + /*
127 + * The test is setup to send:
128 + * "sendbytes" SP <n * char>
129 + */
130 + if (received_len < strlen("sendbytes "))
131 + BUG("received_len is short in app__sendbytes_command");
132 +
133 if (skip_prefix(received, "sendbytes ", &p))
134 len_ballast = strlen(p);
135
@@ -160,7 +167,7 @@ static ipc_server_application_cb test_app_cb;
167 * by this application.
168 */
169 static int test_app_cb(void *application_data,
163 - const char *command,
170 + const char *command, size_t command_len,
171 ipc_server_reply_cb *reply_cb,
172 struct ipc_server_reply_data *reply_data)
173 {
@@ -173,7 +180,7 @@ static int test_app_cb(void *application_data,
180 if (application_data != (void*)&my_app_data)
181 BUG("application_cb: application_data pointer wrong");
182
176 - if (!strcmp(command, "quit")) {
183 + if (command_len == 4 && !strncmp(command, "quit", 4)) {
184 /*
185 * The client sent a "quit" command. This is an async
186 * request for the server to shutdown.
@@ -193,22 +200,23 @@ static int test_app_cb(void *application_data,
200 return SIMPLE_IPC_QUIT;
201 }
202
196 - if (!strcmp(command, "ping")) {
203 + if (command_len == 4 && !strncmp(command, "ping", 4)) {
204 const char *answer = "pong";
205 return reply_cb(reply_data, answer, strlen(answer));
206 }
207
201 - if (!strcmp(command, "big"))
208 + if (command_len == 3 && !strncmp(command, "big", 3))
209 return app__big_command(reply_cb, reply_data);
210
204 - if (!strcmp(command, "chunk"))
211 + if (command_len == 5 && !strncmp(command, "chunk", 5))
212 return app__chunk_command(reply_cb, reply_data);
213
207 - if (!strcmp(command, "slow"))
214 + if (command_len == 4 && !strncmp(command, "slow", 4))
215 return app__slow_command(reply_cb, reply_data);
216
210 - if (starts_with(command, "sendbytes "))
211 - return app__sendbytes_command(command, reply_cb, reply_data);
217 + if (command_len >= 10 && starts_with(command, "sendbytes "))
218 + return app__sendbytes_command(command, command_len,
219 + reply_cb, reply_data);
220
221 return app__unhandled_command(command, reply_cb, reply_data);
222 }
@@ -488,7 +496,9 @@ static int client__send_ipc(void)
496 options.wait_if_busy = 1;
497 options.wait_if_not_found = 0;
498
491 - if (!ipc_client_send_command(cl_args.path, &options, command, &buf)) {
499 + if (!ipc_client_send_command(cl_args.path, &options,
500 + command, strlen(command),
501 + &buf)) {
502 if (buf.len) {
503 printf("%s\n", buf.buf);
504 fflush(stdout);
@@ -556,7 +566,9 @@ static int do_sendbytes(int bytecount, char byte, const char *path,
566 strbuf_addstr(&buf_send, "sendbytes ");
567 strbuf_addchars(&buf_send, byte, bytecount);
568
559 - if (!ipc_client_send_command(path, options, buf_send.buf, &buf_resp)) {
569 + if (!ipc_client_send_command(path, options,
570 + buf_send.buf, buf_send.len,
571 + &buf_resp)) {
572 strbuf_rtrim(&buf_resp);
573 printf("sent:%c%08d %s\n", byte, bytecount, buf_resp.buf);
574 fflush(stdout);