| 3342 | } |
| 3343 | |
| 3344 | cbm_daemon_ipc_connection_t *cbm_daemon_ipc_connect(const cbm_daemon_ipc_endpoint_t *endpoint, |
| 3345 | uint32_t timeout_ms) { |
| 3346 | if (!endpoint_runtime_still_valid(endpoint)) { |
| 3347 | return NULL; |
| 3348 | } |
| 3349 | uint64_t deadline_ms = ipc_deadline_after(timeout_ms); |
| 3350 | for (;;) { |
| 3351 | struct stat status; |
| 3352 | if (fstatat(endpoint->dir_fd, endpoint->socket_name, &status, AT_SYMLINK_NOFOLLOW) != 0) { |
| 3353 | int path_error = errno; |
| 3354 | if (path_error == ENOENT && ipc_retry_pause(deadline_ms)) { |
| 3355 | continue; |
| 3356 | } |
| 3357 | return NULL; |
| 3358 | } |
| 3359 | if (!posix_socket_status_secure_transport(&status)) { |
| 3360 | return NULL; |
| 3361 | } |
| 3362 | |
| 3363 | int fd = local_socket_new(); |
| 3364 | if (fd < 0) { |
| 3365 | return NULL; |
| 3366 | } |
| 3367 | struct sockaddr_un address; |
| 3368 | socklen_t address_length; |
| 3369 | if (!unix_address_set(&address, endpoint->address, &address_length)) { |
| 3370 | (void)close(fd); |
| 3371 | return NULL; |
| 3372 | } |
| 3373 | |
| 3374 | int result = local_socket_connect(fd, &address, address_length); |
| 3375 | int connect_error = result == 0 ? 0 : errno; |
| 3376 | if (result != 0 && connect_error != EINPROGRESS && connect_error != EAGAIN && |
| 3377 | connect_error != EWOULDBLOCK) { |
| 3378 | (void)close(fd); |
| 3379 | if ((connect_error == ENOENT || connect_error == ECONNREFUSED) && |
| 3380 | ipc_retry_pause(deadline_ms)) { |
| 3381 | continue; |
| 3382 | } |
| 3383 | return NULL; |
| 3384 | } |
| 3385 | if (result != 0) { |
| 3386 | int ready = poll_until(fd, POLLOUT, deadline_ms); |
| 3387 | int socket_error = 0; |
| 3388 | socklen_t error_length = sizeof(socket_error); |
| 3389 | if (ready != 1 || |
| 3390 | getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_error, &error_length) != 0) { |
| 3391 | (void)close(fd); |
| 3392 | return NULL; |
| 3393 | } |
| 3394 | if (socket_error != 0) { |
| 3395 | (void)close(fd); |
| 3396 | if ((socket_error == ENOENT || socket_error == ECONNREFUSED) && |
| 3397 | ipc_retry_pause(deadline_ms)) { |
| 3398 | continue; |
| 3399 | } |
| 3400 | return NULL; |
| 3401 | } |