Compare commits
1 commit
main
...
feat/trace
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3717e01ab9 |
62 changed files with 989 additions and 676 deletions
2
LICENSE
2
LICENSE
|
|
@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
|||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
net-tools Copyright (C) 2026 lohhiiccc
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
if BUILD_BUNDLED_LIBCLI
|
||||
SUBDIRS = libcli src
|
||||
else
|
||||
SUBDIRS = src
|
||||
endif
|
||||
|
||||
if BUILD_TESTS
|
||||
SUBDIRS += tests
|
||||
|
|
|
|||
36
README.md
36
README.md
|
|
@ -41,21 +41,18 @@ ft_ping - Send ICMP ECHO_REQUEST to network hosts
|
|||
Usage: ft_ping [options] <destination>
|
||||
|
||||
Options:
|
||||
-h, --help Display this help and exit
|
||||
-V, --version Display version information and exit
|
||||
-v, --verbose Verbose output
|
||||
-q, --quiet Quiet mode (only show summary)
|
||||
-c, --count <NUM> Stop after sending N packets
|
||||
-i, --interval <SEC> Wait N seconds between packets
|
||||
-T, --tos <NUM> Set Type of Service (TOS)
|
||||
-t, --ttl <TTL> Set Time To Live
|
||||
-s, --size <SIZE> Packet size in bytes
|
||||
-W, --linger <SEC> Timeout for replies in seconds
|
||||
-w, --timeout <SEC> Exit after N seconds regardless of packets sent/received
|
||||
-f, --flood Flood mode
|
||||
-M, --dont-fragment Set the Don't Fragment bit
|
||||
-l, --preload <NUM> Send N packets in burst before normal loop
|
||||
-p, --pattern <HEX> Fill packet payload with hex pattern
|
||||
-h, --help Display this help and exit
|
||||
-V, --version Display version information and exit
|
||||
-v, --verbose Verbose output
|
||||
-q, --quiet Quiet mode (only show summary)
|
||||
-c, --count <NUM> Stop after sending N packets
|
||||
-i, --interval <SEC> Wait N seconds between packets
|
||||
-t, --ttl <TTL> Set Time To Live
|
||||
-s, --size <SIZE> Packet size in bytes
|
||||
-W, --timeout <SEC> Timeout for replies in seconds
|
||||
-w, --deadline <SEC> Exit after N seconds regardless of packets sent/received
|
||||
-f, --flood Flood mode
|
||||
-M, --dont-fragment Set the Don't Fragment bit
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
|
@ -65,7 +62,7 @@ Handles everything ICMP at the socket level: open a raw socket, build and
|
|||
send echo requests, receive and parse replies. No loop, no display. Just a
|
||||
clean interface over the kernel socket.
|
||||
|
||||
### libcli
|
||||
### src/cli
|
||||
Shared CLI parsing layer used by all binaries. Provides a generic getopt
|
||||
wrapper and primitive parsers (int, float) that each binary plugs into.
|
||||
|
||||
|
|
@ -86,10 +83,9 @@ Manages timing and signals. Installs SIGALRM (triggers send) and SIGINT
|
|||
Signal handlers only write a flag -- the loop does the actual work.
|
||||
|
||||
### src/ping/tracker
|
||||
A bitmap over the full 16-bit sequence space (UINT16_MAX bits). Marks
|
||||
each sequence number when a reply arrives and detects duplicates. Send
|
||||
timestamps are not stored here — RTT is computed from a timestamp
|
||||
embedded at the start of the payload.
|
||||
A 128-slot circular buffer indexed by (seq % 128). Records when each
|
||||
packet was sent and marks it when a reply arrives. Used to compute RTT
|
||||
and detect duplicates.
|
||||
|
||||
### src/ping/stats
|
||||
Accumulates RTT samples (min, max, sum, sum of squares) in nanoseconds.
|
||||
|
|
|
|||
13
autogen.sh
13
autogen.sh
|
|
@ -2,5 +2,14 @@
|
|||
# autogen.sh - Generate Autotools build files
|
||||
|
||||
set -e
|
||||
mkdir -pv m4 build-aux
|
||||
autoreconf -f --install --verbose
|
||||
|
||||
# Generate libcli configure first (it's an Autotools submodule)
|
||||
if [ -f libcli/autogen.sh ]; then
|
||||
echo "[autogen] Configuring libcli submodule..."
|
||||
(cd libcli && ./autogen.sh)
|
||||
fi
|
||||
|
||||
echo "[autogen] Running autoreconf..."
|
||||
autoreconf -fiv
|
||||
|
||||
echo "[autogen] Done. Now run: ./configure && make"
|
||||
|
|
|
|||
115
configure.ac
115
configure.ac
|
|
@ -2,7 +2,7 @@ AC_PREREQ([2.69])
|
|||
AC_INIT([net-tools], [0.0.1], [])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_MACRO_DIRS([m4])
|
||||
AM_INIT_AUTOMAKE([foreign -Wall -Werror subdir-objects])
|
||||
AM_INIT_AUTOMAKE([foreign -Wall subdir-objects])
|
||||
|
||||
# Compiler: prefer clang
|
||||
AC_PROG_CC
|
||||
|
|
@ -13,96 +13,65 @@ if test "x$GCC" = "xyes" && test "x$CC" = "xgcc"; then
|
|||
AC_MSG_NOTICE([Using clang])
|
||||
fi
|
||||
fi
|
||||
if test "x$ac_cv_env_CFLAGS_set" != "xset"; then
|
||||
CFLAGS=""
|
||||
fi
|
||||
|
||||
STRICT_CFLAGS="-Wall -Wextra -Werror -pipe -Wpedantic -Wconversion -Wshadow -Wvla"
|
||||
AC_SUBST([STRICT_CFLAGS])
|
||||
|
||||
AM_PROG_AR
|
||||
LT_PREREQ([2.2])
|
||||
LT_INIT
|
||||
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
# --enable-debug
|
||||
AC_ARG_ENABLE(
|
||||
[debug],
|
||||
[AS_HELP_STRING([--enable-debug], [Enable debug build: -g -O0 (default: no)])],
|
||||
[enable_debug=$enableval],
|
||||
[enable_debug=no]
|
||||
)
|
||||
AM_CONDITIONAL([ENABLE_DEBUG], [test "x$enable_debug" = "xyes"])
|
||||
AS_IF([test "x$enable_debug" = "xyes"],
|
||||
[CFLAGS="-g -O0"],
|
||||
[CFLAGS="-O2"],
|
||||
)
|
||||
|
||||
AC_SUBST([DEBUG_CFLAGS])
|
||||
|
||||
|
||||
# --with-bundled-libcli
|
||||
AC_ARG_WITH(
|
||||
[bundled-libcli],
|
||||
AS_HELP_STRING([--with-bundled-libcli], [force using bundled ./libcli (ignore system)]),
|
||||
[with_bundled_libcli=yes],
|
||||
[with_bundled_libcli=no]
|
||||
)
|
||||
have_system_libcli=no
|
||||
|
||||
AS_IF([test "x$with_bundled_libcli" != "xyes"], [
|
||||
PKG_CHECK_MODULES(
|
||||
[LIBCLI], [libcli >= 0.1.0],
|
||||
[have_system_libcli=yes],
|
||||
[have_system_libcli=no]
|
||||
)
|
||||
])
|
||||
|
||||
AM_CONDITIONAL([USE_SYSTEM_LIBCLI], [test "x$have_system_libcli" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_BUNDLED_LIBCLI], [test "x$have_system_libcli" != "xyes"])
|
||||
|
||||
AC_SUBST([LIBCLI_CFLAGS])
|
||||
AC_SUBST([LIBCLI_LIBS])
|
||||
|
||||
AS_IF([test "x$have_system_libcli" != "xyes"], [AC_CONFIG_SUBDIRS([libcli])])
|
||||
# Strict flags — always enabled, not optional
|
||||
STRICT_CFLAGS="-Wall -Wextra -Werror -Wpedantic -Wconversion -Wshadow"
|
||||
AC_SUBST([STRICT_CFLAGS])
|
||||
|
||||
# libcli: Autotools submodule — configure automatically
|
||||
AC_CONFIG_SUBDIRS([libcli])
|
||||
|
||||
# --enable-tests
|
||||
AC_ARG_ENABLE(
|
||||
[tests],
|
||||
[AS_HELP_STRING([--enable-tests], [Build Criterion unit tests (default: no)])],
|
||||
[enable_tests=$enableval],
|
||||
[enable_tests=no]
|
||||
)
|
||||
AC_ARG_ENABLE([tests],
|
||||
[AS_HELP_STRING([--enable-tests], [Build Criterion unit tests (default: no)])],
|
||||
[enable_tests=$enableval],
|
||||
[enable_tests=no])
|
||||
AM_CONDITIONAL([BUILD_TESTS], [test "x$enable_tests" = "xyes"])
|
||||
AS_IF([test "x$enable_tests" = "xyes"], [
|
||||
PKG_CHECK_MODULES([CRITERION], [criterion], [], [
|
||||
AC_MSG_NOTICE([pkg-config could not find criterion -- trying manual detection])
|
||||
AC_CHECK_HEADER([criterion/criterion.h], [], [AC_MSG_ERROR([criterion/criterion.h not found])])
|
||||
AC_CHECK_LIB([criterion], [main],
|
||||
[CRITERION_LIBS="-lcriterion"],
|
||||
[AC_MSG_ERROR([libcriterion not found])])
|
||||
])
|
||||
])
|
||||
PKG_CHECK_MODULES([CRITERION], [criterion], [], [
|
||||
AC_MSG_NOTICE([pkg-config could not find criterion -- trying manual detection])
|
||||
AC_CHECK_HEADER([criterion/criterion.h], [], [
|
||||
AC_MSG_ERROR([criterion/criterion.h not found])])
|
||||
AC_CHECK_LIB([criterion], [main],
|
||||
[CRITERION_LIBS="-lcriterion"],
|
||||
[AC_MSG_ERROR([libcriterion not found])])
|
||||
])
|
||||
])
|
||||
|
||||
# --enable-debug
|
||||
AC_ARG_ENABLE([debug],
|
||||
[AS_HELP_STRING([--enable-debug], [Enable debug build: -g -O0 (default: no)])],
|
||||
[enable_debug=$enableval],
|
||||
[enable_debug=no])
|
||||
AM_CONDITIONAL([ENABLE_DEBUG], [test "x$enable_debug" = "xyes"])
|
||||
|
||||
# --enable-sanitizers
|
||||
AC_ARG_ENABLE([sanitizers],
|
||||
[AS_HELP_STRING([--enable-sanitizers],
|
||||
[Enable AddressSanitizer and UndefinedBehaviorSanitizer (default: no)])],
|
||||
[enable_sanitizers=$enableval],
|
||||
[enable_sanitizers=no])
|
||||
AM_CONDITIONAL([ENABLE_SANITIZERS], [test "x$enable_sanitizers" = "xyes"])
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
src/ping/Makefile
|
||||
src/traceroute/Makefile
|
||||
tests/Makefile
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_NOTICE([
|
||||
|
||||
net-tools $VERSION
|
||||
------------------
|
||||
PREFIX : $prefix
|
||||
CC : $CC
|
||||
CFLAGS : $STRICT_CFLAGS $CFLAGS
|
||||
tests : $enable_tests
|
||||
debug : $enable_debug
|
||||
libcli : system=$have_system_libcli (forced bundled=$with_bundled_libcli)
|
||||
net-tools $VERSION
|
||||
------------------
|
||||
CC : $CC
|
||||
CFLAGS : $STRICT_CFLAGS
|
||||
tests : $enable_tests
|
||||
debug : $enable_debug
|
||||
sanitizers : $enable_sanitizers
|
||||
])
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ enum {
|
|||
OPT_ARG_SECONDS = OPT_ARG_STRING + 1,
|
||||
OPT_ARG_BYTES,
|
||||
OPT_ARG_TTL,
|
||||
OPT_ARG_PATTERN,
|
||||
};
|
||||
|
||||
#define PING_OPTIONS_LIST \
|
||||
|
|
@ -61,14 +60,6 @@ enum {
|
|||
OPT_ARG_SECONDS, \
|
||||
"Wait N seconds between packets" \
|
||||
) \
|
||||
X( \
|
||||
'T', \
|
||||
"tos", \
|
||||
required_argument, \
|
||||
cli_handle_tos, \
|
||||
OPT_ARG_UINT, \
|
||||
"Set Type of Service (TOS)" \
|
||||
) \
|
||||
X( \
|
||||
't', \
|
||||
"ttl", \
|
||||
|
|
@ -87,17 +78,17 @@ enum {
|
|||
) \
|
||||
X( \
|
||||
'W', \
|
||||
"linger", \
|
||||
"timeout", \
|
||||
required_argument, \
|
||||
cli_handle_linger, \
|
||||
cli_handle_timeout, \
|
||||
OPT_ARG_SECONDS, \
|
||||
"Timeout for replies in seconds" \
|
||||
) \
|
||||
X( \
|
||||
'w', \
|
||||
"timeout", \
|
||||
"deadline", \
|
||||
required_argument, \
|
||||
cli_handle_timeout, \
|
||||
cli_handle_deadline, \
|
||||
OPT_ARG_SECONDS, \
|
||||
"Exit after N seconds regardless of packets sent/received" \
|
||||
) \
|
||||
|
|
@ -116,22 +107,6 @@ enum {
|
|||
cli_handle_dont_fragment, \
|
||||
OPT_ARG_NONE, \
|
||||
"Set the Don't Fragment bit" \
|
||||
) \
|
||||
X( \
|
||||
'l', \
|
||||
"preload", \
|
||||
required_argument, \
|
||||
cli_handle_preload, \
|
||||
OPT_ARG_UINT, \
|
||||
"Send N packets in burst before normal loop" \
|
||||
) \
|
||||
X( \
|
||||
'p', \
|
||||
"pattern", \
|
||||
required_argument, \
|
||||
cli_handle_pattern, \
|
||||
OPT_ARG_PATTERN, \
|
||||
"Fill packet payload with hex pattern" \
|
||||
)
|
||||
|
||||
#undef X
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
#ifndef CLI_INTERNAL_PARSE_UTILS
|
||||
#define CLI_INTERNAL_PARSE_UTILS
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int cli_parse_uint64(const char *s, uint64_t *out);
|
||||
int cli_parse_float(const char *s, float *out);
|
||||
int cli_parse_ufloat(const char *s, float *out);
|
||||
int cli_parse_hex(const char *str, uint8_t *out, size_t max_len, size_t
|
||||
*out_len);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -6,17 +6,14 @@
|
|||
extern const struct option_descriptor g_options[];
|
||||
|
||||
int cli_handle_count(const char *arg, void *config);
|
||||
int cli_handle_preload(const char *arg, void *config);
|
||||
int cli_handle_pattern(const char *arg, void *config);
|
||||
int cli_handle_dont_fragment(const char *arg, void *config);
|
||||
int cli_handle_deadline(const char *arg, void *config);
|
||||
int cli_handle_flood(const char *arg, void *config);
|
||||
int cli_handle_help(const char *arg, void *config);
|
||||
int cli_handle_interval(const char *arg, void *config);
|
||||
int cli_handle_quiet(const char *arg, void *config);
|
||||
int cli_handle_size(const char *arg, void *config);
|
||||
int cli_handle_linger(const char *arg, void *config);
|
||||
int cli_handle_timeout(const char *arg, void *config);
|
||||
int cli_handle_tos(const char *arg, void *config);
|
||||
int cli_handle_ttl(const char *arg, void *config);
|
||||
int cli_handle_verbose(const char *arg, void *config);
|
||||
int cli_handle_version(const char *arg, void *config);
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef PING_HANDLERS_H
|
||||
#define PING_HANDLERS_H
|
||||
|
||||
#include "icmp.h"
|
||||
#include "internal/ping/ping_state.h"
|
||||
|
||||
void ping_handle_echo_reply(struct ping_state *state,
|
||||
const icmp_reply_t *reply);
|
||||
void ping_handle_icmp_error(struct ping_state *state,
|
||||
const icmp_reply_t *reply);
|
||||
|
||||
#endif
|
||||
|
|
@ -10,8 +10,7 @@
|
|||
void ping_output_start(const struct ping_config *config,
|
||||
struct destinations *dest, size_t payload_bytes);
|
||||
void ping_output_packet(const icmp_reply_t *reply, uint16_t seq,
|
||||
int64_t rtt_ns, size_t payload_bytes, const struct ping_config *config,
|
||||
int is_dup);
|
||||
int64_t rtt_ns, size_t payload_bytes, const struct ping_config *config);
|
||||
void ping_output_error(const icmp_reply_t *reply,
|
||||
const icmp_offending_packet_t *offending,
|
||||
uint16_t seq, const struct ping_config *config);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ struct ping_state {
|
|||
volatile sig_atomic_t send_flag;
|
||||
volatile sig_atomic_t stop_flag;
|
||||
size_t nb_errors;
|
||||
int ts_in_payload;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,16 +3,28 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <time.h>
|
||||
|
||||
struct ping_tracker {
|
||||
uint8_t rcvd[UINT16_MAX / 8];
|
||||
size_t nb_sent;
|
||||
size_t nb_recv;
|
||||
size_t nb_dup;
|
||||
#include "internal/ping/tracker_flags.h"
|
||||
|
||||
#define PING_TRACKER_SLOTS 128
|
||||
|
||||
struct ping_tracker_slot {
|
||||
struct timespec ts;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
void ping_tracker_init(struct ping_tracker *t);
|
||||
void ping_tracker_record_send(struct ping_tracker *t, uint16_t seq);
|
||||
int ping_tracker_record_recv(struct ping_tracker *t, uint16_t seq);
|
||||
struct ping_tracker {
|
||||
struct ping_tracker_slot slots[PING_TRACKER_SLOTS];
|
||||
size_t nb_sent;
|
||||
size_t nb_recv;
|
||||
};
|
||||
|
||||
void ping_tracker_init(struct ping_tracker *t);
|
||||
void ping_tracker_record_send(struct ping_tracker *t, uint16_t seq, const
|
||||
struct timespec *ts);
|
||||
int64_t ping_tracker_record_recv(struct ping_tracker *t, uint16_t seq,
|
||||
const struct timespec *ts);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
14
includes/internal/traceroute/cli_handlers.h
Normal file
14
includes/internal/traceroute/cli_handlers.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef TRACEROUTE_CLI_HANDLERS_H
|
||||
#define TRACEROUTE_CLI_HANDLERS_H
|
||||
|
||||
#include "cli.h"
|
||||
|
||||
extern const struct option_descriptor g_options[];
|
||||
|
||||
int cli_handle_help(const char *arg, void *config);
|
||||
int cli_handle_version(const char *arg, void *config);
|
||||
int cli_handle_verbose(const char *arg, void *config);
|
||||
int cli_handle_max_ttl(const char *arg, void *config);
|
||||
int cli_handle_waittime(const char *arg, void *config);
|
||||
|
||||
#endif
|
||||
65
includes/internal/traceroute/options.h
Normal file
65
includes/internal/traceroute/options.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#ifndef TRACEROUTE_CLI_OPT_H
|
||||
#define TRACEROUTE_CLI_OPT_H
|
||||
|
||||
#include <getopt.h>
|
||||
#include "cli.h"
|
||||
|
||||
enum {
|
||||
OPT_TR_ARG_HOPS = OPT_ARG_STRING + 1,
|
||||
OPT_TR_ARG_SECONDS,
|
||||
};
|
||||
|
||||
#define TRACEROUTE_OPTIONS_LIST \
|
||||
X( \
|
||||
'h', \
|
||||
"help", \
|
||||
no_argument, \
|
||||
cli_handle_help, \
|
||||
OPT_ARG_NONE, \
|
||||
"Display this help and exit" \
|
||||
) \
|
||||
X( \
|
||||
'V', \
|
||||
"version", \
|
||||
no_argument, \
|
||||
cli_handle_version, \
|
||||
OPT_ARG_NONE, \
|
||||
"Display version information and exit" \
|
||||
) \
|
||||
X( \
|
||||
'v', \
|
||||
"verbose", \
|
||||
no_argument, \
|
||||
cli_handle_verbose, \
|
||||
OPT_ARG_NONE, \
|
||||
"Verbose output" \
|
||||
) \
|
||||
X( \
|
||||
'm', \
|
||||
"max-ttl", \
|
||||
required_argument, \
|
||||
cli_handle_max_ttl, \
|
||||
OPT_TR_ARG_HOPS, \
|
||||
"Set the max number of hops" \
|
||||
) \
|
||||
X( \
|
||||
'w', \
|
||||
"waittime", \
|
||||
required_argument, \
|
||||
cli_handle_waittime, \
|
||||
OPT_TR_ARG_SECONDS, \
|
||||
"Set the time to wait for a response" \
|
||||
)
|
||||
|
||||
#undef X
|
||||
#define X(short_opt, long_opt, has_arg, handler, arg_type, desc) + 1
|
||||
enum { TR_OPT_LEN = (0 TRACEROUTE_OPTIONS_LIST) };
|
||||
|
||||
#undef X
|
||||
#define X(short_opt, long_opt, has_arg, handler, arg_type, desc) \
|
||||
+ (1 * (has_arg == no_argument) \
|
||||
+ (2 * (has_arg == required_argument) \
|
||||
+ (3 * (has_arg == optional_argument))))
|
||||
enum { TR_OPTSTR_LEN = (2 TRACEROUTE_OPTIONS_LIST) };
|
||||
|
||||
#endif
|
||||
9
includes/internal/traceroute/parse_utils.h
Normal file
9
includes/internal/traceroute/parse_utils.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef TRACEROUTE_CLI_PARSE_UTILS_H
|
||||
#define TRACEROUTE_CLI_PARSE_UTILS_H
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include "traceroute/traceroute.h"
|
||||
|
||||
int cli_parse_destination(const char *s, struct traceroute_config *config);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,21 +1,15 @@
|
|||
#ifndef FT_PING_CONST
|
||||
#define FT_PING_CONST
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/* Default configuration values */
|
||||
#define DEFAULT_COUNT 0
|
||||
#define DEFAULT_PRELOAD 1
|
||||
#define DEFAULT_INTERVAL 1.0
|
||||
#define DEFAULT_TTL 64
|
||||
#define DEFAULT_PACKET_SIZE 56
|
||||
#define DEFAULT_LINGER 1.0
|
||||
#define DEFAULT_TIMEOUT 1.0
|
||||
|
||||
/* Maximum values */
|
||||
#define MAX_PACKET_SIZE 65507
|
||||
#define MAX_TTL 255
|
||||
|
||||
/* Minimum payload size to embed a send timestamp */
|
||||
#define PING_TIMESTAMP_SIZE ((size_t)sizeof(struct timespec))
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,17 +16,11 @@ struct ping_config
|
|||
|
||||
/* Options */
|
||||
uint64_t count;
|
||||
uint64_t preload;
|
||||
double interval;
|
||||
uint8_t ttl;
|
||||
uint8_t tos;
|
||||
size_t packet_size;
|
||||
double linger;
|
||||
double timeout;
|
||||
|
||||
/* Pattern (-p) */
|
||||
uint8_t pattern[16];
|
||||
uint8_t pattern_len;
|
||||
double deadline;
|
||||
|
||||
/* Flags */
|
||||
uint8_t flags;
|
||||
|
|
|
|||
11
includes/traceroute/cli.h
Normal file
11
includes/traceroute/cli.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef TRACEROUTE_CLI_H
|
||||
#define TRACEROUTE_CLI_H
|
||||
|
||||
#include <cli.h>
|
||||
#include "traceroute/traceroute.h"
|
||||
|
||||
enum cli_code cli_parse_arguments(int argc, char **argv, struct
|
||||
traceroute_config *config);
|
||||
void cli_config_free(struct traceroute_config *config);
|
||||
|
||||
#endif
|
||||
11
includes/traceroute/ft_traceroute_const.h
Normal file
11
includes/traceroute/ft_traceroute_const.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef FT_TRACEROUTE_CONST_H
|
||||
#define FT_TRACEROUTE_CONST_H
|
||||
|
||||
#define DEFAULT_MAX_TTL 30
|
||||
#define DEFAULT_NQUERIES 3
|
||||
#define DEFAULT_WAITTIME 5.0
|
||||
|
||||
#define MAX_TRACEROUTE_TTL 255
|
||||
#define MAX_NQUERIES 10
|
||||
|
||||
#endif
|
||||
10
includes/traceroute/ft_traceroute_flags.h
Normal file
10
includes/traceroute/ft_traceroute_flags.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef FT_TRACEROUTE_FLAGS_H
|
||||
#define FT_TRACEROUTE_FLAGS_H
|
||||
|
||||
#define FLAG_TR_VERBOSE (1 << 0)
|
||||
#define FLAG_TR_NO_DNS (1 << 1)
|
||||
|
||||
#define HAS_FLAG(flags, flag) ((flags) & (flag))
|
||||
#define SET_FLAG(flags, flag) ((flags) |= (flag))
|
||||
|
||||
#endif
|
||||
18
includes/traceroute/traceroute.h
Normal file
18
includes/traceroute/traceroute.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef TRACEROUTE_H
|
||||
#define TRACEROUTE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
struct traceroute_config {
|
||||
const char *destination;
|
||||
struct in_addr dest_ip;
|
||||
uint8_t max_ttl;
|
||||
uint8_t nqueries;
|
||||
double waittime;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
int traceroute_run(const struct traceroute_config *config);
|
||||
|
||||
#endif
|
||||
2
libcli
2
libcli
|
|
@ -1 +1 @@
|
|||
Subproject commit 9f179fa596b1f50007d4995256f47cf5edb4f5dc
|
||||
Subproject commit ae7fdf2f94a7c3c759d449ee1c4d3439473c6e42
|
||||
2
libicmp
2
libicmp
|
|
@ -1 +1 @@
|
|||
Subproject commit 75c5766f00f85d57171bc6c88e4dbe7c4ad6bdd0
|
||||
Subproject commit a9bdaf33f22b60b8643871b2522721cd041ac885
|
||||
|
|
@ -1 +1 @@
|
|||
SUBDIRS = ping
|
||||
SUBDIRS = ping traceroute
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
bin_PROGRAMS = ft_ping
|
||||
noinst_LTLIBRARIES = libping_core.la
|
||||
bin_PROGRAMS = ft_ping
|
||||
noinst_LTLIBRARIES = libping_core.la
|
||||
|
||||
PING_VERSION = 0.0.1
|
||||
VERSION_HEADER = $(top_srcdir)/includes/version_gen.h
|
||||
PING_VERSION = 0.0.1
|
||||
VERSION_HEADER = $(top_srcdir)/includes/version_gen.h
|
||||
|
||||
# Version header: generated at build time (embeds git hash + date)
|
||||
BUILT_SOURCES = $(VERSION_HEADER)
|
||||
CLEANFILES = $(VERSION_HEADER)
|
||||
BUILT_SOURCES = $(VERSION_HEADER)
|
||||
CLEANFILES = $(VERSION_HEADER)
|
||||
|
||||
$(VERSION_HEADER): FORCE
|
||||
@NEW_HEADER=$$(mktemp); \
|
||||
|
|
@ -41,79 +41,80 @@ $(VERSION_HEADER): FORCE
|
|||
FORCE:
|
||||
.PHONY: FORCE
|
||||
|
||||
libping_core_la_SOURCES = \
|
||||
cli/parse.c \
|
||||
cli/handlers/handle_count.c \
|
||||
cli/handlers/handle_preload.c \
|
||||
cli/handlers/handle_pattern.c \
|
||||
cli/handlers/handle_dont_fragment.c \
|
||||
cli/handlers/handle_linger.c \
|
||||
cli/handlers/handle_flood.c \
|
||||
cli/handlers/handle_help.c \
|
||||
cli/handlers/handle_interval.c \
|
||||
cli/handlers/handle_quiet.c \
|
||||
cli/handlers/option_map.c \
|
||||
cli/handlers/handle_size.c \
|
||||
cli/handlers/handle_timeout.c \
|
||||
cli/handlers/handle_tos.c \
|
||||
cli/handlers/handle_ttl.c \
|
||||
cli/handlers/handle_version.c \
|
||||
cli/handlers/handle_verbose.c \
|
||||
cli/parse_utils/parse_inet_addr.c \
|
||||
cli/parse_utils/parse_destinations.c \
|
||||
cli/config_free.c \
|
||||
cli/messages/version.c \
|
||||
cli/messages/error.c \
|
||||
core/ping.c \
|
||||
core/loop.c \
|
||||
core/send.c \
|
||||
core/callback.c \
|
||||
core/reply.c \
|
||||
core/error.c \
|
||||
tracker/init.c \
|
||||
tracker/record_send.c \
|
||||
tracker/record_recv.c \
|
||||
output/start.c \
|
||||
output/packet.c \
|
||||
output/error.c \
|
||||
output/summary.c \
|
||||
output/flood.c \
|
||||
scheduler/scheduler_arm.c \
|
||||
scheduler/scheduler_select_tv.c \
|
||||
scheduler/scheduler_init.c \
|
||||
stats/stats_get.c \
|
||||
stats/stats_init.c \
|
||||
stats/stats_update.c
|
||||
libping_core_la_SOURCES = \
|
||||
cli/parse.c \
|
||||
cli/handlers/handle_count.c \
|
||||
cli/handlers/handle_dont_fragment.c \
|
||||
cli/handlers/handle_deadline.c \
|
||||
cli/handlers/handle_flood.c \
|
||||
cli/handlers/handle_help.c \
|
||||
cli/handlers/handle_interval.c \
|
||||
cli/handlers/handle_quiet.c \
|
||||
cli/handlers/option_map.c \
|
||||
cli/handlers/handle_size.c \
|
||||
cli/handlers/handle_timeout.c \
|
||||
cli/handlers/handle_ttl.c \
|
||||
cli/handlers/handle_version.c \
|
||||
cli/handlers/handle_verbose.c \
|
||||
cli/parse_utils/parse_inet_addr.c \
|
||||
cli/parse_utils/parse_destinations.c \
|
||||
cli/config_free.c \
|
||||
cli/messages/help.c \
|
||||
cli/messages/version.c \
|
||||
cli/messages/error.c \
|
||||
core/ping.c \
|
||||
core/loop.c \
|
||||
core/send.c \
|
||||
core/callback.c \
|
||||
tracker/init.c \
|
||||
tracker/record_send.c \
|
||||
tracker/record_recv.c \
|
||||
output/start.c \
|
||||
output/packet.c \
|
||||
output/error.c \
|
||||
output/summary.c \
|
||||
output/flood.c \
|
||||
scheduler/scheduler_arm.c \
|
||||
scheduler/scheduler_select_tv.c \
|
||||
scheduler/scheduler_init.c \
|
||||
stats/stats_get.c \
|
||||
stats/stats_init.c \
|
||||
stats/stats_update.c
|
||||
|
||||
BASE_CFLAGS = -std=c99 $(STRICT_CFLAGS)
|
||||
BASE_CFLAGS = -std=c99 $(STRICT_CFLAGS)
|
||||
|
||||
if ENABLE_DEBUG
|
||||
EXTRA_CFLAGS = -g -O0
|
||||
EXTRA_CFLAGS = -g -O0
|
||||
else
|
||||
EXTRA_CFLAGS =
|
||||
EXTRA_CFLAGS =
|
||||
endif
|
||||
|
||||
if ENABLE_SANITIZERS
|
||||
SANITIZER_FLAGS = -fsanitize=address,undefined
|
||||
else
|
||||
SANITIZER_FLAGS =
|
||||
endif
|
||||
|
||||
PING_CPPFLAGS = \
|
||||
-I $(top_srcdir)/includes \
|
||||
-I $(top_srcdir)/libicmp/includes \
|
||||
-I $(top_srcdir)/libcli/include \
|
||||
-D_GNU_SOURCE
|
||||
PING_CPPFLAGS = \
|
||||
-I $(top_srcdir)/includes \
|
||||
-I $(top_srcdir)/libicmp/includes \
|
||||
-I $(top_srcdir)/libcli/include \
|
||||
-D_GNU_SOURCE
|
||||
|
||||
PING_CFLAGS = $(BASE_CFLAGS) $(EXTRA_CFLAGS)
|
||||
PING_CFLAGS = $(BASE_CFLAGS) $(EXTRA_CFLAGS) $(SANITIZER_FLAGS)
|
||||
|
||||
libping_core_la_CPPFLAGS = $(PING_CPPFLAGS)
|
||||
libping_core_la_CFLAGS = $(PING_CFLAGS)
|
||||
libping_core_la_CPPFLAGS = $(PING_CPPFLAGS)
|
||||
libping_core_la_CFLAGS = $(PING_CFLAGS)
|
||||
|
||||
ft_ping_SOURCES = main.c
|
||||
ft_ping_CPPFLAGS = $(PING_CPPFLAGS)
|
||||
ft_ping_CFLAGS = $(PING_CFLAGS)
|
||||
ft_ping_LDFLAGS =
|
||||
ft_ping_LDADD = \
|
||||
libping_core.la \
|
||||
$(top_srcdir)/libicmp/libicmp.a \
|
||||
$(top_builddir)/libcli/src/libcli.la \
|
||||
-lm
|
||||
ft_ping_SOURCES = main.c
|
||||
ft_ping_CPPFLAGS = $(PING_CPPFLAGS)
|
||||
ft_ping_CFLAGS = $(PING_CFLAGS)
|
||||
ft_ping_LDFLAGS = $(SANITIZER_FLAGS)
|
||||
ft_ping_LDADD = \
|
||||
libping_core.la \
|
||||
$(top_srcdir)/libicmp/libicmp.a \
|
||||
$(top_builddir)/libcli/src/libcli.la \
|
||||
-lm
|
||||
|
||||
# Build libicmp (simple Makefile) before linking
|
||||
$(top_srcdir)/libicmp/libicmp.a: FORCE
|
||||
|
|
|
|||
|
|
@ -1,37 +1,11 @@
|
|||
#include <stdio.h>
|
||||
#include "cli.h"
|
||||
#include "compiler.h"
|
||||
#include "internal/cli/options.h"
|
||||
#include "internal/ping/cli_handlers.h"
|
||||
#include "ping/cli.h"
|
||||
|
||||
/* Forward declarations */
|
||||
static inline const char * option_arg_type_to_str(int type);
|
||||
/* -------------------- */
|
||||
#include "internal/cli/messages.h"
|
||||
|
||||
int
|
||||
cli_handle_help(__unused const char *arg, __unused void *config_void)
|
||||
{
|
||||
printf("ft_ping - Send ICMP ECHO_REQUEST to network hosts\n");
|
||||
printf("Usage: ft_ping [options] <destination>\n\n");
|
||||
cli_print_options(g_options, PING_OPT_LEN, option_arg_type_to_str);
|
||||
print_help();
|
||||
|
||||
return CLI_EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
option_arg_type_to_str(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OPT_ARG_NONE: return "";
|
||||
case OPT_ARG_INT: return "<NUM>";
|
||||
case OPT_ARG_UINT: return "<NUM>";
|
||||
case OPT_ARG_SECONDS: return "<SEC>";
|
||||
case OPT_ARG_BYTES: return "<SIZE>";
|
||||
case OPT_ARG_TTL: return "<TTL>";
|
||||
case OPT_ARG_PATTERN: return "<HEX>";
|
||||
case OPT_ARG_STRING: return "<STR>";
|
||||
default: return "<ARG>";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
#include "ping/cli.h"
|
||||
#include "internal/cli/parse_utils.h"
|
||||
|
||||
int
|
||||
cli_handle_linger(const char *arg, void *config_void)
|
||||
{
|
||||
struct ping_config *config = (struct ping_config *)config_void;
|
||||
float linger;
|
||||
|
||||
if (0 != cli_parse_ufloat(arg, &linger))
|
||||
return CLI_ERROR;
|
||||
config->linger = linger;
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#include "ping/cli.h"
|
||||
#include "internal/cli/parse_utils.h"
|
||||
|
||||
int
|
||||
cli_handle_pattern(const char *arg, void *config_void)
|
||||
{
|
||||
struct ping_config *config = (struct ping_config *)config_void;
|
||||
size_t pattern_len;
|
||||
|
||||
if (0 != cli_parse_hex(arg, config->pattern, 16, &pattern_len))
|
||||
return CLI_ERROR;
|
||||
config->pattern_len = (uint8_t)pattern_len;
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#include "ping/cli.h"
|
||||
#include "internal/cli/parse_utils.h"
|
||||
|
||||
int
|
||||
cli_handle_preload(const char *arg, void *config_void)
|
||||
{
|
||||
struct ping_config *config = (struct ping_config *)config_void;
|
||||
uint64_t preload;
|
||||
|
||||
if (0 != cli_parse_uint64(arg, &preload))
|
||||
return CLI_ERROR;
|
||||
config->preload = preload;
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
|
@ -5,10 +5,11 @@ int
|
|||
cli_handle_timeout(const char *arg, void *config_void)
|
||||
{
|
||||
struct ping_config *config = (struct ping_config *)config_void;
|
||||
float timeout;
|
||||
float TO;
|
||||
|
||||
if (0 != cli_parse_ufloat(arg, &timeout))
|
||||
if (0 != cli_parse_ufloat(arg, &TO))
|
||||
return CLI_ERROR;
|
||||
config->timeout = timeout;
|
||||
|
||||
config->timeout = TO;
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
#include "ping/cli.h"
|
||||
#include "internal/cli/parse_utils.h"
|
||||
|
||||
int
|
||||
cli_handle_tos(const char *arg, void *config_void)
|
||||
{
|
||||
struct ping_config *config = (struct ping_config *)config_void;
|
||||
uint64_t tos;
|
||||
|
||||
if (0 != cli_parse_uint64(arg, &tos) || tos > 255)
|
||||
return CLI_ERROR;
|
||||
config->tos = (uint8_t)tos;
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
45
src/ping/cli/messages/help.c
Normal file
45
src/ping/cli/messages/help.c
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "internal/ping/cli_handlers.h"
|
||||
#include "internal/cli/options.h"
|
||||
|
||||
/* Forward declarations */
|
||||
static inline const char * option_arg_type_to_str(int type);
|
||||
/* -------------------- */
|
||||
|
||||
void
|
||||
print_help(void)
|
||||
{
|
||||
printf("ft_ping - Send ICMP ECHO_REQUEST to network hosts\n");
|
||||
printf("Usage: ft_ping [options] <destination>\n\n");
|
||||
printf("Options:\n");
|
||||
|
||||
for (size_t i = 0; i < PING_OPT_LEN; ++i)
|
||||
{
|
||||
const struct option_descriptor *opt = &g_options[i];
|
||||
const char *argstr = option_arg_type_to_str(opt->arg_type);
|
||||
|
||||
printf(" -%c, --%-10s %-8s %s\n",
|
||||
opt->short_opt,
|
||||
opt->long_opt,
|
||||
argstr[0] ? argstr : "",
|
||||
opt->description
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
option_arg_type_to_str(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OPT_ARG_NONE: return "";
|
||||
case OPT_ARG_INT: return "<NUM>";
|
||||
case OPT_ARG_UINT: return "<NUM>";
|
||||
case OPT_ARG_SECONDS: return "<SEC>";
|
||||
case OPT_ARG_BYTES: return "<SIZE>";
|
||||
case OPT_ARG_TTL: return "<TTL>";
|
||||
case OPT_ARG_STRING: return "<STR>";
|
||||
default: return "<ARG>";
|
||||
}
|
||||
}
|
||||
|
|
@ -31,9 +31,8 @@ init_config(struct ping_config *config)
|
|||
{
|
||||
memset(config, 0, sizeof(struct ping_config));
|
||||
config->count = DEFAULT_COUNT;
|
||||
config->preload = DEFAULT_PRELOAD;
|
||||
config->interval = DEFAULT_INTERVAL;
|
||||
config->ttl = DEFAULT_TTL;
|
||||
config->packet_size = DEFAULT_PACKET_SIZE;
|
||||
config->linger = DEFAULT_LINGER;
|
||||
config->timeout = DEFAULT_TIMEOUT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,17 @@
|
|||
#include "icmp_types.h"
|
||||
#include "internal/ping/handlers.h"
|
||||
#include "ping/ft_ping_flags.h"
|
||||
#include "internal/ping/output.h"
|
||||
|
||||
/* Forward declarations */
|
||||
static int extract_our_echo(const icmp_reply_t *reply, uint16_t our_id,
|
||||
struct in_addr dest, uint16_t *seq_out);
|
||||
static void handle_echo_reply(struct ping_state *state,
|
||||
const icmp_reply_t *reply);
|
||||
static int extract_our_error(const icmp_reply_t *reply, uint16_t our_id,
|
||||
struct in_addr dest, icmp_offending_packet_t *out, uint16_t *seq_out);
|
||||
static void handle_icmp_error(struct ping_state *state,
|
||||
const icmp_reply_t *reply);
|
||||
/* -------------------- */
|
||||
|
||||
void
|
||||
ping_callback(const icmp_reply_t *reply, void *userdata)
|
||||
|
|
@ -8,8 +20,69 @@ ping_callback(const icmp_reply_t *reply, void *userdata)
|
|||
|
||||
state = (struct ping_state *)userdata;
|
||||
if (ICMP_TYPE_ECHO_REPLY == reply->type)
|
||||
ping_handle_echo_reply(state, reply);
|
||||
handle_echo_reply(state, reply);
|
||||
else if (ICMP_TYPE_TIME_EXCEEDED == reply->type
|
||||
|| ICMP_TYPE_DEST_UNREACHABLE == reply->type)
|
||||
ping_handle_icmp_error(state, reply);
|
||||
handle_icmp_error(state, reply);
|
||||
}
|
||||
|
||||
static int
|
||||
extract_our_echo(const icmp_reply_t *reply, uint16_t our_id,
|
||||
struct in_addr dest, 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 || reply->from.s_addr != dest.s_addr)
|
||||
return 0;
|
||||
*seq_out = seq;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_echo_reply(struct ping_state *state, const icmp_reply_t *reply)
|
||||
{
|
||||
uint16_t seq;
|
||||
int64_t rtt;
|
||||
|
||||
if (0 == extract_our_echo(reply, state->id, state->dest, &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,
|
||||
struct in_addr dest, icmp_offending_packet_t *out, uint16_t *seq_out)
|
||||
{
|
||||
if ((0 > icmp_error_extract_offending(reply, out))
|
||||
|| ICMP_TYPE_ECHO_REQUEST != out->icmp_type
|
||||
|| our_id != out->rest.echo.id || out->dst.s_addr != dest.s_addr)
|
||||
return 0;
|
||||
*seq_out = out->rest.echo.seq;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_icmp_error(struct ping_state *state, const icmp_reply_t *reply)
|
||||
{
|
||||
icmp_offending_packet_t offending;
|
||||
uint16_t seq;
|
||||
|
||||
if (0 == extract_our_error(reply, state->id, state->dest, &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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
#include "icmp.h"
|
||||
#include "icmp_types.h"
|
||||
#include "ping/ft_ping_flags.h"
|
||||
#include "internal/ping/handlers.h"
|
||||
#include "internal/ping/output.h"
|
||||
|
||||
/* Forward declarations */
|
||||
static int extract_our_error(const icmp_reply_t *reply, uint16_t our_id,
|
||||
struct in_addr dest, icmp_offending_packet_t *out, uint16_t *seq_out);
|
||||
/* -------------------- */
|
||||
|
||||
void
|
||||
ping_handle_icmp_error(struct ping_state *state, const icmp_reply_t *reply)
|
||||
{
|
||||
icmp_offending_packet_t offending;
|
||||
uint16_t seq;
|
||||
|
||||
if (0 == extract_our_error(reply, state->id, state->dest, &offending, &seq))
|
||||
return;
|
||||
if (0 == ping_tracker_record_recv(state->tracker, seq))
|
||||
return;
|
||||
state->nb_errors++;
|
||||
if (!HAS_FLAG(state->config->flags, FLAG_QUIET))
|
||||
ping_output_error(reply, &offending, seq, state->config);
|
||||
}
|
||||
|
||||
static int
|
||||
extract_our_error(const icmp_reply_t *reply, uint16_t our_id,
|
||||
struct in_addr dest, icmp_offending_packet_t *out, uint16_t *seq_out)
|
||||
{
|
||||
if ((0 > icmp_error_extract_offending(reply, out))
|
||||
|| ICMP_TYPE_ECHO_REQUEST != out->icmp_type
|
||||
|| our_id != out->rest.echo.id || out->dst.s_addr != dest.s_addr)
|
||||
return 0;
|
||||
*seq_out = out->rest.echo.seq;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -7,13 +7,12 @@
|
|||
#include "internal/ping/scheduler.h"
|
||||
|
||||
/* Forward declarations */
|
||||
static int timeout_expired(const struct ping_state *state);
|
||||
static int linger_expired(const struct ping_state *state);
|
||||
static int should_stop(const struct ping_state *state);
|
||||
static inline int can_send_more(const struct ping_state *state);
|
||||
static void try_recv(struct ping_state *state);
|
||||
static void handle_send_trigger(struct ping_state *state, size_t
|
||||
payload_len);
|
||||
static int deadline_expired(const struct ping_state *state);
|
||||
static int linger_expired(const struct ping_state *state);
|
||||
static int should_stop(const struct ping_state *state);
|
||||
static int can_send_more(const struct ping_state *state);
|
||||
static void try_recv(struct ping_state *state);
|
||||
static void handle_send_trigger(struct ping_state *state, size_t payload_len);
|
||||
/* -------------------- */
|
||||
|
||||
void
|
||||
|
|
@ -29,18 +28,18 @@ ping_loop(struct ping_state *state, size_t payload_len)
|
|||
}
|
||||
|
||||
static int
|
||||
timeout_expired(const struct ping_state *state)
|
||||
deadline_expired(const struct ping_state *state)
|
||||
{
|
||||
struct timespec now;
|
||||
double elapsed;
|
||||
|
||||
if (0.0 == state->config->timeout)
|
||||
if (0.0 == state->config->deadline)
|
||||
return 0;
|
||||
if (0 != icmp_get_time(&now))
|
||||
return 0;
|
||||
elapsed = (double)(now.tv_sec - state->start_time.tv_sec)
|
||||
+ (double)(now.tv_nsec - state->start_time.tv_nsec) / 1e9;
|
||||
return elapsed >= state->config->timeout;
|
||||
return elapsed >= state->config->deadline;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -49,12 +48,13 @@ linger_expired(const struct ping_state *state)
|
|||
struct timespec now;
|
||||
double elapsed;
|
||||
|
||||
if ((0 == state->linger_start.tv_sec && 0 == state->linger_start.tv_nsec)
|
||||
|| 0!= icmp_get_time(&now))
|
||||
if (0 == state->linger_start.tv_sec && 0 == state->linger_start.tv_nsec)
|
||||
return 0;
|
||||
if (0 != icmp_get_time(&now))
|
||||
return 0;
|
||||
elapsed = (double)(now.tv_sec - state->linger_start.tv_sec)
|
||||
+ (double)(now.tv_nsec - state->linger_start.tv_nsec) / 1e9;
|
||||
return elapsed >= state->config->linger;
|
||||
return elapsed >= state->config->timeout;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -62,9 +62,11 @@ should_stop(const struct ping_state *state)
|
|||
{
|
||||
size_t count;
|
||||
|
||||
if (state->stop_flag
|
||||
|| timeout_expired(state)
|
||||
|| linger_expired(state))
|
||||
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)
|
||||
|
|
@ -72,7 +74,7 @@ should_stop(const struct ping_state *state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
static int
|
||||
can_send_more(const struct ping_state *state)
|
||||
{
|
||||
size_t count;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "version_gen.h"
|
||||
#include "ping/ft_ping_const.h"
|
||||
#include "ping/ft_ping_flags.h"
|
||||
#include "internal/ping/output.h"
|
||||
#include "internal/ping/scheduler.h"
|
||||
|
|
@ -11,67 +9,47 @@
|
|||
#include "internal/ping/loop.h"
|
||||
|
||||
/* Forward declarations */
|
||||
static icmp_handle_t *ping_create_handle(const struct ping_config *config);
|
||||
static int ping_one(const struct ping_config *config, struct destinations
|
||||
*dest, icmp_handle_t *handle);
|
||||
static int ping_one(const struct ping_config *config,
|
||||
struct destinations *dest, icmp_handle_t *handle);
|
||||
static void ping_init_state(struct ping_state *state, struct ping_stats *stats,
|
||||
struct ping_tracker *tracker, const struct ping_config *config,
|
||||
struct in_addr dest, icmp_handle_t *handle);
|
||||
static int ping_preload(struct ping_state *state, size_t payload_len);
|
||||
/* -------------------- */
|
||||
|
||||
int
|
||||
ping_run(const struct ping_config *config)
|
||||
{
|
||||
icmp_handle_t *handle;
|
||||
int ret = 0;
|
||||
size_t i = 0;
|
||||
int ret = 0 ;
|
||||
size_t i = 0 ;
|
||||
|
||||
if (0 == config->nb_destinations)
|
||||
return 1;
|
||||
handle = ping_create_handle(config);
|
||||
handle = icmp_create();
|
||||
if (NULL == handle)
|
||||
{
|
||||
dprintf(STDERR_FILENO, "%s: requires CAP_NET_RAW or root privileges\n",
|
||||
g_prog_name);
|
||||
return 1;
|
||||
}
|
||||
if (HAS_FLAG(config->flags, FLAG_DONT_FRAGMENT)
|
||||
&& 0 != icmp_set_dont_fragment(handle))
|
||||
{
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (i < config->nb_destinations)
|
||||
{
|
||||
if (0 != ping_one(config, &config->destinations[i], handle))
|
||||
ret = 1;
|
||||
i++;
|
||||
}
|
||||
cleanup:
|
||||
icmp_destroy(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static icmp_handle_t *
|
||||
ping_create_handle(const struct ping_config *config)
|
||||
{
|
||||
icmp_handle_t *handle;
|
||||
|
||||
handle = icmp_create();
|
||||
if (NULL == handle)
|
||||
{
|
||||
dprintf(STDERR_FILENO, "%s: requires CAP_NET_RAW or root privileges\n",
|
||||
g_prog_name);
|
||||
goto cleanup;
|
||||
}
|
||||
if (HAS_FLAG(config->flags, FLAG_DONT_FRAGMENT)
|
||||
&& 0 != icmp_set_dont_fragment(handle))
|
||||
{
|
||||
dprintf(STDERR_FILENO, "%s: %s\n", g_prog_name, icmp_strerror(handle));
|
||||
goto cleanup;
|
||||
}
|
||||
if (0 != config->tos && 0 != icmp_set_tos(handle, config->tos))
|
||||
{
|
||||
dprintf(STDERR_FILENO, "%s: %s\n", g_prog_name, icmp_strerror(handle));
|
||||
goto cleanup;
|
||||
}
|
||||
return handle;
|
||||
|
||||
cleanup:
|
||||
icmp_destroy(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
ping_one(const struct ping_config *config, struct destinations *dest,
|
||||
icmp_handle_t *handle)
|
||||
|
|
@ -84,14 +62,9 @@ ping_one(const struct ping_config *config, struct destinations *dest,
|
|||
ping_init_state(&state, &stats, &tracker, config, dest->ip, handle);
|
||||
payload_len = config->packet_size;
|
||||
if (0 != ping_scheduler_init(&state))
|
||||
{
|
||||
dprintf(STDERR_FILENO, "%s: sigaction: %s\n",
|
||||
g_prog_name, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
ping_output_start(config, dest, payload_len);
|
||||
if (0 != ping_preload(&state, payload_len))
|
||||
return 1;
|
||||
do_send(&state, payload_len);
|
||||
ping_loop(&state, payload_len);
|
||||
ping_output_summary(&state, dest);
|
||||
return tracker.nb_recv <= state.nb_errors;
|
||||
|
|
@ -111,27 +84,5 @@ ping_init_state(struct ping_state *state, struct ping_stats *stats,
|
|||
state->tracker = tracker;
|
||||
state->stats = stats;
|
||||
state->handle = handle;
|
||||
state->ts_in_payload = (config->packet_size >= PING_TIMESTAMP_SIZE);
|
||||
icmp_get_time(&state->start_time);
|
||||
}
|
||||
|
||||
static int
|
||||
ping_preload(struct ping_state *state, size_t payload_len)
|
||||
{
|
||||
const struct ping_config *config = state->config;
|
||||
uint64_t i = 0;
|
||||
|
||||
while (i < config->preload && (0 == config->count ||
|
||||
state->tracker->nb_sent < config->count))
|
||||
{
|
||||
do_send(state, payload_len);
|
||||
i++;
|
||||
}
|
||||
if (0 == config->preload && 0 != ping_scheduler_arm(config))
|
||||
{
|
||||
dprintf(STDERR_FILENO, "%s: setitimer: %s\n",
|
||||
g_prog_name, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "icmp.h"
|
||||
#include "ping/ft_ping_const.h"
|
||||
#include "ping/ft_ping_flags.h"
|
||||
#include "internal/ping/handlers.h"
|
||||
#include "internal/ping/output.h"
|
||||
|
||||
/* Forward declarations */
|
||||
static int extract_our_echo(const icmp_reply_t *reply, uint16_t our_id,
|
||||
struct in_addr dest, uint16_t *seq_out);
|
||||
/* -------------------- */
|
||||
|
||||
void
|
||||
ping_handle_echo_reply(struct ping_state *state, const icmp_reply_t *reply)
|
||||
{
|
||||
uint16_t seq;
|
||||
int is_new;
|
||||
int64_t rtt_ns;
|
||||
struct timespec send_ts;
|
||||
|
||||
if (0 == extract_our_echo(reply, state->id, state->dest, &seq))
|
||||
return;
|
||||
is_new = ping_tracker_record_recv(state->tracker, seq);
|
||||
rtt_ns = -1;
|
||||
if (state->ts_in_payload && reply->payload_len >= PING_TIMESTAMP_SIZE)
|
||||
{
|
||||
memcpy(&send_ts, reply->payload, sizeof(send_ts));
|
||||
rtt_ns = icmp_time_diff_ns(&send_ts, &reply->timestamp);
|
||||
if (is_new)
|
||||
ping_stats_update(state->stats, rtt_ns);
|
||||
}
|
||||
if (HAS_FLAG(state->config->flags, FLAG_FLOOD))
|
||||
{
|
||||
if (is_new)
|
||||
ping_output_flood_erase();
|
||||
return;
|
||||
}
|
||||
ping_output_packet(reply, seq, rtt_ns, state->config->packet_size,
|
||||
state->config, !is_new);
|
||||
}
|
||||
|
||||
static int
|
||||
extract_our_echo(const icmp_reply_t *reply, uint16_t our_id,
|
||||
struct in_addr dest, uint16_t *seq_out)
|
||||
{
|
||||
uint16_t id;
|
||||
uint16_t seq;
|
||||
|
||||
if ((0 > icmp_reply_id_seq(reply, &id, &seq))
|
||||
|| ((our_id != id || reply->from.s_addr != dest.s_addr)))
|
||||
return 0;
|
||||
*seq_out = seq;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -12,10 +12,9 @@
|
|||
#include "ping/ft_ping_flags.h"
|
||||
|
||||
/* Forward declarations */
|
||||
static inline void fill_payload(uint8_t *payload, size_t len,
|
||||
const struct ping_config *config, int ts_in_payload);
|
||||
static inline void fill_payload(uint8_t *payload, size_t payload_len);
|
||||
static int ping_send_one(struct ping_state *state, uint16_t seq,
|
||||
uint8_t *payload, size_t payload_len, struct timespec *ts);
|
||||
const uint8_t *payload, size_t payload_len, struct timespec *ts);
|
||||
/* -------------------- */
|
||||
|
||||
void
|
||||
|
|
@ -26,14 +25,14 @@ do_send(struct ping_state *state, size_t payload_len)
|
|||
int ret;
|
||||
|
||||
state->send_flag = 0;
|
||||
fill_payload(payload, payload_len, state->config, state->ts_in_payload);
|
||||
fill_payload(payload, payload_len);
|
||||
ret = ping_send_one(state, state->seq, payload, payload_len, &ts);
|
||||
if (-1 == ret)
|
||||
dprintf(STDERR_FILENO, "%s: %s\n",
|
||||
g_prog_name, icmp_strerror(state->handle));
|
||||
else if (0 == ret)
|
||||
{
|
||||
ping_tracker_record_send(state->tracker, state->seq);
|
||||
ping_tracker_record_send(state->tracker, state->seq, &ts);
|
||||
state->seq++;
|
||||
}
|
||||
|
||||
|
|
@ -49,14 +48,12 @@ do_send(struct ping_state *state, size_t payload_len)
|
|||
|
||||
static int
|
||||
ping_send_one(struct ping_state *state, uint16_t seq,
|
||||
uint8_t *payload, size_t payload_len, struct timespec *ts)
|
||||
const uint8_t *payload, size_t payload_len, struct timespec *ts)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (0 != icmp_get_time(ts))
|
||||
return -1;
|
||||
if (state->ts_in_payload)
|
||||
memcpy(payload, ts, sizeof(*ts));
|
||||
ret = icmp_send_echo(state->handle,
|
||||
state->dest,
|
||||
state->id,
|
||||
|
|
@ -71,21 +68,8 @@ ping_send_one(struct ping_state *state, uint16_t seq,
|
|||
}
|
||||
|
||||
static inline void
|
||||
fill_payload(uint8_t *payload, size_t len, const struct ping_config *config,
|
||||
int ts_in_payload)
|
||||
fill_payload(uint8_t *payload, size_t payload_len)
|
||||
{
|
||||
size_t offset;
|
||||
size_t i;
|
||||
|
||||
offset = ts_in_payload ? PING_TIMESTAMP_SIZE : 0;
|
||||
if (0 == config->pattern_len)
|
||||
{
|
||||
for (i = offset; i < len; ++i)
|
||||
payload[i] = (uint8_t)((i - offset) & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = offset; i < len; ++i)
|
||||
payload[i] = config->pattern[(i - offset) % config->pattern_len];
|
||||
}
|
||||
for (size_t i = 0; i < payload_len; ++i)
|
||||
payload[i] = (uint8_t)('a' + (i % 26));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,27 +6,17 @@
|
|||
|
||||
void
|
||||
ping_output_packet(const icmp_reply_t *reply, uint16_t seq,
|
||||
int64_t rtt_ns, size_t payload_bytes, const struct ping_config *config,
|
||||
int is_dup)
|
||||
int64_t rtt_ns, size_t payload_bytes, const struct ping_config *config)
|
||||
{
|
||||
char from_str[INET_ADDRSTRLEN];
|
||||
|
||||
if (HAS_FLAG(config->flags, FLAG_QUIET | FLAG_FLOOD))
|
||||
return;
|
||||
inet_ntop(AF_INET, &reply->from, from_str, sizeof(from_str));
|
||||
if (0 <= rtt_ns)
|
||||
printf("%zu bytes from %s: icmp_seq=%u ttl=%u time=%.3f ms%s\n",
|
||||
payload_bytes + 8,
|
||||
from_str,
|
||||
(unsigned int)seq,
|
||||
(unsigned int)reply->ttl,
|
||||
(double)rtt_ns / 1e6,
|
||||
is_dup ? " (DUP!)" : "");
|
||||
else
|
||||
printf("%zu bytes from %s: icmp_seq=%u ttl=%u%s\n",
|
||||
payload_bytes + 8,
|
||||
from_str,
|
||||
(unsigned int)seq,
|
||||
(unsigned int)reply->ttl,
|
||||
is_dup ? " (DUP!)" : "");
|
||||
printf("%zu bytes from %s: icmp_seq=%u ttl=%u time=%.3f ms\n",
|
||||
payload_bytes + 8,
|
||||
from_str,
|
||||
(unsigned int)seq,
|
||||
(unsigned int)reply->ttl,
|
||||
(double)rtt_ns / 1e6);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ ping_output_summary(const struct ping_state *state,
|
|||
ok_recv = state->tracker->nb_recv - errors;
|
||||
printf("--- %s ping statistics ---\n", dest->dom);
|
||||
print_loss_line(sent, ok_recv, errors);
|
||||
if (0 < state->stats->count)
|
||||
if (0 < ok_recv)
|
||||
print_rtt_line(state->stats);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@ void
|
|||
ping_scheduler_select_tv(const struct ping_config *config, struct timeval *tv)
|
||||
{
|
||||
tv->tv_usec = 0;
|
||||
tv->tv_sec = (long)config->linger * !HAS_FLAG(config->flags, FLAG_FLOOD);
|
||||
tv->tv_sec = (long)config->timeout * !HAS_FLAG(config->flags, FLAG_FLOOD);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
#include "icmp.h"
|
||||
#include "internal/ping/tracker.h"
|
||||
|
||||
int
|
||||
ping_tracker_record_recv(struct ping_tracker *t, uint16_t seq)
|
||||
int64_t
|
||||
ping_tracker_record_recv(struct ping_tracker *t, uint16_t seq,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
uint8_t *byte;
|
||||
uint8_t bit;
|
||||
struct ping_tracker_slot *slot;
|
||||
|
||||
byte = &t->rcvd[seq >> 3];
|
||||
bit = (uint8_t)(1u << (seq & 7u)); /* 7 == 0b111 */
|
||||
if (*byte & bit)
|
||||
{
|
||||
t->nb_dup++;
|
||||
return (0);
|
||||
}
|
||||
*byte |= bit;
|
||||
slot = &t->slots[seq % PING_TRACKER_SLOTS];
|
||||
if ((slot->flags & (TRACKER_SLOT_USED | TRACKER_SLOT_ACKED))
|
||||
!= TRACKER_SLOT_USED)
|
||||
return (-1);
|
||||
slot->flags |= TRACKER_SLOT_ACKED;
|
||||
t->nb_recv++;
|
||||
return (1);
|
||||
return (icmp_time_diff_ns(&slot->ts, ts));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
#include "compiler.h"
|
||||
#include "internal/ping/tracker.h"
|
||||
|
||||
void
|
||||
ping_tracker_record_send(struct ping_tracker *t, uint16_t seq __unused)
|
||||
ping_tracker_record_send(struct ping_tracker *t, uint16_t seq,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
struct ping_tracker_slot *slot;
|
||||
|
||||
slot = &t->slots[seq % PING_TRACKER_SLOTS];
|
||||
slot->ts = *ts;
|
||||
slot->flags = TRACKER_SLOT_USED;
|
||||
t->nb_sent++;
|
||||
}
|
||||
|
|
|
|||
54
src/traceroute/Makefile.am
Normal file
54
src/traceroute/Makefile.am
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
bin_PROGRAMS = ft_traceroute
|
||||
noinst_LTLIBRARIES = libtraceroute_core.la
|
||||
|
||||
TRACEROUTE_VERSION = 0.0.1
|
||||
VERSION_HEADER = $(top_srcdir)/includes/version_gen.h
|
||||
|
||||
BUILT_SOURCES = $(VERSION_HEADER)
|
||||
|
||||
libtraceroute_core_la_SOURCES = \
|
||||
cli/parse.c \
|
||||
cli/config_free.c \
|
||||
cli/handlers/option_map.c \
|
||||
cli/handlers/handle_help.c \
|
||||
cli/handlers/handle_version.c \
|
||||
cli/handlers/handle_verbose.c \
|
||||
cli/handlers/handle_max_ttl.c \
|
||||
cli/handlers/handle_waittime.c \
|
||||
cli/messages/help.c \
|
||||
cli/messages/version.c \
|
||||
cli/messages/error.c \
|
||||
cli/parse_utils/parse_destination.c \
|
||||
core/traceroute.c
|
||||
|
||||
BASE_CFLAGS = -std=c99 $(STRICT_CFLAGS)
|
||||
|
||||
if ENABLE_DEBUG
|
||||
EXTRA_CFLAGS = -g -O0
|
||||
else
|
||||
EXTRA_CFLAGS =
|
||||
endif
|
||||
|
||||
if ENABLE_SANITIZERS
|
||||
SANITIZER_FLAGS = -fsanitize=address,undefined
|
||||
else
|
||||
SANITIZER_FLAGS =
|
||||
endif
|
||||
|
||||
TRACEROUTE_CPPFLAGS = \
|
||||
-I $(top_srcdir)/includes \
|
||||
-I $(top_srcdir)/libcli/include \
|
||||
-D_GNU_SOURCE
|
||||
|
||||
TRACEROUTE_CFLAGS = $(BASE_CFLAGS) $(EXTRA_CFLAGS) $(SANITIZER_FLAGS)
|
||||
|
||||
libtraceroute_core_la_CPPFLAGS = $(TRACEROUTE_CPPFLAGS)
|
||||
libtraceroute_core_la_CFLAGS = $(TRACEROUTE_CFLAGS)
|
||||
|
||||
ft_traceroute_SOURCES = main.c
|
||||
ft_traceroute_CPPFLAGS = $(TRACEROUTE_CPPFLAGS)
|
||||
ft_traceroute_CFLAGS = $(TRACEROUTE_CFLAGS)
|
||||
ft_traceroute_LDFLAGS = $(SANITIZER_FLAGS)
|
||||
ft_traceroute_LDADD = \
|
||||
libtraceroute_core.la \
|
||||
$(top_builddir)/libcli/src/libcli.la
|
||||
7
src/traceroute/cli/config_free.c
Normal file
7
src/traceroute/cli/config_free.c
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#include "traceroute/cli.h"
|
||||
|
||||
void
|
||||
cli_config_free(struct traceroute_config *config)
|
||||
{
|
||||
config->destination = NULL;
|
||||
}
|
||||
14
src/traceroute/cli/handlers/handle_help.c
Normal file
14
src/traceroute/cli/handlers/handle_help.c
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include "compiler.h"
|
||||
#include "traceroute/cli.h"
|
||||
#include "internal/traceroute/cli_handlers.h"
|
||||
|
||||
/* Forward declaration */
|
||||
void print_help(void);
|
||||
/* ------------------- */
|
||||
|
||||
int
|
||||
cli_handle_help(__unused const char *arg, __unused void *config)
|
||||
{
|
||||
print_help();
|
||||
return CLI_EXIT_SUCCESS;
|
||||
}
|
||||
15
src/traceroute/cli/handlers/handle_max_ttl.c
Normal file
15
src/traceroute/cli/handlers/handle_max_ttl.c
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#include "traceroute/cli.h"
|
||||
#include "traceroute/ft_traceroute_const.h"
|
||||
#include "internal/cli/parse_utils.h"
|
||||
|
||||
int
|
||||
cli_handle_max_ttl(const char *arg, void *config_void)
|
||||
{
|
||||
struct traceroute_config *config = (struct traceroute_config *)config_void;
|
||||
uint64_t val;
|
||||
|
||||
if (0 != cli_parse_uint64(arg, &val) || 0 == val || val > MAX_TRACEROUTE_TTL)
|
||||
return CLI_ERROR;
|
||||
config->max_ttl = (uint8_t)val;
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
11
src/traceroute/cli/handlers/handle_verbose.c
Normal file
11
src/traceroute/cli/handlers/handle_verbose.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include "compiler.h"
|
||||
#include "traceroute/cli.h"
|
||||
#include "traceroute/ft_traceroute_flags.h"
|
||||
|
||||
int
|
||||
cli_handle_verbose(__unused const char *arg, void *config_void)
|
||||
{
|
||||
struct traceroute_config *config = (struct traceroute_config *)config_void;
|
||||
SET_FLAG(config->flags, FLAG_TR_VERBOSE);
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
13
src/traceroute/cli/handlers/handle_version.c
Normal file
13
src/traceroute/cli/handlers/handle_version.c
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include "compiler.h"
|
||||
#include "traceroute/cli.h"
|
||||
|
||||
/* Forward declaration */
|
||||
void print_version(void);
|
||||
/* ------------------- */
|
||||
|
||||
int
|
||||
cli_handle_version(__unused const char *arg, __unused void *config)
|
||||
{
|
||||
print_version();
|
||||
return CLI_EXIT_SUCCESS;
|
||||
}
|
||||
14
src/traceroute/cli/handlers/handle_waittime.c
Normal file
14
src/traceroute/cli/handlers/handle_waittime.c
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include "traceroute/cli.h"
|
||||
#include "internal/cli/parse_utils.h"
|
||||
|
||||
int
|
||||
cli_handle_waittime(const char *arg, void *config_void)
|
||||
{
|
||||
struct traceroute_config *config = (struct traceroute_config *)config_void;
|
||||
float val;
|
||||
|
||||
if (0 != cli_parse_ufloat(arg, &val) || val <= 0.0f)
|
||||
return CLI_ERROR;
|
||||
config->waittime = (double)val;
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
13
src/traceroute/cli/handlers/option_map.c
Normal file
13
src/traceroute/cli/handlers/option_map.c
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include "internal/traceroute/cli_handlers.h"
|
||||
#include "internal/traceroute/options.h"
|
||||
|
||||
#undef X
|
||||
#define X(short_opt, long_opt, has_arg, handler, arg_type, desc) \
|
||||
{ short_opt, long_opt, has_arg, handler, arg_type, desc },
|
||||
|
||||
const struct option_descriptor g_options[] = {
|
||||
TRACEROUTE_OPTIONS_LIST
|
||||
{0, NULL, 0, NULL, OPT_ARG_NONE, NULL}
|
||||
};
|
||||
|
||||
#undef X
|
||||
32
src/traceroute/cli/messages/error.c
Normal file
32
src/traceroute/cli/messages/error.c
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "traceroute/cli.h"
|
||||
#include "version_gen.h"
|
||||
|
||||
/* Forward declaration */
|
||||
static inline void print_suggest_help(void);
|
||||
/* ------------------- */
|
||||
|
||||
enum cli_code
|
||||
error_missing_dest(void)
|
||||
{
|
||||
dprintf(STDERR_FILENO, "%s: usage error: Destination address required\n",
|
||||
g_prog_name);
|
||||
print_suggest_help();
|
||||
return CLI_ERROR;
|
||||
}
|
||||
|
||||
enum cli_code
|
||||
error_invalid_dest(void)
|
||||
{
|
||||
dprintf(STDERR_FILENO, "%s: unknown host\n", g_prog_name);
|
||||
return CLI_ERROR;
|
||||
}
|
||||
|
||||
static inline void
|
||||
print_suggest_help(void)
|
||||
{
|
||||
dprintf(STDERR_FILENO, "Try '%s --help' for more information.\n",
|
||||
g_prog_name);
|
||||
}
|
||||
40
src/traceroute/cli/messages/help.c
Normal file
40
src/traceroute/cli/messages/help.c
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "internal/traceroute/cli_handlers.h"
|
||||
#include "internal/traceroute/options.h"
|
||||
|
||||
/* Forward declaration */
|
||||
static inline const char *option_arg_type_to_str(int type);
|
||||
/* ------------------- */
|
||||
|
||||
void
|
||||
print_help(void)
|
||||
{
|
||||
printf("ft_traceroute - Trace the route to a network host\n");
|
||||
printf("Usage: ft_traceroute [options] <destination>\n\n");
|
||||
printf("Options:\n");
|
||||
|
||||
for (size_t i = 0; i < TR_OPT_LEN; ++i)
|
||||
{
|
||||
const struct option_descriptor *opt = &g_options[i];
|
||||
const char *argstr = option_arg_type_to_str(opt->arg_type);
|
||||
|
||||
printf(" -%c, --%-10s %-8s %s\n",
|
||||
opt->short_opt,
|
||||
opt->long_opt,
|
||||
argstr[0] ? argstr : "",
|
||||
opt->description);
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
option_arg_type_to_str(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OPT_ARG_NONE: return "";
|
||||
case OPT_TR_ARG_HOPS: return "<HOPS>";
|
||||
case OPT_TR_ARG_SECONDS: return "<SEC>";
|
||||
default: return "<ARG>";
|
||||
}
|
||||
}
|
||||
19
src/traceroute/cli/messages/version.c
Normal file
19
src/traceroute/cli/messages/version.c
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "version_gen.h"
|
||||
|
||||
void
|
||||
print_version(void)
|
||||
{
|
||||
printf("%s version %s\n", g_prog_name, PING_VERSION);
|
||||
printf("Copyright (C) 2026 lohhiicccc\n");
|
||||
printf("License GPLv3+:");
|
||||
printf("GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\n");
|
||||
printf("This is free software: ");
|
||||
printf("you are free to change and redistribute it.\n");
|
||||
printf("There is NO WARRANTY, to the extent permitted by law.\n");
|
||||
printf("\n");
|
||||
#if PING_HAS_GIT_COMMIT
|
||||
printf("Build: %s (commit %s)\n", PING_BUILD_DATE, PING_GIT_COMMIT);
|
||||
#endif
|
||||
}
|
||||
39
src/traceroute/cli/parse.c
Normal file
39
src/traceroute/cli/parse.c
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "traceroute/cli.h"
|
||||
#include "traceroute/ft_traceroute_const.h"
|
||||
#include "internal/traceroute/cli_handlers.h"
|
||||
#include "internal/traceroute/parse_utils.h"
|
||||
#include "internal/traceroute/options.h"
|
||||
#include "internal/cli/messages.h"
|
||||
|
||||
/* Forward declaration */
|
||||
static void init_config(struct traceroute_config *config);
|
||||
/* ------------------- */
|
||||
|
||||
enum cli_code
|
||||
cli_parse_arguments(int argc, char **argv, struct traceroute_config *config)
|
||||
{
|
||||
char opt_str[TR_OPTSTR_LEN];
|
||||
struct option long_opts[TR_OPT_LEN + 1];
|
||||
enum cli_code ret;
|
||||
|
||||
init_config(config);
|
||||
ret = cli_parse(argc, argv, config, g_options, TR_OPT_LEN,
|
||||
opt_str, long_opts);
|
||||
if (CLI_SUCCESS != ret)
|
||||
return ret;
|
||||
if (optind >= argc)
|
||||
return error_missing_dest();
|
||||
return cli_parse_destination(argv[optind], config);
|
||||
}
|
||||
|
||||
static void
|
||||
init_config(struct traceroute_config *config)
|
||||
{
|
||||
memset(config, 0, sizeof(struct traceroute_config));
|
||||
config->max_ttl = DEFAULT_MAX_TTL;
|
||||
config->nqueries = DEFAULT_NQUERIES;
|
||||
config->waittime = DEFAULT_WAITTIME;
|
||||
}
|
||||
25
src/traceroute/cli/parse_utils/parse_destination.c
Normal file
25
src/traceroute/cli/parse_utils/parse_destination.c
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "traceroute/traceroute.h"
|
||||
#include "internal/traceroute/parse_utils.h"
|
||||
#include "internal/cli/messages.h"
|
||||
|
||||
int
|
||||
cli_parse_destination(const char *s, struct traceroute_config *config)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *res;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
bzero(&hints, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_INET;
|
||||
|
||||
if (0 != getaddrinfo(s, NULL, &hints, &res))
|
||||
return error_invalid_dest();
|
||||
memcpy(&sin, res->ai_addr, sizeof(sin));
|
||||
freeaddrinfo(res);
|
||||
config->dest_ip = sin.sin_addr;
|
||||
config->destination = s;
|
||||
return 0;
|
||||
}
|
||||
8
src/traceroute/core/traceroute.c
Normal file
8
src/traceroute/core/traceroute.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#include "compiler.h"
|
||||
#include "traceroute/traceroute.h"
|
||||
|
||||
int
|
||||
traceroute_run(__unused const struct traceroute_config *config)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
25
src/traceroute/main.c
Normal file
25
src/traceroute/main.c
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "traceroute/cli.h"
|
||||
#include "version_gen.h"
|
||||
|
||||
char *g_prog_name = NULL;
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct traceroute_config config = {0};
|
||||
int ret = CLI_ERROR;
|
||||
|
||||
g_prog_name = argv[0];
|
||||
cli_set_prog_name(g_prog_name);
|
||||
ret = cli_parse_arguments(argc, argv, &config);
|
||||
if (ret != CLI_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
ret = traceroute_run(&config);
|
||||
|
||||
cleanup:
|
||||
cli_config_free(&config);
|
||||
return (ret == CLI_ERROR) ? 2 : EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,53 +1,59 @@
|
|||
check_PROGRAMS = test_tracker test_stats test_send
|
||||
check_PROGRAMS = test_tracker test_stats test_send
|
||||
|
||||
test_tracker_SOURCES = test_support.c ping/tracker/test_tracker.c
|
||||
test_stats_SOURCES = test_support.c ping/stats/test_stats.c
|
||||
test_send_SOURCES = test_support.c send/test_do_send.c
|
||||
test_tracker_SOURCES = test_support.c ping/tracker/test_tracker.c
|
||||
test_stats_SOURCES = test_support.c ping/stats/test_stats.c
|
||||
test_send_SOURCES = test_support.c send/test_do_send.c
|
||||
|
||||
BASE_CFLAGS = -std=c99 $(STRICT_CFLAGS)
|
||||
BASE_CFLAGS = -std=c99 $(STRICT_CFLAGS)
|
||||
|
||||
if ENABLE_DEBUG
|
||||
EXTRA_CFLAGS = -g -O0
|
||||
EXTRA_CFLAGS = -g -O0
|
||||
else
|
||||
EXTRA_CFLAGS =
|
||||
EXTRA_CFLAGS =
|
||||
endif
|
||||
|
||||
TEST_CPPFLAGS = \
|
||||
-I $(top_srcdir)/includes \
|
||||
-I $(top_srcdir)/libicmp/includes \
|
||||
-I $(top_srcdir)/libcli/include \
|
||||
-I $(top_srcdir)/tests \
|
||||
-D_GNU_SOURCE
|
||||
if ENABLE_SANITIZERS
|
||||
SANITIZER_FLAGS = -fsanitize=address,undefined
|
||||
else
|
||||
SANITIZER_FLAGS =
|
||||
endif
|
||||
|
||||
TEST_CFLAGS = $(BASE_CFLAGS) $(EXTRA_CFLAGS)
|
||||
TEST_CPPFLAGS = \
|
||||
-I $(top_srcdir)/includes \
|
||||
-I $(top_srcdir)/libicmp/includes \
|
||||
-I $(top_srcdir)/libcli/include \
|
||||
-I $(top_srcdir)/tests \
|
||||
-D_GNU_SOURCE
|
||||
|
||||
TEST_LDADD = \
|
||||
$(top_builddir)/src/ping/libping_core.la \
|
||||
$(top_srcdir)/libicmp/libicmp.a \
|
||||
$(top_builddir)/libcli/src/libcli.la \
|
||||
$(CRITERION_LIBS) \
|
||||
-lm
|
||||
TEST_CFLAGS = $(BASE_CFLAGS) $(EXTRA_CFLAGS) $(SANITIZER_FLAGS)
|
||||
|
||||
test_tracker_CPPFLAGS = $(TEST_CPPFLAGS)
|
||||
test_tracker_CFLAGS = $(TEST_CFLAGS)
|
||||
test_tracker_LDFLAGS =
|
||||
test_tracker_LDADD = $(TEST_LDADD)
|
||||
TEST_LDADD = \
|
||||
$(top_builddir)/src/ping/libping_core.la \
|
||||
$(top_srcdir)/libicmp/libicmp.a \
|
||||
$(top_builddir)/libcli/src/libcli.la \
|
||||
$(CRITERION_LIBS) \
|
||||
-lm
|
||||
|
||||
test_stats_CPPFLAGS = $(TEST_CPPFLAGS)
|
||||
test_stats_CFLAGS = $(TEST_CFLAGS)
|
||||
test_stats_LDFLAGS =
|
||||
test_stats_LDADD = $(TEST_LDADD)
|
||||
test_tracker_CPPFLAGS = $(TEST_CPPFLAGS)
|
||||
test_tracker_CFLAGS = $(TEST_CFLAGS)
|
||||
test_tracker_LDFLAGS = $(SANITIZER_FLAGS)
|
||||
test_tracker_LDADD = $(TEST_LDADD)
|
||||
|
||||
test_send_CPPFLAGS = $(TEST_CPPFLAGS)
|
||||
test_send_CFLAGS = $(TEST_CFLAGS)
|
||||
test_send_LDFLAGS = \
|
||||
-Wl,--wrap=icmp_send_echo \
|
||||
-Wl,--wrap=icmp_should_retry \
|
||||
-Wl,--wrap=icmp_strerror \
|
||||
-Wl,--wrap=ping_scheduler_arm
|
||||
test_send_LDADD = $(TEST_LDADD)
|
||||
test_stats_CPPFLAGS = $(TEST_CPPFLAGS)
|
||||
test_stats_CFLAGS = $(TEST_CFLAGS)
|
||||
test_stats_LDFLAGS = $(SANITIZER_FLAGS)
|
||||
test_stats_LDADD = $(TEST_LDADD)
|
||||
|
||||
TESTS = test_tracker test_stats test_send
|
||||
test_send_CPPFLAGS = $(TEST_CPPFLAGS)
|
||||
test_send_CFLAGS = $(TEST_CFLAGS)
|
||||
test_send_LDFLAGS = $(SANITIZER_FLAGS) \
|
||||
-Wl,--wrap=icmp_send_echo \
|
||||
-Wl,--wrap=icmp_should_retry \
|
||||
-Wl,--wrap=icmp_strerror \
|
||||
-Wl,--wrap=ping_scheduler_arm
|
||||
test_send_LDADD = $(TEST_LDADD)
|
||||
|
||||
TESTS = test_tracker test_stats test_send
|
||||
|
||||
# Version header needed by test_main.c
|
||||
BUILT_SOURCES = $(top_srcdir)/includes/version_gen.h
|
||||
BUILT_SOURCES = $(top_srcdir)/includes/version_gen.h
|
||||
|
|
|
|||
|
|
@ -2,65 +2,99 @@
|
|||
#include <stdint.h>
|
||||
#include "internal/ping/tracker.h"
|
||||
|
||||
static struct timespec
|
||||
make_ts(long sec, long nsec)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
ts.tv_sec = sec;
|
||||
ts.tv_nsec = nsec;
|
||||
return (ts);
|
||||
}
|
||||
|
||||
Test(ping_tracker, init)
|
||||
{
|
||||
struct ping_tracker t;
|
||||
struct ping_tracker t;
|
||||
|
||||
ping_tracker_init(&t);
|
||||
cr_assert_eq(t.nb_sent, (size_t)0);
|
||||
cr_assert_eq(t.nb_recv, (size_t)0);
|
||||
cr_assert_eq(t.nb_dup, (size_t)0);
|
||||
}
|
||||
|
||||
Test(ping_tracker, basic_send_recv)
|
||||
{
|
||||
struct ping_tracker t;
|
||||
int accepted;
|
||||
struct timespec ts_send;
|
||||
struct timespec ts_recv;
|
||||
int64_t rtt;
|
||||
|
||||
ping_tracker_init(&t);
|
||||
ping_tracker_record_send(&t, 1);
|
||||
accepted = ping_tracker_record_recv(&t, 1);
|
||||
cr_assert_eq(accepted, 1);
|
||||
ts_send = make_ts(1, 0);
|
||||
ts_recv = make_ts(1, 10000000); /* 10 ms later */
|
||||
ping_tracker_record_send(&t, 1, &ts_send);
|
||||
rtt = ping_tracker_record_recv(&t, 1, &ts_recv);
|
||||
cr_assert_eq(rtt, (int64_t)10000000, "Expected RTT of 10ms in ns");
|
||||
cr_assert_eq(t.nb_sent, (size_t)1);
|
||||
cr_assert_eq(t.nb_recv, (size_t)1);
|
||||
cr_assert_eq(t.nb_dup, (size_t)0);
|
||||
}
|
||||
|
||||
Test(ping_tracker, double_recv_is_dup)
|
||||
Test(ping_tracker, double_recv_ignored)
|
||||
{
|
||||
struct ping_tracker t;
|
||||
int accepted;
|
||||
struct timespec ts_send;
|
||||
struct timespec ts_recv;
|
||||
int64_t rtt;
|
||||
|
||||
ping_tracker_init(&t);
|
||||
ping_tracker_record_send(&t, 5);
|
||||
accepted = ping_tracker_record_recv(&t, 5);
|
||||
cr_assert_eq(accepted, 1, "First recv should be accepted");
|
||||
accepted = ping_tracker_record_recv(&t, 5);
|
||||
cr_assert_eq(accepted, 0, "Duplicate recv should return 0");
|
||||
ts_send = make_ts(0, 0);
|
||||
ts_recv = make_ts(0, 5000000);
|
||||
ping_tracker_record_send(&t, 5, &ts_send);
|
||||
rtt = ping_tracker_record_recv(&t, 5, &ts_recv);
|
||||
cr_assert(rtt >= 0, "First recv should succeed");
|
||||
rtt = ping_tracker_record_recv(&t, 5, &ts_recv);
|
||||
cr_assert_eq(rtt, (int64_t)-1, "Duplicate recv should return -1");
|
||||
cr_assert_eq(t.nb_recv, (size_t)1);
|
||||
cr_assert_eq(t.nb_dup, (size_t)1);
|
||||
}
|
||||
|
||||
Test(ping_tracker, unknown_seq_accepted)
|
||||
Test(ping_tracker, unknown_seq_returns_minus_one)
|
||||
{
|
||||
struct ping_tracker t;
|
||||
int accepted;
|
||||
struct timespec ts;
|
||||
int64_t rtt;
|
||||
|
||||
ping_tracker_init(&t);
|
||||
accepted = ping_tracker_record_recv(&t, 42);
|
||||
cr_assert_eq(accepted, 1);
|
||||
cr_assert_eq(t.nb_recv, (size_t)1);
|
||||
ts = make_ts(0, 0);
|
||||
rtt = ping_tracker_record_recv(&t, 42, &ts);
|
||||
cr_assert_eq(rtt, (int64_t)-1);
|
||||
}
|
||||
|
||||
Test(ping_tracker, wraparound_seq)
|
||||
{
|
||||
struct ping_tracker t;
|
||||
struct timespec ts_send;
|
||||
struct timespec ts_recv;
|
||||
int64_t rtt;
|
||||
|
||||
ping_tracker_init(&t);
|
||||
ts_send = make_ts(0, 0);
|
||||
ts_recv = make_ts(0, 1000000);
|
||||
/* seq 128 maps to slot 0 */
|
||||
ping_tracker_record_send(&t, 128, &ts_send);
|
||||
rtt = ping_tracker_record_recv(&t, 128, &ts_recv);
|
||||
cr_assert_eq(rtt, (int64_t)1000000);
|
||||
}
|
||||
|
||||
Test(ping_tracker, lost_count)
|
||||
{
|
||||
struct ping_tracker t;
|
||||
struct timespec ts;
|
||||
|
||||
ping_tracker_init(&t);
|
||||
ping_tracker_record_send(&t, 1);
|
||||
ping_tracker_record_send(&t, 2);
|
||||
ping_tracker_record_send(&t, 3);
|
||||
ping_tracker_record_recv(&t, 2);
|
||||
ts = make_ts(0, 0);
|
||||
ping_tracker_record_send(&t, 1, &ts);
|
||||
ping_tracker_record_send(&t, 2, &ts);
|
||||
ping_tracker_record_send(&t, 3, &ts);
|
||||
ping_tracker_record_recv(&t, 2, &ts);
|
||||
cr_assert_eq(t.nb_sent, (size_t)3);
|
||||
cr_assert_eq(t.nb_recv, (size_t)1);
|
||||
cr_assert_eq(t.nb_sent - t.nb_recv, (size_t)2);
|
||||
|
|
@ -69,36 +103,63 @@ Test(ping_tracker, lost_count)
|
|||
Test(ping_tracker, sent_count_increments)
|
||||
{
|
||||
struct ping_tracker t;
|
||||
struct timespec ts;
|
||||
|
||||
ping_tracker_init(&t);
|
||||
ping_tracker_record_send(&t, 1);
|
||||
ping_tracker_record_send(&t, 2);
|
||||
ping_tracker_record_send(&t, 3);
|
||||
ts = make_ts(0, 0);
|
||||
ping_tracker_record_send(&t, 1, &ts);
|
||||
ping_tracker_record_send(&t, 2, &ts);
|
||||
ping_tracker_record_send(&t, 3, &ts);
|
||||
cr_assert_eq(t.nb_sent, (size_t)3);
|
||||
}
|
||||
|
||||
Test(ping_tracker, no_slot_collision_at_256)
|
||||
Test(ping_tracker, recv_rtt_positive)
|
||||
{
|
||||
struct ping_tracker t;
|
||||
struct timespec ts_send;
|
||||
struct timespec ts_recv;
|
||||
int64_t rtt;
|
||||
|
||||
ping_tracker_init(&t);
|
||||
ts_send = make_ts(1, 0);
|
||||
ts_recv = make_ts(1, 10000000); /* 10 ms later */
|
||||
ping_tracker_record_send(&t, 7, &ts_send);
|
||||
rtt = ping_tracker_record_recv(&t, 7, &ts_recv);
|
||||
cr_assert(rtt > 0, "RTT should be positive");
|
||||
}
|
||||
|
||||
Test(ping_tracker, slot_reuse_after_wraparound)
|
||||
{
|
||||
struct ping_tracker t;
|
||||
struct timespec ts_send;
|
||||
struct timespec ts_recv;
|
||||
int64_t rtt;
|
||||
|
||||
ping_tracker_init(&t);
|
||||
ts_send = make_ts(0, 0);
|
||||
ts_recv = make_ts(0, 1000000);
|
||||
/* seq=1 -> slot 1 */
|
||||
ping_tracker_record_send(&t, 1, &ts_send);
|
||||
rtt = ping_tracker_record_recv(&t, 1, &ts_recv);
|
||||
cr_assert(rtt >= 0, "First round RTT should be >= 0");
|
||||
/* seq=129 -> slot 129 % 128 = 1, same slot */
|
||||
ping_tracker_record_send(&t, 129, &ts_send);
|
||||
rtt = ping_tracker_record_recv(&t, 129, &ts_recv);
|
||||
cr_assert(rtt >= 0, "Second round RTT should be >= 0");
|
||||
cr_assert_eq(t.nb_sent, (size_t)2);
|
||||
cr_assert_eq(t.nb_recv, (size_t)2);
|
||||
}
|
||||
|
||||
Test(ping_tracker, full_buffer)
|
||||
{
|
||||
struct ping_tracker t;
|
||||
struct timespec ts;
|
||||
uint16_t seq;
|
||||
|
||||
ping_tracker_init(&t);
|
||||
for (seq = 0; seq < 256; seq++)
|
||||
{
|
||||
ping_tracker_record_send(&t, seq);
|
||||
cr_assert_eq(ping_tracker_record_recv(&t, seq), 1,
|
||||
"seq %u should be accepted", (unsigned)seq);
|
||||
}
|
||||
cr_assert_eq(t.nb_recv, (size_t)256);
|
||||
}
|
||||
|
||||
Test(ping_tracker, full_seq_space)
|
||||
{
|
||||
struct ping_tracker t;
|
||||
uint32_t seq;
|
||||
|
||||
ping_tracker_init(&t);
|
||||
for (seq = 0; seq < 65536; seq++)
|
||||
ping_tracker_record_send(&t, (uint16_t)seq);
|
||||
cr_assert_eq(t.nb_sent, (size_t)65536);
|
||||
ts = make_ts(0, 0);
|
||||
for (seq = 1; seq <= 128; seq++)
|
||||
ping_tracker_record_send(&t, seq, &ts);
|
||||
cr_assert_eq(t.nb_sent, (size_t)128);
|
||||
cr_assert_eq(t.nb_recv, (size_t)0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
#include "internal/ping/ping_state.h"
|
||||
#include "internal/ping/tracker.h"
|
||||
#include "ping/ping.h"
|
||||
#include "ping/ft_ping_const.h"
|
||||
|
||||
/* Controllable mock state */
|
||||
int g_mock_send_ret;
|
||||
|
|
@ -105,23 +104,3 @@ Test(do_send, eagain_then_success_uses_same_seq, .init = setup)
|
|||
cr_assert_eq(g_state.seq, (uint16_t)1);
|
||||
cr_assert_eq(g_tracker.nb_sent, (size_t)1);
|
||||
}
|
||||
|
||||
Test(do_send, ts_in_payload_increments_seq, .init = setup)
|
||||
{
|
||||
g_mock_send_ret = 0;
|
||||
g_state.ts_in_payload = 1;
|
||||
do_send(&g_state, PING_TIMESTAMP_SIZE);
|
||||
cr_assert_eq(g_state.seq, (uint16_t)1);
|
||||
cr_assert_eq(g_tracker.nb_sent, (size_t)1);
|
||||
}
|
||||
|
||||
Test(do_send, ts_in_payload_multiple_sends, .init = setup)
|
||||
{
|
||||
g_mock_send_ret = 0;
|
||||
g_state.ts_in_payload = 1;
|
||||
do_send(&g_state, PING_TIMESTAMP_SIZE);
|
||||
do_send(&g_state, PING_TIMESTAMP_SIZE);
|
||||
do_send(&g_state, PING_TIMESTAMP_SIZE);
|
||||
cr_assert_eq(g_state.seq, (uint16_t)3);
|
||||
cr_assert_eq(g_tracker.nb_sent, (size_t)3);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue