#include #include "icmp.h" #include "ft_ping_flags.h" #include "internal/loop.h" #include "internal/send.h" #include "internal/callback.h" #include "internal/tracker.h" #include "internal/output.h" #include "internal/scheduler.h" /* Forward declarations */ static int deadline_expired(const t_ping_state *state); static int linger_expired(const t_ping_state *state); static int should_stop(const t_ping_state *state); static int can_send_more(const t_ping_state *state); static void do_send(t_ping_state *state, size_t payload_len); static void try_recv(t_ping_state *state); static void handle_send_trigger(t_ping_state *state, size_t payload_len); /* -------------------- */ void ping_loop(t_ping_state *state, size_t payload_len) { do { handle_send_trigger(state, payload_len); if (should_stop(state)) break; try_recv(state); } while (state->send_flag || !should_stop(state)); } static int deadline_expired(const t_ping_state *state) { struct timespec now; double elapsed; if (0.0 == state->config->deadline) return 0; icmp_get_time(&now); elapsed = (double)(now.tv_sec - state->start_time.tv_sec) + (double)(now.tv_nsec - state->start_time.tv_nsec) / 1e9; return elapsed >= state->config->deadline; } static int linger_expired(const t_ping_state *state) { struct timespec now; double elapsed; if (0 == state->linger_start.tv_sec && 0 == state->linger_start.tv_nsec) return 0; icmp_get_time(&now); elapsed = (double)(now.tv_sec - state->linger_start.tv_sec) + (double)(now.tv_nsec - state->linger_start.tv_nsec) / 1e9; return elapsed >= state->config->timeout; } static int should_stop(const t_ping_state *state) { size_t count; if (state->stop_flag) return 1; if (deadline_expired(state)) return 1; if (linger_expired(state)) return 1; count = state->config->count; if (0 != count && state->tracker->nb_recv >= count) return 1; return 0; } static int can_send_more(const t_ping_state *state) { size_t count; count = state->config->count; return 0 == count || state->tracker->nb_sent < count; } static void do_send(t_ping_state *state, size_t payload_len) { state->send_flag = 0; ping_send_one(state, payload_len); if (HAS_FLAG(state->config->flags, FLAG_FLOOD)) ping_output_flood_dot(); ping_scheduler_arm(state->config); } static void try_recv(t_ping_state *state) { int fd; fd_set rfds; struct timeval tv; int ret; fd = icmp_get_fd(state->handle); ping_scheduler_select_tv(state->config, &tv); FD_ZERO(&rfds); FD_SET(fd, &rfds); ret = select(fd + 1, &rfds, NULL, NULL, &tv); if (0 < ret) icmp_process(state->handle, ping_callback, state, 0); } static void handle_send_trigger(t_ping_state *state, size_t payload_len) { if (!state->send_flag && !HAS_FLAG(state->config->flags, FLAG_FLOOD)) return; if (can_send_more(state)) do_send(state, payload_len); else { if (0 == state->linger_start.tv_sec && 0 == state->linger_start.tv_nsec) icmp_get_time(&state->linger_start); state->send_flag = 0; } }