Like th_http but arms a client-side receive-timeout watchdog. If the * single-threaded server wedges, recv() returns instead of blocking forever, so * the test FAILs deterministically rather than hanging CI. 0 on connect/timeout. */
| 972 | * single-threaded server wedges, recv() returns instead of blocking forever, so |
| 973 | * the test FAILs deterministically rather than hanging CI. 0 on connect/timeout. */ |
| 974 | static int th_http_deadline(int port, const char *request, char *resp, size_t respsz, |
| 975 | int timeout_ms) { |
| 976 | th_sock_t s = th_connect(port); |
| 977 | if (s == TH_SOCK_BAD) |
| 978 | return 0; |
| 979 | #ifdef _WIN32 |
| 980 | DWORD tv = (DWORD)timeout_ms; |
| 981 | setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv)); |
| 982 | #else |
| 983 | struct timeval tv; |
| 984 | tv.tv_sec = timeout_ms / 1000; |
| 985 | tv.tv_usec = (timeout_ms % 1000) * 1000; |
| 986 | setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); |
| 987 | #endif |
| 988 | if (th_send_all(s, request, strlen(request)) != 0) { |
| 989 | th_sock_close(s); |
| 990 | return 0; |
| 991 | } |
| 992 | int n = th_recv_until_close(s, resp, respsz); |
| 993 | th_sock_close(s); |
| 994 | return n; |
| 995 | } |
| 996 | |
| 997 | /* #798 was a single-threaded-server wedge: list_projects never returned and the |
| 998 | * whole UI stopped answering. Assert the running server answers list_projects |
no test coverage detected