128 lines
3 KiB
C
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;
|
|
}
|
|
}
|