| 1678 | } |
| 1679 | |
| 1680 | static void *runtime_connection_worker(void *opaque) { |
| 1681 | cbm_daemon_runtime_worker_t *worker = opaque; |
| 1682 | cbm_daemon_runtime_service_t *service = worker->service; |
| 1683 | cbm_daemon_frame_t frame = {0}; |
| 1684 | uint8_t *payload = NULL; |
| 1685 | char requested_version[CBM_DAEMON_VERSION_TEXT_SIZE]; |
| 1686 | char requested_build[CBM_DAEMON_BUILD_FINGERPRINT_SIZE]; |
| 1687 | |
| 1688 | int received = cbm_daemon_ipc_receive_frame_bounded( |
| 1689 | worker->connection, service->request_timeout_ms, |
| 1690 | CBM_DAEMON_ACTIVATION_SHUTDOWN_REQUEST_SIZE, &frame, &payload); |
| 1691 | if (received != 1 || frame.type != CBM_DAEMON_FRAME_REQUEST) { |
| 1692 | free(payload); |
| 1693 | runtime_worker_finish(worker); |
| 1694 | return NULL; |
| 1695 | } |
| 1696 | if (frame.flags == CBM_DAEMON_RUNTIME_OP_ACTIVATION_SHUTDOWN) { |
| 1697 | runtime_worker_handle_activation_shutdown(worker, payload, frame.length); |
| 1698 | free(payload); |
| 1699 | return NULL; |
| 1700 | } |
| 1701 | if (frame.flags == CBM_DAEMON_RUNTIME_OP_STATUS) { |
| 1702 | runtime_worker_handle_status(worker, payload, frame.length); |
| 1703 | free(payload); |
| 1704 | return NULL; |
| 1705 | } |
| 1706 | if (frame.flags == CBM_DAEMON_RUNTIME_OP_STOP) { |
| 1707 | runtime_worker_handle_stop(worker, payload, frame.length); |
| 1708 | free(payload); |
| 1709 | return NULL; |
| 1710 | } |
| 1711 | if (frame.flags != CBM_DAEMON_RUNTIME_OP_HELLO || |
| 1712 | frame.length != CBM_DAEMON_RENDEZVOUS_REQUEST_SIZE || |
| 1713 | !runtime_rendezvous_request_decode(payload, requested_version, requested_build)) { |
| 1714 | free(payload); |
| 1715 | runtime_worker_finish(worker); |
| 1716 | return NULL; |
| 1717 | } |
| 1718 | free(payload); |
| 1719 | payload = NULL; |
| 1720 | |
| 1721 | cbm_daemon_runtime_connect_result_t hello_result; |
| 1722 | memset(&hello_result, 0, sizeof(hello_result)); |
| 1723 | cbm_daemon_hello_status_t hello_status = runtime_rendezvous_compare( |
| 1724 | service->identity.semantic_version, service->identity.build_fingerprint, requested_version, |
| 1725 | requested_build, &hello_result.conflict); |
| 1726 | if (hello_status != CBM_DAEMON_HELLO_COMPATIBLE) { |
| 1727 | if (hello_status == CBM_DAEMON_HELLO_INVALID) { |
| 1728 | runtime_worker_finish(worker); |
| 1729 | return NULL; |
| 1730 | } |
| 1731 | hello_result.status = CBM_DAEMON_RUNTIME_CONNECT_CONFLICT; |
| 1732 | hello_result.hello_status = hello_status; |
| 1733 | (void)cbm_daemon_conflict_format(&hello_result.conflict, hello_result.message, |
| 1734 | sizeof(hello_result.message)); |
| 1735 | if (!cbm_daemon_conflict_log_append(service->conflict_log_path, &hello_result.conflict, |
| 1736 | service->conflict_log_cap_bytes)) { |
| 1737 | /* This goes through the daemon operation-log sink, never back |
nothing calls this directly
no test coverage detected