net-tools/src/core/loop.c
2026-03-12 16:12:18 +01:00

128 lines
3 KiB
C

#include <sys/select.h>
#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;
}
}