Files
cleonos/cleonos/c/apps/ping_main.c
2026-04-25 12:33:18 +08:00

184 lines
5.0 KiB
C

#include "cmd_runtime.h"
#include <stdio.h>
#define USH_PING_POLL_BUDGET 200000000ULL
static int ush_ping_parse_ipv4_be(const char *text, u64 *out_ipv4_be) {
u64 acc = 0ULL;
u64 value = 0ULL;
u64 parts = 0ULL;
u64 has_digit = 0ULL;
u64 i = 0ULL;
if (text == (const char *)0 || out_ipv4_be == (u64 *)0) {
return 0;
}
while (text[i] != '\0') {
char ch = text[i];
if (ch >= '0' && ch <= '9') {
value = (value * 10ULL) + (u64)(ch - '0');
if (value > 255ULL) {
return 0;
}
has_digit = 1ULL;
} else if (ch == '.') {
if (has_digit == 0ULL || parts >= 3ULL) {
return 0;
}
acc = (acc << 8ULL) | value;
parts++;
value = 0ULL;
has_digit = 0ULL;
} else {
return 0;
}
i++;
}
if (has_digit == 0ULL || parts != 3ULL) {
return 0;
}
acc = (acc << 8ULL) | value;
*out_ipv4_be = acc & 0xFFFFFFFFULL;
return 1;
}
static void ush_ping_print_ipv4(u64 ipv4_be) {
unsigned int a = (unsigned int)((ipv4_be >> 24ULL) & 0xFFULL);
unsigned int b = (unsigned int)((ipv4_be >> 16ULL) & 0xFFULL);
unsigned int c = (unsigned int)((ipv4_be >> 8ULL) & 0xFFULL);
unsigned int d = (unsigned int)(ipv4_be & 0xFFULL);
(void)printf("%u.%u.%u.%u", a, b, c, d);
}
static int ush_cmd_ping(const char *arg) {
char host[USH_PATH_MAX];
char count_text[32];
const char *rest = "";
const char *rest2 = "";
u64 target_ipv4_be = 0ULL;
u64 local_ipv4_be;
u64 count = 4ULL;
u64 i;
u64 received = 0ULL;
if (arg == (const char *)0 || arg[0] == '\0') {
(void)puts("ping: usage ping <a.b.c.d> [count]");
return 0;
}
if (ush_split_first_and_rest(arg, host, (u64)sizeof(host), &rest) == 0) {
(void)puts("ping: usage ping <a.b.c.d> [count]");
return 0;
}
if (ush_ping_parse_ipv4_be(host, &target_ipv4_be) == 0) {
(void)puts("ping: invalid ipv4 address");
return 0;
}
if (rest != (const char *)0 && rest[0] != '\0') {
if (ush_split_first_and_rest(rest, count_text, (u64)sizeof(count_text), &rest2) == 0) {
(void)puts("ping: usage ping <a.b.c.d> [count]");
return 0;
}
if (rest2 != (const char *)0 && rest2[0] != '\0') {
(void)puts("ping: usage ping <a.b.c.d> [count]");
return 0;
}
if (ush_parse_u64_dec(count_text, &count) == 0 || count == 0ULL || count > 64ULL) {
(void)puts("ping: count must be in range 1..64");
return 0;
}
}
if (cleonos_sys_net_available() == 0ULL) {
(void)puts("ping: network unavailable (e1000 not ready)");
return 0;
}
local_ipv4_be = cleonos_sys_net_ipv4_addr();
(void)fputs("PING ", 1);
ush_ping_print_ipv4(target_ipv4_be);
(void)fputs(" from ", 1);
ush_ping_print_ipv4(local_ipv4_be);
(void)putchar('\n');
for (i = 0ULL; i < count; i++) {
u64 ok = cleonos_sys_net_ping(target_ipv4_be, USH_PING_POLL_BUDGET);
if (ok != 0ULL) {
(void)fputs("reply from ", 1);
ush_ping_print_ipv4(target_ipv4_be);
(void)printf(" seq=%llu\n", (unsigned long long)(i + 1ULL));
received++;
} else {
(void)fputs("timeout from ", 1);
ush_ping_print_ipv4(target_ipv4_be);
(void)printf(" seq=%llu\n", (unsigned long long)(i + 1ULL));
}
if (i + 1ULL < count) {
(void)cleonos_sys_sleep_ticks(30ULL);
}
}
(void)puts("");
(void)printf("ping stats: tx=%llu rx=%llu loss=%llu\n", (unsigned long long)count, (unsigned long long)received,
(unsigned long long)(count - received));
return (received > 0ULL) ? 1 : 0;
}
int cleonos_app_main(void) {
ush_cmd_ctx ctx;
ush_cmd_ret ret;
ush_state sh;
char initial_cwd[USH_PATH_MAX];
int has_context = 0;
int success = 0;
const char *arg = "";
ush_zero(&ctx, (u64)sizeof(ctx));
ush_zero(&ret, (u64)sizeof(ret));
ush_init_state(&sh);
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
if (ush_command_ctx_read(&ctx) != 0) {
if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "ping") != 0) {
has_context = 1;
arg = ctx.arg;
if (ctx.cwd[0] == '/') {
ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd);
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
}
}
}
success = ush_cmd_ping(arg);
if (has_context != 0) {
if (ush_streq(sh.cwd, initial_cwd) == 0) {
ret.flags |= USH_CMD_RET_FLAG_CWD;
ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd);
}
if (sh.exit_requested != 0) {
ret.flags |= USH_CMD_RET_FLAG_EXIT;
ret.exit_code = sh.exit_code;
}
(void)ush_command_ret_write(&ret);
}
return (success != 0) ? 0 : 1;
}