/src/git/compat/simple-ipc/ipc-unix-socket.c
Line | Count | Source |
1 | | #include "git-compat-util.h" |
2 | | #include "gettext.h" |
3 | | #include "simple-ipc.h" |
4 | | #include "strbuf.h" |
5 | | #include "thread-utils.h" |
6 | | #include "trace2.h" |
7 | | #include "unix-socket.h" |
8 | | #include "unix-stream-server.h" |
9 | | |
10 | | #ifndef SUPPORTS_SIMPLE_IPC |
11 | | /* |
12 | | * This source file should only be compiled when Simple IPC is supported. |
13 | | * See the top-level Makefile. |
14 | | */ |
15 | | #error SUPPORTS_SIMPLE_IPC not defined |
16 | | #endif |
17 | | |
18 | | enum ipc_active_state ipc_get_active_state(const char *path) |
19 | 0 | { |
20 | 0 | enum ipc_active_state state = IPC_STATE__OTHER_ERROR; |
21 | 0 | struct ipc_client_connect_options options |
22 | 0 | = IPC_CLIENT_CONNECT_OPTIONS_INIT; |
23 | 0 | struct stat st; |
24 | 0 | struct ipc_client_connection *connection_test = NULL; |
25 | |
|
26 | 0 | options.wait_if_busy = 0; |
27 | 0 | options.wait_if_not_found = 0; |
28 | |
|
29 | 0 | if (lstat(path, &st) == -1) { |
30 | 0 | switch (errno) { |
31 | 0 | case ENOENT: |
32 | 0 | case ENOTDIR: |
33 | 0 | return IPC_STATE__NOT_LISTENING; |
34 | 0 | default: |
35 | 0 | return IPC_STATE__INVALID_PATH; |
36 | 0 | } |
37 | 0 | } |
38 | | |
39 | | #ifdef __CYGWIN__ |
40 | | /* |
41 | | * Cygwin emulates Unix sockets by writing special-crafted files whose |
42 | | * `system` bit is set. |
43 | | * |
44 | | * If we are too fast, Cygwin might still be in the process of marking |
45 | | * the underlying file as a system file. Until then, we will not see a |
46 | | * Unix socket here, but a plain file instead. Just in case that this |
47 | | * is happening, wait a little and try again. |
48 | | */ |
49 | | { |
50 | | static const int delay[] = { 1, 10, 20, 40, -1 }; |
51 | | int i; |
52 | | |
53 | | for (i = 0; S_ISREG(st.st_mode) && delay[i] > 0; i++) { |
54 | | sleep_millisec(delay[i]); |
55 | | if (lstat(path, &st) == -1) |
56 | | return IPC_STATE__INVALID_PATH; |
57 | | } |
58 | | } |
59 | | #endif |
60 | | |
61 | | /* also complain if a plain file is in the way */ |
62 | 0 | if ((st.st_mode & S_IFMT) != S_IFSOCK) |
63 | 0 | return IPC_STATE__INVALID_PATH; |
64 | | |
65 | | /* |
66 | | * Just because the filesystem has a S_IFSOCK type inode |
67 | | * at `path`, doesn't mean it that there is a server listening. |
68 | | * Ping it to be sure. |
69 | | */ |
70 | 0 | state = ipc_client_try_connect(path, &options, &connection_test); |
71 | 0 | ipc_client_close_connection(connection_test); |
72 | |
|
73 | 0 | return state; |
74 | 0 | } |
75 | | |
76 | | /* |
77 | | * Retry frequency when trying to connect to a server. |
78 | | * |
79 | | * This value should be short enough that we don't seriously delay our |
80 | | * caller, but not fast enough that our spinning puts pressure on the |
81 | | * system. |
82 | | */ |
83 | 0 | #define WAIT_STEP_MS (50) |
84 | | |
85 | | /* |
86 | | * Try to connect to the server. If the server is just starting up or |
87 | | * is very busy, we may not get a connection the first time. |
88 | | */ |
89 | | static enum ipc_active_state connect_to_server( |
90 | | const char *path, |
91 | | int timeout_ms, |
92 | | const struct ipc_client_connect_options *options, |
93 | | int *pfd) |
94 | 0 | { |
95 | 0 | int k; |
96 | |
|
97 | 0 | *pfd = -1; |
98 | |
|
99 | 0 | for (k = 0; k < timeout_ms; k += WAIT_STEP_MS) { |
100 | 0 | int fd = unix_stream_connect(path, options->uds_disallow_chdir); |
101 | |
|
102 | 0 | if (fd != -1) { |
103 | 0 | *pfd = fd; |
104 | 0 | return IPC_STATE__LISTENING; |
105 | 0 | } |
106 | | |
107 | 0 | if (errno == ENOENT) { |
108 | 0 | if (!options->wait_if_not_found) |
109 | 0 | return IPC_STATE__PATH_NOT_FOUND; |
110 | | |
111 | 0 | goto sleep_and_try_again; |
112 | 0 | } |
113 | | |
114 | 0 | if (errno == ETIMEDOUT) { |
115 | 0 | if (!options->wait_if_busy) |
116 | 0 | return IPC_STATE__NOT_LISTENING; |
117 | | |
118 | 0 | goto sleep_and_try_again; |
119 | 0 | } |
120 | | |
121 | 0 | if (errno == ECONNREFUSED) { |
122 | 0 | if (!options->wait_if_busy) |
123 | 0 | return IPC_STATE__NOT_LISTENING; |
124 | | |
125 | 0 | goto sleep_and_try_again; |
126 | 0 | } |
127 | | |
128 | 0 | return IPC_STATE__OTHER_ERROR; |
129 | | |
130 | 0 | sleep_and_try_again: |
131 | 0 | sleep_millisec(WAIT_STEP_MS); |
132 | 0 | } |
133 | | |
134 | 0 | return IPC_STATE__NOT_LISTENING; |
135 | 0 | } |
136 | | |
137 | | /* |
138 | | * The total amount of time that we are willing to wait when trying to |
139 | | * connect to a server. |
140 | | * |
141 | | * When the server is first started, it might take a little while for |
142 | | * it to become ready to service requests. Likewise, the server may |
143 | | * be very (temporarily) busy and not respond to our connections. |
144 | | * |
145 | | * We should gracefully and silently handle those conditions and try |
146 | | * again for a reasonable time period. |
147 | | * |
148 | | * The value chosen here should be long enough for the server |
149 | | * to reliably heal from the above conditions. |
150 | | */ |
151 | 0 | #define MY_CONNECTION_TIMEOUT_MS (1000) |
152 | | |
153 | | enum ipc_active_state ipc_client_try_connect( |
154 | | const char *path, |
155 | | const struct ipc_client_connect_options *options, |
156 | | struct ipc_client_connection **p_connection) |
157 | 0 | { |
158 | 0 | enum ipc_active_state state = IPC_STATE__OTHER_ERROR; |
159 | 0 | int fd = -1; |
160 | |
|
161 | 0 | *p_connection = NULL; |
162 | |
|
163 | 0 | trace2_region_enter("ipc-client", "try-connect", NULL); |
164 | 0 | trace2_data_string("ipc-client", NULL, "try-connect/path", path); |
165 | |
|
166 | 0 | state = connect_to_server(path, MY_CONNECTION_TIMEOUT_MS, |
167 | 0 | options, &fd); |
168 | |
|
169 | 0 | trace2_data_intmax("ipc-client", NULL, "try-connect/state", |
170 | 0 | (intmax_t)state); |
171 | 0 | trace2_region_leave("ipc-client", "try-connect", NULL); |
172 | |
|
173 | 0 | if (state == IPC_STATE__LISTENING) { |
174 | 0 | (*p_connection) = xcalloc(1, sizeof(struct ipc_client_connection)); |
175 | 0 | (*p_connection)->fd = fd; |
176 | 0 | } |
177 | |
|
178 | 0 | return state; |
179 | 0 | } |
180 | | |
181 | | void ipc_client_close_connection(struct ipc_client_connection *connection) |
182 | 0 | { |
183 | 0 | if (!connection) |
184 | 0 | return; |
185 | | |
186 | 0 | if (connection->fd != -1) |
187 | 0 | close(connection->fd); |
188 | |
|
189 | 0 | free(connection); |
190 | 0 | } |
191 | | |
192 | | int ipc_client_send_command_to_connection( |
193 | | struct ipc_client_connection *connection, |
194 | | const char *message, size_t message_len, |
195 | | struct strbuf *answer) |
196 | 0 | { |
197 | 0 | int ret = 0; |
198 | |
|
199 | 0 | strbuf_setlen(answer, 0); |
200 | |
|
201 | 0 | trace2_region_enter("ipc-client", "send-command", NULL); |
202 | |
|
203 | 0 | if (write_packetized_from_buf_no_flush(message, message_len, |
204 | 0 | connection->fd) < 0 || |
205 | 0 | packet_flush_gently(connection->fd) < 0) { |
206 | 0 | ret = error(_("could not send IPC command")); |
207 | 0 | goto done; |
208 | 0 | } |
209 | | |
210 | 0 | if (read_packetized_to_strbuf( |
211 | 0 | connection->fd, answer, |
212 | 0 | PACKET_READ_GENTLE_ON_EOF | PACKET_READ_GENTLE_ON_READ_ERROR) < 0) { |
213 | 0 | ret = error(_("could not read IPC response")); |
214 | 0 | goto done; |
215 | 0 | } |
216 | | |
217 | 0 | done: |
218 | 0 | trace2_region_leave("ipc-client", "send-command", NULL); |
219 | 0 | return ret; |
220 | 0 | } |
221 | | |
222 | | int ipc_client_send_command(const char *path, |
223 | | const struct ipc_client_connect_options *options, |
224 | | const char *message, size_t message_len, |
225 | | struct strbuf *answer) |
226 | 0 | { |
227 | 0 | int ret = -1; |
228 | 0 | enum ipc_active_state state; |
229 | 0 | struct ipc_client_connection *connection = NULL; |
230 | |
|
231 | 0 | state = ipc_client_try_connect(path, options, &connection); |
232 | |
|
233 | 0 | if (state != IPC_STATE__LISTENING) |
234 | 0 | return ret; |
235 | | |
236 | 0 | ret = ipc_client_send_command_to_connection(connection, |
237 | 0 | message, message_len, |
238 | 0 | answer); |
239 | |
|
240 | 0 | ipc_client_close_connection(connection); |
241 | |
|
242 | 0 | return ret; |
243 | 0 | } |
244 | | |
245 | | static int set_socket_blocking_flag(int fd, int make_nonblocking) |
246 | 0 | { |
247 | 0 | int flags; |
248 | |
|
249 | 0 | flags = fcntl(fd, F_GETFL, NULL); |
250 | |
|
251 | 0 | if (flags < 0) |
252 | 0 | return -1; |
253 | | |
254 | 0 | if (make_nonblocking) |
255 | 0 | flags |= O_NONBLOCK; |
256 | 0 | else |
257 | 0 | flags &= ~O_NONBLOCK; |
258 | |
|
259 | 0 | return fcntl(fd, F_SETFL, flags); |
260 | 0 | } |
261 | | |
262 | | /* |
263 | | * Magic numbers used to annotate callback instance data. |
264 | | * These are used to help guard against accidentally passing the |
265 | | * wrong instance data across multiple levels of callbacks (which |
266 | | * is easy to do if there are `void*` arguments). |
267 | | */ |
268 | | enum magic { |
269 | | MAGIC_SERVER_REPLY_DATA, |
270 | | MAGIC_WORKER_THREAD_DATA, |
271 | | MAGIC_ACCEPT_THREAD_DATA, |
272 | | MAGIC_SERVER_DATA, |
273 | | }; |
274 | | |
275 | | struct ipc_server_reply_data { |
276 | | enum magic magic; |
277 | | int fd; |
278 | | struct ipc_worker_thread_data *worker_thread_data; |
279 | | }; |
280 | | |
281 | | struct ipc_worker_thread_data { |
282 | | enum magic magic; |
283 | | struct ipc_worker_thread_data *next_thread; |
284 | | struct ipc_server_data *server_data; |
285 | | pthread_t pthread_id; |
286 | | }; |
287 | | |
288 | | struct ipc_accept_thread_data { |
289 | | enum magic magic; |
290 | | struct ipc_server_data *server_data; |
291 | | |
292 | | struct unix_ss_socket *server_socket; |
293 | | |
294 | | int fd_send_shutdown; |
295 | | int fd_wait_shutdown; |
296 | | pthread_t pthread_id; |
297 | | }; |
298 | | |
299 | | /* |
300 | | * With unix-sockets, the conceptual "ipc-server" is implemented as a single |
301 | | * controller "accept-thread" thread and a pool of "worker-thread" threads. |
302 | | * The former does the usual `accept()` loop and dispatches connections |
303 | | * to an idle worker thread. The worker threads wait in an idle loop for |
304 | | * a new connection, communicate with the client and relay data to/from |
305 | | * the `application_cb` and then wait for another connection from the |
306 | | * server thread. This avoids the overhead of constantly creating and |
307 | | * destroying threads. |
308 | | */ |
309 | | struct ipc_server_data { |
310 | | enum magic magic; |
311 | | ipc_server_application_cb *application_cb; |
312 | | void *application_data; |
313 | | struct strbuf buf_path; |
314 | | |
315 | | struct ipc_accept_thread_data *accept_thread; |
316 | | struct ipc_worker_thread_data *worker_thread_list; |
317 | | |
318 | | pthread_mutex_t work_available_mutex; |
319 | | pthread_cond_t work_available_cond; |
320 | | |
321 | | /* |
322 | | * Accepted but not yet processed client connections are kept |
323 | | * in a circular buffer FIFO. The queue is empty when the |
324 | | * positions are equal. |
325 | | */ |
326 | | int *fifo_fds; |
327 | | int queue_size; |
328 | | int back_pos; |
329 | | int front_pos; |
330 | | |
331 | | int started; |
332 | | int shutdown_requested; |
333 | | int is_stopped; |
334 | | }; |
335 | | |
336 | | /* |
337 | | * Remove and return the oldest queued connection. |
338 | | * |
339 | | * Returns -1 if empty. |
340 | | */ |
341 | | static int fifo_dequeue(struct ipc_server_data *server_data) |
342 | 0 | { |
343 | | /* ASSERT holding mutex */ |
344 | |
|
345 | 0 | int fd; |
346 | |
|
347 | 0 | if (server_data->back_pos == server_data->front_pos) |
348 | 0 | return -1; |
349 | | |
350 | 0 | fd = server_data->fifo_fds[server_data->front_pos]; |
351 | 0 | server_data->fifo_fds[server_data->front_pos] = -1; |
352 | |
|
353 | 0 | server_data->front_pos++; |
354 | 0 | if (server_data->front_pos == server_data->queue_size) |
355 | 0 | server_data->front_pos = 0; |
356 | |
|
357 | 0 | return fd; |
358 | 0 | } |
359 | | |
360 | | /* |
361 | | * Push a new fd onto the back of the queue. |
362 | | * |
363 | | * Drop it and return -1 if queue is already full. |
364 | | */ |
365 | | static int fifo_enqueue(struct ipc_server_data *server_data, int fd) |
366 | 0 | { |
367 | | /* ASSERT holding mutex */ |
368 | |
|
369 | 0 | int next_back_pos; |
370 | |
|
371 | 0 | next_back_pos = server_data->back_pos + 1; |
372 | 0 | if (next_back_pos == server_data->queue_size) |
373 | 0 | next_back_pos = 0; |
374 | |
|
375 | 0 | if (next_back_pos == server_data->front_pos) { |
376 | | /* Queue is full. Just drop it. */ |
377 | 0 | close(fd); |
378 | 0 | return -1; |
379 | 0 | } |
380 | | |
381 | 0 | server_data->fifo_fds[server_data->back_pos] = fd; |
382 | 0 | server_data->back_pos = next_back_pos; |
383 | |
|
384 | 0 | return fd; |
385 | 0 | } |
386 | | |
387 | | /* |
388 | | * Wait for a connection to be queued to the FIFO and return it. |
389 | | * |
390 | | * Returns -1 if someone has already requested a shutdown. |
391 | | */ |
392 | | static int worker_thread__wait_for_connection( |
393 | | struct ipc_worker_thread_data *worker_thread_data) |
394 | 0 | { |
395 | | /* ASSERT NOT holding mutex */ |
396 | |
|
397 | 0 | struct ipc_server_data *server_data = worker_thread_data->server_data; |
398 | 0 | int fd = -1; |
399 | |
|
400 | 0 | pthread_mutex_lock(&server_data->work_available_mutex); |
401 | 0 | for (;;) { |
402 | 0 | if (server_data->shutdown_requested) |
403 | 0 | break; |
404 | | |
405 | 0 | fd = fifo_dequeue(server_data); |
406 | 0 | if (fd >= 0) |
407 | 0 | break; |
408 | | |
409 | 0 | pthread_cond_wait(&server_data->work_available_cond, |
410 | 0 | &server_data->work_available_mutex); |
411 | 0 | } |
412 | 0 | pthread_mutex_unlock(&server_data->work_available_mutex); |
413 | |
|
414 | 0 | return fd; |
415 | 0 | } |
416 | | |
417 | | /* |
418 | | * Forward declare our reply callback function so that any compiler |
419 | | * errors are reported when we actually define the function (in addition |
420 | | * to any errors reported when we try to pass this callback function as |
421 | | * a parameter in a function call). The former are easier to understand. |
422 | | */ |
423 | | static ipc_server_reply_cb do_io_reply_callback; |
424 | | |
425 | | /* |
426 | | * Relay application's response message to the client process. |
427 | | * (We do not flush at this point because we allow the caller |
428 | | * to chunk data to the client thru us.) |
429 | | */ |
430 | | static int do_io_reply_callback(struct ipc_server_reply_data *reply_data, |
431 | | const char *response, size_t response_len) |
432 | 0 | { |
433 | 0 | if (reply_data->magic != MAGIC_SERVER_REPLY_DATA) |
434 | 0 | BUG("reply_cb called with wrong instance data"); |
435 | | |
436 | 0 | return write_packetized_from_buf_no_flush(response, response_len, |
437 | 0 | reply_data->fd); |
438 | 0 | } |
439 | | |
440 | | /* A randomly chosen value. */ |
441 | 0 | #define MY_WAIT_POLL_TIMEOUT_MS (10) |
442 | | |
443 | | /* |
444 | | * If the client hangs up without sending any data on the wire, just |
445 | | * quietly close the socket and ignore this client. |
446 | | * |
447 | | * This worker thread is committed to reading the IPC request data |
448 | | * from the client at the other end of this fd. Wait here for the |
449 | | * client to actually put something on the wire -- because if the |
450 | | * client just does a ping (connect and hangup without sending any |
451 | | * data), our use of the pkt-line read routines will spew an error |
452 | | * message. |
453 | | * |
454 | | * Return -1 if the client hung up. |
455 | | * Return 0 if data (possibly incomplete) is ready. |
456 | | */ |
457 | | static int worker_thread__wait_for_io_start( |
458 | | struct ipc_worker_thread_data *worker_thread_data, |
459 | | int fd) |
460 | 0 | { |
461 | 0 | struct ipc_server_data *server_data = worker_thread_data->server_data; |
462 | 0 | struct pollfd pollfd[1]; |
463 | 0 | int result; |
464 | |
|
465 | 0 | for (;;) { |
466 | 0 | pollfd[0].fd = fd; |
467 | 0 | pollfd[0].events = POLLIN; |
468 | |
|
469 | 0 | result = poll(pollfd, 1, MY_WAIT_POLL_TIMEOUT_MS); |
470 | 0 | if (result < 0) { |
471 | 0 | if (errno == EINTR) |
472 | 0 | continue; |
473 | 0 | goto cleanup; |
474 | 0 | } |
475 | | |
476 | 0 | if (result == 0) { |
477 | | /* a timeout */ |
478 | |
|
479 | 0 | int in_shutdown; |
480 | |
|
481 | 0 | pthread_mutex_lock(&server_data->work_available_mutex); |
482 | 0 | in_shutdown = server_data->shutdown_requested; |
483 | 0 | pthread_mutex_unlock(&server_data->work_available_mutex); |
484 | | |
485 | | /* |
486 | | * If a shutdown is already in progress and this |
487 | | * client has not started talking yet, just drop it. |
488 | | */ |
489 | 0 | if (in_shutdown) |
490 | 0 | goto cleanup; |
491 | 0 | continue; |
492 | 0 | } |
493 | | |
494 | 0 | if (pollfd[0].revents & POLLHUP) |
495 | 0 | goto cleanup; |
496 | | |
497 | 0 | if (pollfd[0].revents & POLLIN) |
498 | 0 | return 0; |
499 | | |
500 | 0 | goto cleanup; |
501 | 0 | } |
502 | | |
503 | 0 | cleanup: |
504 | 0 | close(fd); |
505 | 0 | return -1; |
506 | 0 | } |
507 | | |
508 | | /* |
509 | | * Receive the request/command from the client and pass it to the |
510 | | * registered request-callback. The request-callback will compose |
511 | | * a response and call our reply-callback to send it to the client. |
512 | | */ |
513 | | static int worker_thread__do_io( |
514 | | struct ipc_worker_thread_data *worker_thread_data, |
515 | | int fd) |
516 | 0 | { |
517 | | /* ASSERT NOT holding lock */ |
518 | |
|
519 | 0 | struct strbuf buf = STRBUF_INIT; |
520 | 0 | struct ipc_server_reply_data reply_data; |
521 | 0 | int ret = 0; |
522 | |
|
523 | 0 | reply_data.magic = MAGIC_SERVER_REPLY_DATA; |
524 | 0 | reply_data.worker_thread_data = worker_thread_data; |
525 | |
|
526 | 0 | reply_data.fd = fd; |
527 | |
|
528 | 0 | ret = read_packetized_to_strbuf( |
529 | 0 | reply_data.fd, &buf, |
530 | 0 | PACKET_READ_GENTLE_ON_EOF | PACKET_READ_GENTLE_ON_READ_ERROR); |
531 | 0 | if (ret >= 0) { |
532 | 0 | ret = worker_thread_data->server_data->application_cb( |
533 | 0 | worker_thread_data->server_data->application_data, |
534 | 0 | buf.buf, buf.len, do_io_reply_callback, &reply_data); |
535 | |
|
536 | 0 | packet_flush_gently(reply_data.fd); |
537 | 0 | } |
538 | 0 | else { |
539 | | /* |
540 | | * The client probably disconnected/shutdown before it |
541 | | * could send a well-formed message. Ignore it. |
542 | | */ |
543 | 0 | } |
544 | |
|
545 | 0 | strbuf_release(&buf); |
546 | 0 | close(reply_data.fd); |
547 | |
|
548 | 0 | return ret; |
549 | 0 | } |
550 | | |
551 | | /* |
552 | | * Block SIGPIPE on the current thread (so that we get EPIPE from |
553 | | * write() rather than an actual signal). |
554 | | * |
555 | | * Note that using sigchain_push() and _pop() to control SIGPIPE |
556 | | * around our IO calls is not thread safe: |
557 | | * [] It uses a global stack of handler frames. |
558 | | * [] It uses ALLOC_GROW() to resize it. |
559 | | * [] Finally, according to the `signal(2)` man-page: |
560 | | * "The effects of `signal()` in a multithreaded process are unspecified." |
561 | | */ |
562 | | static void thread_block_sigpipe(sigset_t *old_set) |
563 | 0 | { |
564 | 0 | sigset_t new_set; |
565 | |
|
566 | 0 | sigemptyset(&new_set); |
567 | 0 | sigaddset(&new_set, SIGPIPE); |
568 | |
|
569 | 0 | sigemptyset(old_set); |
570 | 0 | pthread_sigmask(SIG_BLOCK, &new_set, old_set); |
571 | 0 | } |
572 | | |
573 | | /* |
574 | | * Thread proc for an IPC worker thread. It handles a series of |
575 | | * connections from clients. It pulls the next fd from the queue |
576 | | * processes it, and then waits for the next client. |
577 | | * |
578 | | * Block SIGPIPE in this worker thread for the life of the thread. |
579 | | * This avoids stray (and sometimes delayed) SIGPIPE signals caused |
580 | | * by client errors and/or when we are under extremely heavy IO load. |
581 | | * |
582 | | * This means that the application callback will have SIGPIPE blocked. |
583 | | * The callback should not change it. |
584 | | */ |
585 | | static void *worker_thread_proc(void *_worker_thread_data) |
586 | 0 | { |
587 | 0 | struct ipc_worker_thread_data *worker_thread_data = _worker_thread_data; |
588 | 0 | struct ipc_server_data *server_data = worker_thread_data->server_data; |
589 | 0 | sigset_t old_set; |
590 | 0 | int fd, io; |
591 | 0 | int ret; |
592 | |
|
593 | 0 | trace2_thread_start("ipc-worker"); |
594 | |
|
595 | 0 | thread_block_sigpipe(&old_set); |
596 | |
|
597 | 0 | for (;;) { |
598 | 0 | fd = worker_thread__wait_for_connection(worker_thread_data); |
599 | 0 | if (fd == -1) |
600 | 0 | break; /* in shutdown */ |
601 | | |
602 | 0 | io = worker_thread__wait_for_io_start(worker_thread_data, fd); |
603 | 0 | if (io == -1) |
604 | 0 | continue; /* client hung up without sending anything */ |
605 | | |
606 | 0 | ret = worker_thread__do_io(worker_thread_data, fd); |
607 | |
|
608 | 0 | if (ret == SIMPLE_IPC_QUIT) { |
609 | 0 | trace2_data_string("ipc-worker", NULL, "queue_stop_async", |
610 | 0 | "application_quit"); |
611 | | /* |
612 | | * The application layer is telling the ipc-server |
613 | | * layer to shutdown. |
614 | | * |
615 | | * We DO NOT have a response to send to the client. |
616 | | * |
617 | | * Queue an async stop (to stop the other threads) and |
618 | | * allow this worker thread to exit now (no sense waiting |
619 | | * for the thread-pool shutdown signal). |
620 | | * |
621 | | * Other non-idle worker threads are allowed to finish |
622 | | * responding to their current clients. |
623 | | */ |
624 | 0 | ipc_server_stop_async(server_data); |
625 | 0 | break; |
626 | 0 | } |
627 | 0 | } |
628 | |
|
629 | 0 | trace2_thread_exit(); |
630 | 0 | return NULL; |
631 | 0 | } |
632 | | |
633 | | /* A randomly chosen value. */ |
634 | 0 | #define MY_ACCEPT_POLL_TIMEOUT_MS (60 * 1000) |
635 | | |
636 | | /* |
637 | | * Accept a new client connection on our socket. This uses non-blocking |
638 | | * IO so that we can also wait for shutdown requests on our socket-pair |
639 | | * without actually spinning on a fast timeout. |
640 | | */ |
641 | | static int accept_thread__wait_for_connection( |
642 | | struct ipc_accept_thread_data *accept_thread_data) |
643 | 0 | { |
644 | 0 | struct pollfd pollfd[2]; |
645 | 0 | int result; |
646 | |
|
647 | 0 | for (;;) { |
648 | 0 | pollfd[0].fd = accept_thread_data->fd_wait_shutdown; |
649 | 0 | pollfd[0].events = POLLIN; |
650 | |
|
651 | 0 | pollfd[1].fd = accept_thread_data->server_socket->fd_socket; |
652 | 0 | pollfd[1].events = POLLIN; |
653 | |
|
654 | 0 | result = poll(pollfd, 2, MY_ACCEPT_POLL_TIMEOUT_MS); |
655 | 0 | if (result < 0) { |
656 | 0 | if (errno == EINTR) |
657 | 0 | continue; |
658 | 0 | return result; |
659 | 0 | } |
660 | | |
661 | 0 | if (result == 0) { |
662 | | /* a timeout */ |
663 | | |
664 | | /* |
665 | | * If someone deletes or force-creates a new unix |
666 | | * domain socket at our path, all future clients |
667 | | * will be routed elsewhere and we silently starve. |
668 | | * If that happens, just queue a shutdown. |
669 | | */ |
670 | 0 | if (unix_ss_was_stolen( |
671 | 0 | accept_thread_data->server_socket)) { |
672 | 0 | trace2_data_string("ipc-accept", NULL, |
673 | 0 | "queue_stop_async", |
674 | 0 | "socket_stolen"); |
675 | 0 | ipc_server_stop_async( |
676 | 0 | accept_thread_data->server_data); |
677 | 0 | } |
678 | 0 | continue; |
679 | 0 | } |
680 | | |
681 | 0 | if (pollfd[0].revents & POLLIN) { |
682 | | /* shutdown message queued to socketpair */ |
683 | 0 | return -1; |
684 | 0 | } |
685 | | |
686 | 0 | if (pollfd[1].revents & POLLIN) { |
687 | | /* a connection is available on server_socket */ |
688 | |
|
689 | 0 | int client_fd = |
690 | 0 | accept(accept_thread_data->server_socket->fd_socket, |
691 | 0 | NULL, NULL); |
692 | 0 | if (client_fd >= 0) |
693 | 0 | return client_fd; |
694 | | |
695 | | /* |
696 | | * An error here is unlikely -- it probably |
697 | | * indicates that the connecting process has |
698 | | * already dropped the connection. |
699 | | */ |
700 | 0 | continue; |
701 | 0 | } |
702 | | |
703 | 0 | BUG("unandled poll result errno=%d r[0]=%d r[1]=%d", |
704 | 0 | errno, pollfd[0].revents, pollfd[1].revents); |
705 | 0 | } |
706 | 0 | } |
707 | | |
708 | | /* |
709 | | * Thread proc for the IPC server "accept thread". This waits for |
710 | | * an incoming socket connection, appends it to the queue of available |
711 | | * connections, and notifies a worker thread to process it. |
712 | | * |
713 | | * Block SIGPIPE in this thread for the life of the thread. This |
714 | | * avoids any stray SIGPIPE signals when closing pipe fds under |
715 | | * extremely heavy loads (such as when the fifo queue is full and we |
716 | | * drop incoming connections). |
717 | | */ |
718 | | static void *accept_thread_proc(void *_accept_thread_data) |
719 | 0 | { |
720 | 0 | struct ipc_accept_thread_data *accept_thread_data = _accept_thread_data; |
721 | 0 | struct ipc_server_data *server_data = accept_thread_data->server_data; |
722 | 0 | sigset_t old_set; |
723 | |
|
724 | 0 | trace2_thread_start("ipc-accept"); |
725 | |
|
726 | 0 | thread_block_sigpipe(&old_set); |
727 | |
|
728 | 0 | for (;;) { |
729 | 0 | int client_fd = accept_thread__wait_for_connection( |
730 | 0 | accept_thread_data); |
731 | |
|
732 | 0 | pthread_mutex_lock(&server_data->work_available_mutex); |
733 | 0 | if (server_data->shutdown_requested) { |
734 | 0 | pthread_mutex_unlock(&server_data->work_available_mutex); |
735 | 0 | if (client_fd >= 0) |
736 | 0 | close(client_fd); |
737 | 0 | break; |
738 | 0 | } |
739 | | |
740 | 0 | if (client_fd < 0) { |
741 | | /* ignore transient accept() errors */ |
742 | 0 | } |
743 | 0 | else { |
744 | 0 | fifo_enqueue(server_data, client_fd); |
745 | 0 | pthread_cond_broadcast(&server_data->work_available_cond); |
746 | 0 | } |
747 | 0 | pthread_mutex_unlock(&server_data->work_available_mutex); |
748 | 0 | } |
749 | |
|
750 | 0 | trace2_thread_exit(); |
751 | 0 | return NULL; |
752 | 0 | } |
753 | | |
754 | | /* |
755 | | * We can't predict the connection arrival rate relative to the worker |
756 | | * processing rate, therefore we allow the "accept-thread" to queue up |
757 | | * a generous number of connections, since we'd rather have the client |
758 | | * not unnecessarily timeout if we can avoid it. (The assumption is |
759 | | * that this will be used for FSMonitor and a few second wait on a |
760 | | * connection is better than having the client timeout and do the full |
761 | | * computation itself.) |
762 | | * |
763 | | * The FIFO queue size is set to a multiple of the worker pool size. |
764 | | * This value chosen at random. |
765 | | */ |
766 | 0 | #define FIFO_SCALE (100) |
767 | | |
768 | | /* |
769 | | * The backlog value for `listen(2)`. This doesn't need to huge, |
770 | | * rather just large enough for our "accept-thread" to wake up and |
771 | | * queue incoming connections onto the FIFO without the kernel |
772 | | * dropping any. |
773 | | * |
774 | | * This value chosen at random. |
775 | | */ |
776 | 0 | #define LISTEN_BACKLOG (50) |
777 | | |
778 | | static int create_listener_socket( |
779 | | const char *path, |
780 | | const struct ipc_server_opts *ipc_opts, |
781 | | struct unix_ss_socket **new_server_socket) |
782 | 0 | { |
783 | 0 | struct unix_ss_socket *server_socket = NULL; |
784 | 0 | struct unix_stream_listen_opts uslg_opts = UNIX_STREAM_LISTEN_OPTS_INIT; |
785 | 0 | int ret; |
786 | |
|
787 | 0 | uslg_opts.listen_backlog_size = LISTEN_BACKLOG; |
788 | 0 | uslg_opts.disallow_chdir = ipc_opts->uds_disallow_chdir; |
789 | |
|
790 | 0 | ret = unix_ss_create(path, &uslg_opts, -1, &server_socket); |
791 | 0 | if (ret) |
792 | 0 | return ret; |
793 | | |
794 | 0 | if (set_socket_blocking_flag(server_socket->fd_socket, 1)) { |
795 | 0 | int saved_errno = errno; |
796 | 0 | unix_ss_free(server_socket); |
797 | 0 | errno = saved_errno; |
798 | 0 | return -1; |
799 | 0 | } |
800 | | |
801 | 0 | *new_server_socket = server_socket; |
802 | |
|
803 | 0 | trace2_data_string("ipc-server", NULL, "listen-with-lock", path); |
804 | 0 | return 0; |
805 | 0 | } |
806 | | |
807 | | static int setup_listener_socket( |
808 | | const char *path, |
809 | | const struct ipc_server_opts *ipc_opts, |
810 | | struct unix_ss_socket **new_server_socket) |
811 | 0 | { |
812 | 0 | int ret, saved_errno; |
813 | |
|
814 | 0 | trace2_region_enter("ipc-server", "create-listener_socket", NULL); |
815 | |
|
816 | 0 | ret = create_listener_socket(path, ipc_opts, new_server_socket); |
817 | |
|
818 | 0 | saved_errno = errno; |
819 | 0 | trace2_region_leave("ipc-server", "create-listener_socket", NULL); |
820 | 0 | errno = saved_errno; |
821 | |
|
822 | 0 | return ret; |
823 | 0 | } |
824 | | |
825 | | /* |
826 | | * Start IPC server in a pool of background threads. |
827 | | */ |
828 | | int ipc_server_init_async(struct ipc_server_data **returned_server_data, |
829 | | const char *path, const struct ipc_server_opts *opts, |
830 | | ipc_server_application_cb *application_cb, |
831 | | void *application_data) |
832 | 0 | { |
833 | 0 | struct unix_ss_socket *server_socket = NULL; |
834 | 0 | struct ipc_server_data *server_data; |
835 | 0 | int sv[2]; |
836 | 0 | int k; |
837 | 0 | int ret; |
838 | 0 | int nr_threads = opts->nr_threads; |
839 | |
|
840 | 0 | *returned_server_data = NULL; |
841 | | |
842 | | /* |
843 | | * Create a socketpair and set sv[1] to non-blocking. This |
844 | | * will used to send a shutdown message to the accept-thread |
845 | | * and allows the accept-thread to wait on EITHER a client |
846 | | * connection or a shutdown request without spinning. |
847 | | */ |
848 | 0 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) |
849 | 0 | return -1; |
850 | | |
851 | 0 | if (set_socket_blocking_flag(sv[1], 1)) { |
852 | 0 | int saved_errno = errno; |
853 | 0 | close(sv[0]); |
854 | 0 | close(sv[1]); |
855 | 0 | errno = saved_errno; |
856 | 0 | return -1; |
857 | 0 | } |
858 | | |
859 | 0 | ret = setup_listener_socket(path, opts, &server_socket); |
860 | 0 | if (ret) { |
861 | 0 | int saved_errno = errno; |
862 | 0 | close(sv[0]); |
863 | 0 | close(sv[1]); |
864 | 0 | errno = saved_errno; |
865 | 0 | return ret; |
866 | 0 | } |
867 | | |
868 | 0 | server_data = xcalloc(1, sizeof(*server_data)); |
869 | 0 | server_data->magic = MAGIC_SERVER_DATA; |
870 | 0 | server_data->application_cb = application_cb; |
871 | 0 | server_data->application_data = application_data; |
872 | 0 | strbuf_init(&server_data->buf_path, 0); |
873 | 0 | strbuf_addstr(&server_data->buf_path, path); |
874 | |
|
875 | 0 | if (nr_threads < 1) |
876 | 0 | nr_threads = 1; |
877 | |
|
878 | 0 | pthread_mutex_init(&server_data->work_available_mutex, NULL); |
879 | 0 | pthread_cond_init(&server_data->work_available_cond, NULL); |
880 | |
|
881 | 0 | server_data->queue_size = nr_threads * FIFO_SCALE; |
882 | 0 | CALLOC_ARRAY(server_data->fifo_fds, server_data->queue_size); |
883 | |
|
884 | 0 | server_data->accept_thread = |
885 | 0 | xcalloc(1, sizeof(*server_data->accept_thread)); |
886 | 0 | server_data->accept_thread->magic = MAGIC_ACCEPT_THREAD_DATA; |
887 | 0 | server_data->accept_thread->server_data = server_data; |
888 | 0 | server_data->accept_thread->server_socket = server_socket; |
889 | 0 | server_data->accept_thread->fd_send_shutdown = sv[0]; |
890 | 0 | server_data->accept_thread->fd_wait_shutdown = sv[1]; |
891 | | |
892 | | /* |
893 | | * Hold work-available mutex so that no work can start until |
894 | | * we unlock it. |
895 | | */ |
896 | 0 | pthread_mutex_lock(&server_data->work_available_mutex); |
897 | |
|
898 | 0 | if (pthread_create(&server_data->accept_thread->pthread_id, NULL, |
899 | 0 | accept_thread_proc, server_data->accept_thread)) |
900 | 0 | die_errno(_("could not start accept_thread '%s'"), path); |
901 | | |
902 | 0 | for (k = 0; k < nr_threads; k++) { |
903 | 0 | struct ipc_worker_thread_data *wtd; |
904 | |
|
905 | 0 | wtd = xcalloc(1, sizeof(*wtd)); |
906 | 0 | wtd->magic = MAGIC_WORKER_THREAD_DATA; |
907 | 0 | wtd->server_data = server_data; |
908 | |
|
909 | 0 | if (pthread_create(&wtd->pthread_id, NULL, worker_thread_proc, |
910 | 0 | wtd)) { |
911 | 0 | if (k == 0) |
912 | 0 | die(_("could not start worker[0] for '%s'"), |
913 | 0 | path); |
914 | | /* |
915 | | * Limp along with the thread pool that we have. |
916 | | */ |
917 | 0 | break; |
918 | 0 | } |
919 | | |
920 | 0 | wtd->next_thread = server_data->worker_thread_list; |
921 | 0 | server_data->worker_thread_list = wtd; |
922 | 0 | } |
923 | | |
924 | 0 | *returned_server_data = server_data; |
925 | 0 | return 0; |
926 | 0 | } |
927 | | |
928 | | void ipc_server_start_async(struct ipc_server_data *server_data) |
929 | 0 | { |
930 | 0 | if (!server_data || server_data->started) |
931 | 0 | return; |
932 | | |
933 | 0 | server_data->started = 1; |
934 | 0 | pthread_mutex_unlock(&server_data->work_available_mutex); |
935 | 0 | } |
936 | | |
937 | | /* |
938 | | * Gently tell the IPC server treads to shutdown. |
939 | | * Can be run on any thread. |
940 | | */ |
941 | | int ipc_server_stop_async(struct ipc_server_data *server_data) |
942 | 0 | { |
943 | | /* ASSERT NOT holding mutex */ |
944 | |
|
945 | 0 | int fd; |
946 | |
|
947 | 0 | if (!server_data) |
948 | 0 | return 0; |
949 | | |
950 | 0 | trace2_region_enter("ipc-server", "server-stop-async", NULL); |
951 | | |
952 | | /* If we haven't started yet, we are already holding lock. */ |
953 | 0 | if (server_data->started) |
954 | 0 | pthread_mutex_lock(&server_data->work_available_mutex); |
955 | |
|
956 | 0 | server_data->shutdown_requested = 1; |
957 | | |
958 | | /* |
959 | | * Write a byte to the shutdown socket pair to wake up the |
960 | | * accept-thread. |
961 | | */ |
962 | 0 | if (write(server_data->accept_thread->fd_send_shutdown, "Q", 1) < 0) |
963 | 0 | error_errno("could not write to fd_send_shutdown"); |
964 | | |
965 | | /* |
966 | | * Drain the queue of existing connections. |
967 | | */ |
968 | 0 | while ((fd = fifo_dequeue(server_data)) != -1) |
969 | 0 | close(fd); |
970 | | |
971 | | /* |
972 | | * Gently tell worker threads to stop processing new connections |
973 | | * and exit. (This does not abort in-process conversations.) |
974 | | */ |
975 | 0 | pthread_cond_broadcast(&server_data->work_available_cond); |
976 | |
|
977 | 0 | pthread_mutex_unlock(&server_data->work_available_mutex); |
978 | |
|
979 | 0 | trace2_region_leave("ipc-server", "server-stop-async", NULL); |
980 | |
|
981 | 0 | return 0; |
982 | 0 | } |
983 | | |
984 | | /* |
985 | | * Wait for all IPC server threads to stop. |
986 | | */ |
987 | | int ipc_server_await(struct ipc_server_data *server_data) |
988 | 0 | { |
989 | 0 | pthread_join(server_data->accept_thread->pthread_id, NULL); |
990 | |
|
991 | 0 | if (!server_data->shutdown_requested) |
992 | 0 | BUG("ipc-server: accept-thread stopped for '%s'", |
993 | 0 | server_data->buf_path.buf); |
994 | | |
995 | 0 | while (server_data->worker_thread_list) { |
996 | 0 | struct ipc_worker_thread_data *wtd = |
997 | 0 | server_data->worker_thread_list; |
998 | |
|
999 | 0 | pthread_join(wtd->pthread_id, NULL); |
1000 | |
|
1001 | 0 | server_data->worker_thread_list = wtd->next_thread; |
1002 | 0 | free(wtd); |
1003 | 0 | } |
1004 | |
|
1005 | 0 | server_data->is_stopped = 1; |
1006 | |
|
1007 | 0 | return 0; |
1008 | 0 | } |
1009 | | |
1010 | | void ipc_server_free(struct ipc_server_data *server_data) |
1011 | 0 | { |
1012 | 0 | struct ipc_accept_thread_data * accept_thread_data; |
1013 | |
|
1014 | 0 | if (!server_data) |
1015 | 0 | return; |
1016 | | |
1017 | 0 | if (!server_data->is_stopped) |
1018 | 0 | BUG("cannot free ipc-server while running for '%s'", |
1019 | 0 | server_data->buf_path.buf); |
1020 | | |
1021 | 0 | accept_thread_data = server_data->accept_thread; |
1022 | 0 | if (accept_thread_data) { |
1023 | 0 | unix_ss_free(accept_thread_data->server_socket); |
1024 | |
|
1025 | 0 | if (accept_thread_data->fd_send_shutdown != -1) |
1026 | 0 | close(accept_thread_data->fd_send_shutdown); |
1027 | 0 | if (accept_thread_data->fd_wait_shutdown != -1) |
1028 | 0 | close(accept_thread_data->fd_wait_shutdown); |
1029 | |
|
1030 | 0 | free(server_data->accept_thread); |
1031 | 0 | } |
1032 | |
|
1033 | 0 | while (server_data->worker_thread_list) { |
1034 | 0 | struct ipc_worker_thread_data *wtd = |
1035 | 0 | server_data->worker_thread_list; |
1036 | |
|
1037 | 0 | server_data->worker_thread_list = wtd->next_thread; |
1038 | 0 | free(wtd); |
1039 | 0 | } |
1040 | |
|
1041 | 0 | pthread_cond_destroy(&server_data->work_available_cond); |
1042 | 0 | pthread_mutex_destroy(&server_data->work_available_mutex); |
1043 | |
|
1044 | 0 | strbuf_release(&server_data->buf_path); |
1045 | |
|
1046 | 0 | free(server_data->fifo_fds); |
1047 | 0 | free(server_data); |
1048 | 0 | } |