+ // Main loop (event loop)
+ while (1) {
+ int active_count = 0;
+ int max_fd = -1;
+ fd_set readfds;
+ FD_ZERO(&readfds);
+
+ // 1. Collect FDs for select
+ for (int i = 0; i < num_hosts; i++) {
+ trace_session_t *s = &sessions[i];
+ if (s->state == STATE_FINISHED || s->state == STATE_ERROR) continue;
+ active_count++;
+
+ // While waiting for a response, we add the socket to the read set.
+ if (s->state == STATE_AWAIT_REPLY && s->sock >= 0) {
+ FD_SET(s->sock, &readfds);
+ if (s->sock > max_fd) max_fd = s->sock;
+ }
+ }
+ if (active_count == 0) break;
+
+ // 2. Select with a short timeout (10 ms) so that we can check send/timeouts.
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 10000;
+ select(max_fd + 1, &readfds, NULL, NULL, &tv);
+
+ // 3. Processing for all sessions
+ for (int i = 0; i < num_hosts; i++) {
+ trace_session_t *s = &sessions[i];
+ if (s->state == STATE_FINISHED || s->state == STATE_ERROR) continue;
+
+ // A) Read (if data is available)
+ if (s->state == STATE_AWAIT_REPLY && s->sock >= 0 && FD_ISSET(s->sock, &readfds)) {
+ process_read(s);
+ }
+
+ // B) Timeout check (if still waiting)
+ if (s->state == STATE_AWAIT_REPLY) {
+ process_timeout_check(s);
+ }
+
+ // C) Preparing a new hop
+ if (s->state == STATE_PREPARE_HOP) {
+ s->current_ttl++;
+ if (s->current_ttl > s->max_hops) {
+ fprintf(stderr, "[%s] Target not reached (max_hops=%d).\n", s->host_arg, s->max_hops);
+ s->state = STATE_FINISHED;
+ session_close(s);
+ } else {
+ // Initialize output buffer
+ s->line_off = 0;
+ s->line_off += snprintf(s->line_buf + s->line_off, sizeof(s->line_buf) - s->line_off, "[%s] %2d ", s->host_arg, s->current_ttl);
+
+ // Set socket TTL
+ if (s->dst.ss_family == AF_INET) {
+ setsockopt(s->sock, IPPROTO_IP, IP_TTL, &s->current_ttl, sizeof(s->current_ttl));
+ } else {
+ setsockopt(s->sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &s->current_ttl, sizeof(s->current_ttl));
+ }
+
+ s->current_probe = 0;
+ s->printed_addr = false;
+ s->state = STATE_SEND_PROBE;
+ }
+ }
+
+ // D) Send (when ready)
+ if (s->state == STATE_SEND_PROBE) {
+ process_send(s);
+ }
+ }