#include "icmp.h" #include "icmp_types.h" #include "ft_ping_flags.h" #include "internal/ping/callback.h" #include "internal/ping/ping_state.h" #include "internal/ping/stats.h" #include "internal/ping/tracker.h" #include "internal/ping/output.h" /* Forward declarations */ static int extract_our_echo(const icmp_reply_t *reply, uint16_t our_id, uint16_t *seq_out); static void handle_echo_reply(t_ping_state *state, const icmp_reply_t *reply); static int extract_our_error(const icmp_reply_t *reply, uint16_t our_id, icmp_offending_packet_t *out, uint16_t *seq_out); static void handle_icmp_error(t_ping_state *state, const icmp_reply_t *reply); /* -------------------- */ void ping_callback(const icmp_reply_t *reply, void *userdata) { t_ping_state *state; state = (t_ping_state *)userdata; if (ICMP_TYPE_ECHO_REPLY == reply->type) handle_echo_reply(state, reply); else if (ICMP_TYPE_TIME_EXCEEDED == reply->type || ICMP_TYPE_DEST_UNREACHABLE == reply->type) handle_icmp_error(state, reply); } static int extract_our_echo(const icmp_reply_t *reply, uint16_t our_id, uint16_t *seq_out) { uint16_t id; uint16_t seq; if (0 > icmp_reply_id_seq(reply, &id, &seq)) return 0; if (our_id != id) return 0; *seq_out = seq; return 1; } static void handle_echo_reply(t_ping_state *state, const icmp_reply_t *reply) { uint16_t seq; int64_t rtt; if (0 == extract_our_echo(reply, state->id, &seq)) return; rtt = ping_tracker_record_recv(state->tracker, seq, &reply->timestamp); if (0 > rtt) return; ping_stats_update(state->stats, rtt); if (HAS_FLAG(state->config->flags, FLAG_FLOOD)) ping_output_flood_erase(); else ping_output_packet(reply, seq, rtt, state->config->packet_size, state->config); } static int extract_our_error(const icmp_reply_t *reply, uint16_t our_id, icmp_offending_packet_t *out, uint16_t *seq_out) { if (0 > icmp_error_extract_offending(reply, out)) return 0; if (ICMP_TYPE_ECHO_REQUEST != out->icmp_type) return 0; if (our_id != out->rest.echo.id) return 0; *seq_out = out->rest.echo.seq; return 1; } static void handle_icmp_error(t_ping_state *state, const icmp_reply_t *reply) { icmp_offending_packet_t offending; uint16_t seq; if (0 == extract_our_error(reply, state->id, &offending, &seq)) return; if (0 > ping_tracker_record_recv(state->tracker, seq, &reply->timestamp)) return; state->nb_errors++; if (!HAS_FLAG(state->config->flags, FLAG_QUIET)) ping_output_error(reply, &offending, seq, state->config); }