| 1 | #include "git-compat-util.h" |
| 2 | #include "abspath.h" |
| 3 | #include "gettext.h" |
| 4 | #include "simple-ipc.h" |
| 5 | #include "strbuf.h" |
| 6 | #include "pkt-line.h" |
| 7 | #include "thread-utils.h" |
| 8 | #include "trace.h" |
| 9 | #include "trace2.h" |
| 10 | #include "accctrl.h" |
| 11 | #include "aclapi.h" |
| 12 | |
| 13 | #ifndef SUPPORTS_SIMPLE_IPC |
| 14 | /* |
| 15 | * This source file should only be compiled when Simple IPC is supported. |
| 16 | * See the top-level Makefile. |
| 17 | */ |
| 18 | #error SUPPORTS_SIMPLE_IPC not defined |
| 19 | #endif |
| 20 | |
| 21 | static int initialize_pipe_name(const char *path, wchar_t *wpath, size_t alloc) |
| 22 | { |
| 23 | int off = 0; |
| 24 | struct strbuf realpath = STRBUF_INIT; |
| 25 | |
| 26 | if (!strbuf_realpath(&realpath, path, 0)) |
| 27 | return -1; |
| 28 | |
| 29 | off = swprintf(wpath, alloc, L"\\\\.\\pipe\\"); |
| 30 | if (xutftowcs(wpath + off, realpath.buf, alloc - off) < 0) |
| 31 | return -1; |
| 32 | |
| 33 | /* Handle drive prefix */ |
| 34 | if (wpath[off] && wpath[off + 1] == L':') { |
| 35 | wpath[off + 1] = L'_'; |
| 36 | off += 2; |
| 37 | } |
| 38 | |
| 39 | for (; wpath[off]; off++) |
| 40 | if (wpath[off] == L'/') |
| 41 | wpath[off] = L'\\'; |
| 42 | |
| 43 | strbuf_release(&realpath); |
| 44 | return 0; |
| 45 | } |
| 46 | |
| 47 | static enum ipc_active_state get_active_state(wchar_t *pipe_path) |
| 48 | { |
| 49 | if (WaitNamedPipeW(pipe_path, NMPWAIT_USE_DEFAULT_WAIT)) |
| 50 | return IPC_STATE__LISTENING; |
| 51 | |
| 52 | if (GetLastError() == ERROR_SEM_TIMEOUT) |
| 53 | return IPC_STATE__NOT_LISTENING; |
| 54 | |
| 55 | if (GetLastError() == ERROR_FILE_NOT_FOUND) |
| 56 | return IPC_STATE__PATH_NOT_FOUND; |
| 57 | |
| 58 | trace2_data_intmax("ipc-debug", NULL, "getstate/waitpipe/gle", |
| 59 | (intmax_t)GetLastError()); |
| 60 | |
| 61 | return IPC_STATE__OTHER_ERROR; |
| 62 | } |
| 63 | |
| 64 | enum ipc_active_state ipc_get_active_state(const char *path) |
| 65 | { |
| 66 | wchar_t pipe_path[MAX_PATH]; |
| 67 | |
| 68 | if (initialize_pipe_name(path, pipe_path, ARRAY_SIZE(pipe_path)) < 0) |
| 69 | return IPC_STATE__INVALID_PATH; |
| 70 | |
| 71 | return get_active_state(pipe_path); |
| 72 | } |
| 73 | |
| 74 | #define WAIT_STEP_MS (50) |
| 75 | |
| 76 | static enum ipc_active_state connect_to_server( |
| 77 | const wchar_t *wpath, |
| 78 | DWORD timeout_ms, |
| 79 | const struct ipc_client_connect_options *options, |
| 80 | int *pfd) |
| 81 | { |
| 82 | DWORD t_start_ms, t_waited_ms; |
| 83 | DWORD step_ms; |
| 84 | HANDLE hPipe = INVALID_HANDLE_VALUE; |
| 85 | DWORD mode = PIPE_READMODE_BYTE; |
| 86 | DWORD gle; |
| 87 | |
| 88 | *pfd = -1; |
| 89 | |
| 90 | for (;;) { |
| 91 | hPipe = CreateFileW(wpath, GENERIC_READ | GENERIC_WRITE, |
| 92 | 0, NULL, OPEN_EXISTING, 0, NULL); |
| 93 | if (hPipe != INVALID_HANDLE_VALUE) |
| 94 | break; |
| 95 | |
| 96 | gle = GetLastError(); |
| 97 | |
| 98 | switch (gle) { |
| 99 | case ERROR_FILE_NOT_FOUND: |
| 100 | if (!options->wait_if_not_found) |
| 101 | return IPC_STATE__PATH_NOT_FOUND; |
| 102 | if (!timeout_ms) |
| 103 | return IPC_STATE__PATH_NOT_FOUND; |
| 104 | |
| 105 | step_ms = (timeout_ms < WAIT_STEP_MS) ? |
| 106 | timeout_ms : WAIT_STEP_MS; |
| 107 | sleep_millisec(step_ms); |
| 108 | |
| 109 | timeout_ms -= step_ms; |
| 110 | break; /* try again */ |
| 111 | |
| 112 | case ERROR_PIPE_BUSY: |
| 113 | if (!options->wait_if_busy) |
| 114 | return IPC_STATE__NOT_LISTENING; |
| 115 | if (!timeout_ms) |
| 116 | return IPC_STATE__NOT_LISTENING; |
| 117 | |
| 118 | t_start_ms = (DWORD)(getnanotime() / 1000000); |
| 119 | |
| 120 | if (!WaitNamedPipeW(wpath, timeout_ms)) { |
| 121 | DWORD gleWait = GetLastError(); |
| 122 | |
| 123 | if (gleWait == ERROR_SEM_TIMEOUT) |
| 124 | return IPC_STATE__NOT_LISTENING; |
| 125 | |
| 126 | trace2_data_intmax("ipc-debug", NULL, |
| 127 | "connect/waitpipe/gle", |
| 128 | (intmax_t)gleWait); |
| 129 | |
| 130 | return IPC_STATE__OTHER_ERROR; |
| 131 | } |
| 132 | |
| 133 | /* |
| 134 | * A pipe server instance became available. |
| 135 | * Race other client processes to connect to |
| 136 | * it. |
| 137 | * |
| 138 | * But first decrement our overall timeout so |
| 139 | * that we don't starve if we keep losing the |
| 140 | * race. But also guard against special |
| 141 | * NPMWAIT_ values (0 and -1). |
| 142 | */ |
| 143 | t_waited_ms = (DWORD)(getnanotime() / 1000000) - t_start_ms; |
| 144 | if (t_waited_ms < timeout_ms) |
| 145 | timeout_ms -= t_waited_ms; |
| 146 | else |
| 147 | timeout_ms = 1; |
| 148 | break; /* try again */ |
| 149 | |
| 150 | default: |
| 151 | trace2_data_intmax("ipc-debug", NULL, |
| 152 | "connect/createfile/gle", |
| 153 | (intmax_t)gle); |
| 154 | |
| 155 | return IPC_STATE__OTHER_ERROR; |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | if (!SetNamedPipeHandleState(hPipe, &mode, NULL, NULL)) { |
| 160 | gle = GetLastError(); |
| 161 | trace2_data_intmax("ipc-debug", NULL, |
| 162 | "connect/setpipestate/gle", |
| 163 | (intmax_t)gle); |
| 164 | |
| 165 | CloseHandle(hPipe); |
| 166 | return IPC_STATE__OTHER_ERROR; |
| 167 | } |
| 168 | |
| 169 | *pfd = _open_osfhandle((intptr_t)hPipe, O_RDWR|O_BINARY); |
| 170 | if (*pfd < 0) { |
| 171 | gle = GetLastError(); |
| 172 | trace2_data_intmax("ipc-debug", NULL, |
| 173 | "connect/openosfhandle/gle", |
| 174 | (intmax_t)gle); |
| 175 | |
| 176 | CloseHandle(hPipe); |
| 177 | return IPC_STATE__OTHER_ERROR; |
| 178 | } |
| 179 | |
| 180 | /* fd now owns hPipe */ |
| 181 | |
| 182 | return IPC_STATE__LISTENING; |
| 183 | } |
| 184 | |
| 185 | /* |
| 186 | * The default connection timeout for Windows clients. |
| 187 | * |
| 188 | * This is not currently part of the ipc_ API (nor the config settings) |
| 189 | * because of differences between Windows and other platforms. |
| 190 | * |
| 191 | * This value was chosen at random. |
| 192 | */ |
| 193 | #define WINDOWS_CONNECTION_TIMEOUT_MS (30000) |
| 194 | |
| 195 | enum ipc_active_state ipc_client_try_connect( |
| 196 | const char *path, |
| 197 | const struct ipc_client_connect_options *options, |
| 198 | struct ipc_client_connection **p_connection) |
| 199 | { |
| 200 | wchar_t wpath[MAX_PATH]; |
| 201 | enum ipc_active_state state = IPC_STATE__OTHER_ERROR; |
| 202 | int fd = -1; |
| 203 | |
| 204 | *p_connection = NULL; |
| 205 | |
| 206 | trace2_region_enter("ipc-client", "try-connect", NULL); |
| 207 | trace2_data_string("ipc-client", NULL, "try-connect/path", path); |
| 208 | |
| 209 | if (initialize_pipe_name(path, wpath, ARRAY_SIZE(wpath)) < 0) |
| 210 | state = IPC_STATE__INVALID_PATH; |
| 211 | else |
| 212 | state = connect_to_server(wpath, WINDOWS_CONNECTION_TIMEOUT_MS, |
| 213 | options, &fd); |
| 214 | |
| 215 | trace2_data_intmax("ipc-client", NULL, "try-connect/state", |
| 216 | (intmax_t)state); |
| 217 | trace2_region_leave("ipc-client", "try-connect", NULL); |
| 218 | |
| 219 | if (state == IPC_STATE__LISTENING) { |
| 220 | (*p_connection) = xcalloc(1, sizeof(struct ipc_client_connection)); |
| 221 | (*p_connection)->fd = fd; |
| 222 | } |
| 223 | |
| 224 | return state; |
| 225 | } |
| 226 | |
| 227 | void ipc_client_close_connection(struct ipc_client_connection *connection) |
| 228 | { |
| 229 | if (!connection) |
| 230 | return; |
| 231 | |
| 232 | if (connection->fd != -1) |
| 233 | close(connection->fd); |
| 234 | |
| 235 | free(connection); |
| 236 | } |
| 237 | |
| 238 | int ipc_client_send_command_to_connection( |
| 239 | struct ipc_client_connection *connection, |
| 240 | const char *message, size_t message_len, |
| 241 | struct strbuf *answer) |
| 242 | { |
| 243 | int ret = 0; |
| 244 | |
| 245 | strbuf_setlen(answer, 0); |
| 246 | |
| 247 | trace2_region_enter("ipc-client", "send-command", NULL); |
| 248 | |
| 249 | if (write_packetized_from_buf_no_flush(message, message_len, |
| 250 | connection->fd) < 0 || |
| 251 | packet_flush_gently(connection->fd) < 0) { |
| 252 | ret = error(_("could not send IPC command")); |
| 253 | goto done; |
| 254 | } |
| 255 | |
| 256 | FlushFileBuffers((HANDLE)_get_osfhandle(connection->fd)); |
| 257 | |
| 258 | if (read_packetized_to_strbuf( |
| 259 | connection->fd, answer, |
| 260 | PACKET_READ_GENTLE_ON_EOF | PACKET_READ_GENTLE_ON_READ_ERROR) < 0) { |
| 261 | ret = error(_("could not read IPC response")); |
| 262 | goto done; |
| 263 | } |
| 264 | |
| 265 | done: |
| 266 | trace2_region_leave("ipc-client", "send-command", NULL); |
| 267 | return ret; |
| 268 | } |
| 269 | |
| 270 | int ipc_client_send_command(const char *path, |
| 271 | const struct ipc_client_connect_options *options, |
| 272 | const char *message, size_t message_len, |
| 273 | struct strbuf *response) |
| 274 | { |
| 275 | int ret = -1; |
| 276 | enum ipc_active_state state; |
| 277 | struct ipc_client_connection *connection = NULL; |
| 278 | |
| 279 | state = ipc_client_try_connect(path, options, &connection); |
| 280 | |
| 281 | if (state != IPC_STATE__LISTENING) |
| 282 | return ret; |
| 283 | |
| 284 | ret = ipc_client_send_command_to_connection(connection, |
| 285 | message, message_len, |
| 286 | response); |
| 287 | |
| 288 | ipc_client_close_connection(connection); |
| 289 | |
| 290 | return ret; |
| 291 | } |
| 292 | |
| 293 | /* |
| 294 | * Duplicate the given pipe handle and wrap it in a file descriptor so |
| 295 | * that we can use pkt-line on it. |
| 296 | */ |
| 297 | static int dup_fd_from_pipe(const HANDLE pipe) |
| 298 | { |
| 299 | HANDLE process = GetCurrentProcess(); |
| 300 | HANDLE handle; |
| 301 | int fd; |
| 302 | |
| 303 | if (!DuplicateHandle(process, pipe, process, &handle, 0, FALSE, |
| 304 | DUPLICATE_SAME_ACCESS)) { |
| 305 | errno = err_win_to_posix(GetLastError()); |
| 306 | return -1; |
| 307 | } |
| 308 | |
| 309 | fd = _open_osfhandle((intptr_t)handle, O_RDWR|O_BINARY); |
| 310 | if (fd < 0) { |
| 311 | errno = err_win_to_posix(GetLastError()); |
| 312 | CloseHandle(handle); |
| 313 | return -1; |
| 314 | } |
| 315 | |
| 316 | /* |
| 317 | * `handle` is now owned by `fd` and will be automatically closed |
| 318 | * when the descriptor is closed. |
| 319 | */ |
| 320 | |
| 321 | return fd; |
| 322 | } |
| 323 | |
| 324 | /* |
| 325 | * Magic numbers used to annotate callback instance data. |
| 326 | * These are used to help guard against accidentally passing the |
| 327 | * wrong instance data across multiple levels of callbacks (which |
| 328 | * is easy to do if there are `void*` arguments). |
| 329 | */ |
| 330 | enum magic { |
| 331 | MAGIC_SERVER_REPLY_DATA, |
| 332 | MAGIC_SERVER_THREAD_DATA, |
| 333 | MAGIC_SERVER_DATA, |
| 334 | }; |
| 335 | |
| 336 | struct ipc_server_reply_data { |
| 337 | enum magic magic; |
| 338 | int fd; |
| 339 | struct ipc_server_thread_data *server_thread_data; |
| 340 | }; |
| 341 | |
| 342 | struct ipc_server_thread_data { |
| 343 | enum magic magic; |
| 344 | struct ipc_server_thread_data *next_thread; |
| 345 | struct ipc_server_data *server_data; |
| 346 | pthread_t pthread_id; |
| 347 | HANDLE hPipe; |
| 348 | }; |
| 349 | |
| 350 | /* |
| 351 | * On Windows, the conceptual "ipc-server" is implemented as a pool of |
| 352 | * n idential/peer "server-thread" threads. That is, there is no |
| 353 | * hierarchy of threads; and therefore no controller thread managing |
| 354 | * the pool. Each thread has an independent handle to the named pipe, |
| 355 | * receives incoming connections, processes the client, and re-uses |
| 356 | * the pipe for the next client connection. |
| 357 | * |
| 358 | * Therefore, the "ipc-server" only needs to maintain a list of the |
| 359 | * spawned threads for eventual "join" purposes. |
| 360 | * |
| 361 | * A single "stop-event" is visible to all of the server threads to |
| 362 | * tell them to shutdown (when idle). |
| 363 | */ |
| 364 | struct ipc_server_data { |
| 365 | enum magic magic; |
| 366 | ipc_server_application_cb *application_cb; |
| 367 | void *application_data; |
| 368 | struct strbuf buf_path; |
| 369 | wchar_t wpath[MAX_PATH]; |
| 370 | |
| 371 | HANDLE hEventStopRequested; |
| 372 | struct ipc_server_thread_data *thread_list; |
| 373 | int is_stopped; |
| 374 | |
| 375 | pthread_mutex_t startup_barrier; |
| 376 | int started; |
| 377 | }; |
| 378 | |
| 379 | enum connect_result { |
| 380 | CR_CONNECTED = 0, |
| 381 | CR_CONNECT_PENDING, |
| 382 | CR_CONNECT_ERROR, |
| 383 | CR_WAIT_ERROR, |
| 384 | CR_SHUTDOWN, |
| 385 | }; |
| 386 | |
| 387 | static enum connect_result queue_overlapped_connect( |
| 388 | struct ipc_server_thread_data *server_thread_data, |
| 389 | OVERLAPPED *lpo) |
| 390 | { |
| 391 | if (ConnectNamedPipe(server_thread_data->hPipe, lpo)) |
| 392 | goto failed; |
| 393 | |
| 394 | switch (GetLastError()) { |
| 395 | case ERROR_IO_PENDING: |
| 396 | return CR_CONNECT_PENDING; |
| 397 | |
| 398 | case ERROR_PIPE_CONNECTED: |
| 399 | SetEvent(lpo->hEvent); |
| 400 | return CR_CONNECTED; |
| 401 | |
| 402 | default: |
| 403 | break; |
| 404 | } |
| 405 | |
| 406 | failed: |
| 407 | error(_("ConnectNamedPipe failed for '%s' (%lu)"), |
| 408 | server_thread_data->server_data->buf_path.buf, |
| 409 | GetLastError()); |
| 410 | return CR_CONNECT_ERROR; |
| 411 | } |
| 412 | |
| 413 | /* |
| 414 | * Use Windows Overlapped IO to wait for a connection or for our event |
| 415 | * to be signalled. |
| 416 | */ |
| 417 | static enum connect_result wait_for_connection( |
| 418 | struct ipc_server_thread_data *server_thread_data, |
| 419 | OVERLAPPED *lpo) |
| 420 | { |
| 421 | enum connect_result r; |
| 422 | HANDLE waitHandles[2]; |
| 423 | DWORD dwWaitResult; |
| 424 | |
| 425 | r = queue_overlapped_connect(server_thread_data, lpo); |
| 426 | if (r != CR_CONNECT_PENDING) |
| 427 | return r; |
| 428 | |
| 429 | waitHandles[0] = server_thread_data->server_data->hEventStopRequested; |
| 430 | waitHandles[1] = lpo->hEvent; |
| 431 | |
| 432 | dwWaitResult = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE); |
| 433 | switch (dwWaitResult) { |
| 434 | case WAIT_OBJECT_0 + 0: |
| 435 | return CR_SHUTDOWN; |
| 436 | |
| 437 | case WAIT_OBJECT_0 + 1: |
| 438 | ResetEvent(lpo->hEvent); |
| 439 | return CR_CONNECTED; |
| 440 | |
| 441 | default: |
| 442 | return CR_WAIT_ERROR; |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | /* |
| 447 | * Forward declare our reply callback function so that any compiler |
| 448 | * errors are reported when we actually define the function (in addition |
| 449 | * to any errors reported when we try to pass this callback function as |
| 450 | * a parameter in a function call). The former are easier to understand. |
| 451 | */ |
| 452 | static ipc_server_reply_cb do_io_reply_callback; |
| 453 | |
| 454 | /* |
| 455 | * Relay application's response message to the client process. |
| 456 | * (We do not flush at this point because we allow the caller |
| 457 | * to chunk data to the client thru us.) |
| 458 | */ |
| 459 | static int do_io_reply_callback(struct ipc_server_reply_data *reply_data, |
| 460 | const char *response, size_t response_len) |
| 461 | { |
| 462 | if (reply_data->magic != MAGIC_SERVER_REPLY_DATA) |
| 463 | BUG("reply_cb called with wrong instance data"); |
| 464 | |
| 465 | return write_packetized_from_buf_no_flush(response, response_len, |
| 466 | reply_data->fd); |
| 467 | } |
| 468 | |
| 469 | /* |
| 470 | * Receive the request/command from the client and pass it to the |
| 471 | * registered request-callback. The request-callback will compose |
| 472 | * a response and call our reply-callback to send it to the client. |
| 473 | * |
| 474 | * Simple-IPC only contains one round trip, so we flush and close |
| 475 | * here after the response. |
| 476 | */ |
| 477 | static int do_io(struct ipc_server_thread_data *server_thread_data) |
| 478 | { |
| 479 | struct strbuf buf = STRBUF_INIT; |
| 480 | struct ipc_server_reply_data reply_data; |
| 481 | int ret = 0; |
| 482 | |
| 483 | reply_data.magic = MAGIC_SERVER_REPLY_DATA; |
| 484 | reply_data.server_thread_data = server_thread_data; |
| 485 | |
| 486 | reply_data.fd = dup_fd_from_pipe(server_thread_data->hPipe); |
| 487 | if (reply_data.fd < 0) |
| 488 | return error(_("could not create fd from pipe for '%s'"), |
| 489 | server_thread_data->server_data->buf_path.buf); |
| 490 | |
| 491 | ret = read_packetized_to_strbuf( |
| 492 | reply_data.fd, &buf, |
| 493 | PACKET_READ_GENTLE_ON_EOF | PACKET_READ_GENTLE_ON_READ_ERROR); |
| 494 | if (ret >= 0) { |
| 495 | ret = server_thread_data->server_data->application_cb( |
| 496 | server_thread_data->server_data->application_data, |
| 497 | buf.buf, buf.len, do_io_reply_callback, &reply_data); |
| 498 | |
| 499 | packet_flush_gently(reply_data.fd); |
| 500 | |
| 501 | FlushFileBuffers((HANDLE)_get_osfhandle((reply_data.fd))); |
| 502 | } |
| 503 | else { |
| 504 | /* |
| 505 | * The client probably disconnected/shutdown before it |
| 506 | * could send a well-formed message. Ignore it. |
| 507 | */ |
| 508 | } |
| 509 | |
| 510 | strbuf_release(&buf); |
| 511 | close(reply_data.fd); |
| 512 | |
| 513 | return ret; |
| 514 | } |
| 515 | |
| 516 | /* |
| 517 | * Handle IPC request and response with this connected client. And reset |
| 518 | * the pipe to prepare for the next client. |
| 519 | */ |
| 520 | static int use_connection(struct ipc_server_thread_data *server_thread_data) |
| 521 | { |
| 522 | int ret; |
| 523 | |
| 524 | ret = do_io(server_thread_data); |
| 525 | |
| 526 | FlushFileBuffers(server_thread_data->hPipe); |
| 527 | DisconnectNamedPipe(server_thread_data->hPipe); |
| 528 | |
| 529 | return ret; |
| 530 | } |
| 531 | |
| 532 | static void wait_for_startup_barrier(struct ipc_server_data *server_data) |
| 533 | { |
| 534 | /* |
| 535 | * Temporarily hold the startup_barrier mutex before starting, |
| 536 | * which lets us know that it's OK to start serving requests. |
| 537 | */ |
| 538 | pthread_mutex_lock(&server_data->startup_barrier); |
| 539 | pthread_mutex_unlock(&server_data->startup_barrier); |
| 540 | } |
| 541 | |
| 542 | /* |
| 543 | * Thread proc for an IPC server worker thread. It handles a series of |
| 544 | * connections from clients. It cleans and reuses the hPipe between each |
| 545 | * client. |
| 546 | */ |
| 547 | static void *server_thread_proc(void *_server_thread_data) |
| 548 | { |
| 549 | struct ipc_server_thread_data *server_thread_data = _server_thread_data; |
| 550 | HANDLE hEventConnected = INVALID_HANDLE_VALUE; |
| 551 | OVERLAPPED oConnect; |
| 552 | enum connect_result cr; |
| 553 | int ret; |
| 554 | |
| 555 | assert(server_thread_data->hPipe != INVALID_HANDLE_VALUE); |
| 556 | |
| 557 | trace2_thread_start("ipc-server"); |
| 558 | trace2_data_string("ipc-server", NULL, "pipe", |
| 559 | server_thread_data->server_data->buf_path.buf); |
| 560 | |
| 561 | hEventConnected = CreateEventW(NULL, TRUE, FALSE, NULL); |
| 562 | |
| 563 | memset(&oConnect, 0, sizeof(oConnect)); |
| 564 | oConnect.hEvent = hEventConnected; |
| 565 | |
| 566 | wait_for_startup_barrier(server_thread_data->server_data); |
| 567 | |
| 568 | for (;;) { |
| 569 | cr = wait_for_connection(server_thread_data, &oConnect); |
| 570 | |
| 571 | switch (cr) { |
| 572 | case CR_SHUTDOWN: |
| 573 | goto finished; |
| 574 | |
| 575 | case CR_CONNECTED: |
| 576 | ret = use_connection(server_thread_data); |
| 577 | if (ret == SIMPLE_IPC_QUIT) { |
| 578 | ipc_server_stop_async( |
| 579 | server_thread_data->server_data); |
| 580 | goto finished; |
| 581 | } |
| 582 | if (ret > 0) { |
| 583 | /* |
| 584 | * Ignore (transient) IO errors with this |
| 585 | * client and reset for the next client. |
| 586 | */ |
| 587 | } |
| 588 | break; |
| 589 | |
| 590 | case CR_CONNECT_PENDING: |
| 591 | /* By construction, this should not happen. */ |
| 592 | BUG("ipc-server[%s]: unexpeced CR_CONNECT_PENDING", |
| 593 | server_thread_data->server_data->buf_path.buf); |
| 594 | |
| 595 | case CR_CONNECT_ERROR: |
| 596 | case CR_WAIT_ERROR: |
| 597 | /* |
| 598 | * Ignore these theoretical errors. |
| 599 | */ |
| 600 | DisconnectNamedPipe(server_thread_data->hPipe); |
| 601 | break; |
| 602 | |
| 603 | default: |
| 604 | BUG("unandled case after wait_for_connection"); |
| 605 | } |
| 606 | } |
| 607 | |
| 608 | finished: |
| 609 | CloseHandle(server_thread_data->hPipe); |
| 610 | CloseHandle(hEventConnected); |
| 611 | |
| 612 | trace2_thread_exit(); |
| 613 | return NULL; |
| 614 | } |
| 615 | |
| 616 | /* |
| 617 | * We need to build a Windows "SECURITY_ATTRIBUTES" object and use it |
| 618 | * to apply an ACL when we create the initial instance of the Named |
| 619 | * Pipe. The construction is somewhat involved and consists of |
| 620 | * several sequential steps and intermediate objects. |
| 621 | * |
| 622 | * We use this structure to hold these intermediate pointers so that |
| 623 | * we can free them as a group. (It is unclear from the docs whether |
| 624 | * some of these intermediate pointers can be freed before we are |
| 625 | * finished using the "lpSA" member.) |
| 626 | */ |
| 627 | struct my_sa_data |
| 628 | { |
| 629 | PSID pEveryoneSID; |
| 630 | PACL pACL; |
| 631 | PSECURITY_DESCRIPTOR pSD; |
| 632 | LPSECURITY_ATTRIBUTES lpSA; |
| 633 | }; |
| 634 | |
| 635 | static void init_sa(struct my_sa_data *d) |
| 636 | { |
| 637 | memset(d, 0, sizeof(*d)); |
| 638 | } |
| 639 | |
| 640 | static void release_sa(struct my_sa_data *d) |
| 641 | { |
| 642 | if (d->pEveryoneSID) |
| 643 | FreeSid(d->pEveryoneSID); |
| 644 | if (d->pACL) |
| 645 | LocalFree(d->pACL); |
| 646 | if (d->pSD) |
| 647 | LocalFree(d->pSD); |
| 648 | if (d->lpSA) |
| 649 | LocalFree(d->lpSA); |
| 650 | |
| 651 | memset(d, 0, sizeof(*d)); |
| 652 | } |
| 653 | |
| 654 | /* |
| 655 | * Create SECURITY_ATTRIBUTES to apply to the initial named pipe. The |
| 656 | * creator of the first server instance gets to set the ACLs on it. |
| 657 | * |
| 658 | * We allow the well-known group `EVERYONE` to have read+write access |
| 659 | * to the named pipe so that clients can send queries to the daemon |
| 660 | * and receive the response. |
| 661 | * |
| 662 | * Normally, this is not necessary since the daemon is usually |
| 663 | * automatically started by a foreground command like `git status`, |
| 664 | * but in those cases where an elevated Git command started the daemon |
| 665 | * (such that the daemon itself runs with elevation), we need to add |
| 666 | * the ACL so that non-elevated commands can write to it. |
| 667 | * |
| 668 | * The following document was helpful: |
| 669 | * https://docs.microsoft.com/en-us/windows/win32/secauthz/creating-a-security-descriptor-for-a-new-object-in-c-- |
| 670 | * |
| 671 | * Returns d->lpSA set to a SA or NULL. |
| 672 | */ |
| 673 | static LPSECURITY_ATTRIBUTES get_sa(struct my_sa_data *d) |
| 674 | { |
| 675 | SID_IDENTIFIER_AUTHORITY sid_auth_world = SECURITY_WORLD_SID_AUTHORITY; |
| 676 | #define NR_EA (1) |
| 677 | EXPLICIT_ACCESS ea[NR_EA]; |
| 678 | DWORD dwResult; |
| 679 | |
| 680 | if (!AllocateAndInitializeSid(&sid_auth_world, 1, |
| 681 | SECURITY_WORLD_RID, 0,0,0,0,0,0,0, |
| 682 | &d->pEveryoneSID)) { |
| 683 | DWORD gle = GetLastError(); |
| 684 | trace2_data_intmax("ipc-debug", NULL, "alloc-world-sid/gle", |
| 685 | (intmax_t)gle); |
| 686 | goto fail; |
| 687 | } |
| 688 | |
| 689 | MEMZERO_ARRAY(ea, NR_EA); |
| 690 | |
| 691 | ea[0].grfAccessPermissions = GENERIC_READ | GENERIC_WRITE; |
| 692 | ea[0].grfAccessMode = SET_ACCESS; |
| 693 | ea[0].grfInheritance = NO_INHERITANCE; |
| 694 | ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; |
| 695 | ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; |
| 696 | ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; |
| 697 | ea[0].Trustee.ptstrName = (LPTSTR)d->pEveryoneSID; |
| 698 | |
| 699 | dwResult = SetEntriesInAcl(NR_EA, ea, NULL, &d->pACL); |
| 700 | if (dwResult != ERROR_SUCCESS) { |
| 701 | DWORD gle = GetLastError(); |
| 702 | trace2_data_intmax("ipc-debug", NULL, "set-acl-entry/gle", |
| 703 | (intmax_t)gle); |
| 704 | trace2_data_intmax("ipc-debug", NULL, "set-acl-entry/dw", |
| 705 | (intmax_t)dwResult); |
| 706 | goto fail; |
| 707 | } |
| 708 | |
| 709 | d->pSD = (PSECURITY_DESCRIPTOR)LocalAlloc( |
| 710 | LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); |
| 711 | if (!InitializeSecurityDescriptor(d->pSD, SECURITY_DESCRIPTOR_REVISION)) { |
| 712 | DWORD gle = GetLastError(); |
| 713 | trace2_data_intmax("ipc-debug", NULL, "init-sd/gle", (intmax_t)gle); |
| 714 | goto fail; |
| 715 | } |
| 716 | |
| 717 | if (!SetSecurityDescriptorDacl(d->pSD, TRUE, d->pACL, FALSE)) { |
| 718 | DWORD gle = GetLastError(); |
| 719 | trace2_data_intmax("ipc-debug", NULL, "set-sd-dacl/gle", (intmax_t)gle); |
| 720 | goto fail; |
| 721 | } |
| 722 | |
| 723 | d->lpSA = (LPSECURITY_ATTRIBUTES)LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES)); |
| 724 | d->lpSA->nLength = sizeof(SECURITY_ATTRIBUTES); |
| 725 | d->lpSA->lpSecurityDescriptor = d->pSD; |
| 726 | d->lpSA->bInheritHandle = FALSE; |
| 727 | |
| 728 | return d->lpSA; |
| 729 | |
| 730 | fail: |
| 731 | release_sa(d); |
| 732 | return NULL; |
| 733 | } |
| 734 | |
| 735 | static HANDLE create_new_pipe(wchar_t *wpath, int is_first) |
| 736 | { |
| 737 | HANDLE hPipe; |
| 738 | DWORD dwOpenMode, dwPipeMode; |
| 739 | struct my_sa_data my_sa_data; |
| 740 | |
| 741 | init_sa(&my_sa_data); |
| 742 | |
| 743 | dwOpenMode = PIPE_ACCESS_INBOUND | PIPE_ACCESS_OUTBOUND | |
| 744 | FILE_FLAG_OVERLAPPED; |
| 745 | |
| 746 | dwPipeMode = PIPE_TYPE_MESSAGE | PIPE_READMODE_BYTE | PIPE_WAIT | |
| 747 | PIPE_REJECT_REMOTE_CLIENTS; |
| 748 | |
| 749 | if (is_first) { |
| 750 | dwOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; |
| 751 | |
| 752 | /* |
| 753 | * On Windows, the first server pipe instance gets to |
| 754 | * set the ACL / Security Attributes on the named |
| 755 | * pipe; subsequent instances inherit and cannot |
| 756 | * change them. |
| 757 | */ |
| 758 | get_sa(&my_sa_data); |
| 759 | } |
| 760 | |
| 761 | hPipe = CreateNamedPipeW(wpath, dwOpenMode, dwPipeMode, |
| 762 | PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, |
| 763 | my_sa_data.lpSA); |
| 764 | |
| 765 | release_sa(&my_sa_data); |
| 766 | |
| 767 | return hPipe; |
| 768 | } |
| 769 | |
| 770 | int ipc_server_init_async(struct ipc_server_data **returned_server_data, |
| 771 | const char *path, const struct ipc_server_opts *opts, |
| 772 | ipc_server_application_cb *application_cb, |
| 773 | void *application_data) |
| 774 | { |
| 775 | struct ipc_server_data *server_data; |
| 776 | wchar_t wpath[MAX_PATH]; |
| 777 | HANDLE hPipeFirst = INVALID_HANDLE_VALUE; |
| 778 | int k; |
| 779 | int ret = 0; |
| 780 | int nr_threads = opts->nr_threads; |
| 781 | |
| 782 | *returned_server_data = NULL; |
| 783 | |
| 784 | ret = initialize_pipe_name(path, wpath, ARRAY_SIZE(wpath)); |
| 785 | if (ret < 0) { |
| 786 | errno = EINVAL; |
| 787 | return -1; |
| 788 | } |
| 789 | |
| 790 | hPipeFirst = create_new_pipe(wpath, 1); |
| 791 | if (hPipeFirst == INVALID_HANDLE_VALUE) { |
| 792 | errno = EADDRINUSE; |
| 793 | return -2; |
| 794 | } |
| 795 | |
| 796 | server_data = xcalloc(1, sizeof(*server_data)); |
| 797 | server_data->magic = MAGIC_SERVER_DATA; |
| 798 | server_data->application_cb = application_cb; |
| 799 | server_data->application_data = application_data; |
| 800 | server_data->hEventStopRequested = CreateEvent(NULL, TRUE, FALSE, NULL); |
| 801 | strbuf_init(&server_data->buf_path, 0); |
| 802 | strbuf_addstr(&server_data->buf_path, path); |
| 803 | wcscpy(server_data->wpath, wpath); |
| 804 | |
| 805 | /* |
| 806 | * Hold the startup_barrier lock so that no threads will progress |
| 807 | * until ipc_server_start_async() is called. |
| 808 | */ |
| 809 | pthread_mutex_init(&server_data->startup_barrier, NULL); |
| 810 | pthread_mutex_lock(&server_data->startup_barrier); |
| 811 | |
| 812 | if (nr_threads < 1) |
| 813 | nr_threads = 1; |
| 814 | |
| 815 | for (k = 0; k < nr_threads; k++) { |
| 816 | struct ipc_server_thread_data *std; |
| 817 | |
| 818 | std = xcalloc(1, sizeof(*std)); |
| 819 | std->magic = MAGIC_SERVER_THREAD_DATA; |
| 820 | std->server_data = server_data; |
| 821 | std->hPipe = INVALID_HANDLE_VALUE; |
| 822 | |
| 823 | std->hPipe = (k == 0) |
| 824 | ? hPipeFirst |
| 825 | : create_new_pipe(server_data->wpath, 0); |
| 826 | |
| 827 | if (std->hPipe == INVALID_HANDLE_VALUE) { |
| 828 | /* |
| 829 | * If we've reached a pipe instance limit for |
| 830 | * this path, just use fewer threads. |
| 831 | */ |
| 832 | free(std); |
| 833 | break; |
| 834 | } |
| 835 | |
| 836 | if (pthread_create(&std->pthread_id, NULL, |
| 837 | server_thread_proc, std)) { |
| 838 | /* |
| 839 | * Likewise, if we're out of threads, just use |
| 840 | * fewer threads than requested. |
| 841 | * |
| 842 | * However, we just give up if we can't even get |
| 843 | * one thread. This should not happen. |
| 844 | */ |
| 845 | if (k == 0) |
| 846 | die(_("could not start thread[0] for '%s'"), |
| 847 | path); |
| 848 | |
| 849 | CloseHandle(std->hPipe); |
| 850 | free(std); |
| 851 | break; |
| 852 | } |
| 853 | |
| 854 | std->next_thread = server_data->thread_list; |
| 855 | server_data->thread_list = std; |
| 856 | } |
| 857 | |
| 858 | *returned_server_data = server_data; |
| 859 | return 0; |
| 860 | } |
| 861 | |
| 862 | void ipc_server_start_async(struct ipc_server_data *server_data) |
| 863 | { |
| 864 | if (!server_data || server_data->started) |
| 865 | return; |
| 866 | |
| 867 | server_data->started = 1; |
| 868 | pthread_mutex_unlock(&server_data->startup_barrier); |
| 869 | } |
| 870 | |
| 871 | int ipc_server_stop_async(struct ipc_server_data *server_data) |
| 872 | { |
| 873 | if (!server_data) |
| 874 | return 0; |
| 875 | |
| 876 | /* |
| 877 | * Gently tell all of the ipc_server threads to shutdown. |
| 878 | * This will be seen the next time they are idle (and waiting |
| 879 | * for a connection). |
| 880 | * |
| 881 | * We DO NOT attempt to force them to drop an active connection. |
| 882 | */ |
| 883 | SetEvent(server_data->hEventStopRequested); |
| 884 | |
| 885 | /* |
| 886 | * If we haven't yet told the threads they are allowed to run, |
| 887 | * do so now, so they can receive the shutdown event. |
| 888 | */ |
| 889 | ipc_server_start_async(server_data); |
| 890 | |
| 891 | return 0; |
| 892 | } |
| 893 | |
| 894 | int ipc_server_await(struct ipc_server_data *server_data) |
| 895 | { |
| 896 | DWORD dwWaitResult; |
| 897 | |
| 898 | if (!server_data) |
| 899 | return 0; |
| 900 | |
| 901 | dwWaitResult = WaitForSingleObject(server_data->hEventStopRequested, INFINITE); |
| 902 | if (dwWaitResult != WAIT_OBJECT_0) |
| 903 | return error(_("wait for hEvent failed for '%s'"), |
| 904 | server_data->buf_path.buf); |
| 905 | |
| 906 | while (server_data->thread_list) { |
| 907 | struct ipc_server_thread_data *std = server_data->thread_list; |
| 908 | |
| 909 | pthread_join(std->pthread_id, NULL); |
| 910 | |
| 911 | server_data->thread_list = std->next_thread; |
| 912 | free(std); |
| 913 | } |
| 914 | |
| 915 | server_data->is_stopped = 1; |
| 916 | |
| 917 | return 0; |
| 918 | } |
| 919 | |
| 920 | void ipc_server_free(struct ipc_server_data *server_data) |
| 921 | { |
| 922 | if (!server_data) |
| 923 | return; |
| 924 | |
| 925 | if (!server_data->is_stopped) |
| 926 | BUG("cannot free ipc-server while running for '%s'", |
| 927 | server_data->buf_path.buf); |
| 928 | |
| 929 | strbuf_release(&server_data->buf_path); |
| 930 | |
| 931 | if (server_data->hEventStopRequested != INVALID_HANDLE_VALUE) |
| 932 | CloseHandle(server_data->hEventStopRequested); |
| 933 | |
| 934 | while (server_data->thread_list) { |
| 935 | struct ipc_server_thread_data *std = server_data->thread_list; |
| 936 | |
| 937 | server_data->thread_list = std->next_thread; |
| 938 | free(std); |
| 939 | } |
| 940 | |
| 941 | pthread_mutex_destroy(&server_data->startup_barrier); |
| 942 | |
| 943 | free(server_data); |
| 944 | } |