21#include "lwip/netif.h"
23#include "lwip/timeouts.h"
25#include "lwip/inet_chksum.h"
27#include "lwip/netdb.h"
28#include "lwip/sockets.h"
35#define PING_TIME_DIFF_MS(_end, _start) \
36 ((uint32_t)((_end - _start) / 1000))
38#define PING_CHECK_START_TIMEOUT_MS (100)
40#define PING_FLAGS_INIT (1 << 0)
41#define PING_FLAGS_RUN (1 << 1)
43#define THREAD_NOTIFY_BIT 0x01
55static const char *
TAG =
"xf_ping";
59#define XF_GOTO_ON_FALSE(a, err_code, goto_tag, log_tag, format, ...) \
61 if (unlikely(!(a))) { \
62 XF_LOGE(log_tag, format, ##__VA_ARGS__); \
90 ctx->task_exit_flag =
false;
101 ctx->cb_func = cb_func;
102 ctx->user_args = user_args;
111 ctx->icmp_pkt_size =
sizeof(
struct icmp_echo_hdr) + p_cfg->data_size;
117 ctx->packet_hdr->code = 0;
118 ctx->packet_hdr->id = ((uint32_t)
ctx->task_hdl) & 0xFFFF;
120 char *d = (
char *)(
ctx->packet_hdr) +
sizeof(
struct icmp_echo_hdr);
121 for (uint32_t i = 0; i < p_cfg->
data_size; i++) {
127#if CONFIG_XF_NET_APPS_ENABLE_IPV6
128 || ip6_addr_isipv4mappedipv6(ip_2_ip6(&p_cfg->
target_addr))
131 ctx->sock = socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP);
133#if CONFIG_XF_NET_APPS_ENABLE_IPV6
135 ctx->sock = socket(AF_INET6, SOCK_RAW, IP6_NEXTH_ICMP6);
139 TAG,
"create socket failed: %d",
ctx->sock);
143 if (netif_index_to_name(p_cfg->
interface, iface.ifr_name) == NULL) {
144 XF_LOGE(
TAG,
"fail to find interface name with netif index %d",
148 if (setsockopt(
ctx->sock, SOL_SOCKET, SO_BINDTODEVICE, &iface,
sizeof(iface)) != 0) {
149 XF_LOGE(
TAG,
"fail to setsockopt SO_BINDTODEVICE");
154 struct timeval timeout;
156 timeout.tv_usec = (p_cfg->
timeout_ms % 1000) * 1000;
157 setsockopt(
ctx->sock, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof(timeout));
158 setsockopt(
ctx->sock, IPPROTO_IP, IP_TOS, &
ctx->tos,
sizeof(
ctx->tos));
159 setsockopt(
ctx->sock, IPPROTO_IP, IP_TTL, &
ctx->ttl,
sizeof(
ctx->ttl));
162 struct sockaddr_in *to4 = (
struct sockaddr_in *)&
ctx->target_addr;
163 to4->sin_family = AF_INET;
164 inet_addr_from_ip4addr(&to4->sin_addr, ip_2_ip4(&p_cfg->
target_addr));
165 ctx->packet_hdr->type = ICMP_ECHO;
167#if CONFIG_XF_NET_APPS_ENABLE_IPV6
169 struct sockaddr_in6 *to6 = (
struct sockaddr_in6 *)&
ctx->target_addr;
170 to6->sin6_family = AF_INET6;
171 inet6_addr_from_ip6addr(&to6->sin6_addr, ip_2_ip6(&p_cfg->
target_addr));
172 ctx->packet_hdr->type = ICMP6_TYPE_EREQ;
183 closesocket(
ctx->sock);
185 if (
ctx->packet_hdr) {
206#define WAIT_CNT_MAX 1000
207 while (
ctx->task_exit_flag !=
true) {
247 bool b_running =
false;
252 if ((NULL == p_cfg) || (NULL == p_flags)) {
263 struct timeval timeout;
265 timeout.tv_usec = (p_cfg->
timeout_ms % 1000) * 1000;
266 setsockopt(
ctx->sock, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof(timeout));
268 if (p_flags->
b_tos) {
270 setsockopt(
ctx->sock, IPPROTO_IP, IP_TOS, &
ctx->tos,
sizeof(
ctx->tos));
272 if (p_flags->
b_ttl) {
274 setsockopt(
ctx->sock, IPPROTO_IP, IP_TTL, &
ctx->ttl,
sizeof(
ctx->ttl));
280 struct sockaddr_in *to4 = (
struct sockaddr_in *)&
ctx->target_addr;
281 to4->sin_family = AF_INET;
282 inet_addr_from_ip4addr(&to4->sin_addr, ip_2_ip4(&p_cfg->
target_addr));
283 ctx->packet_hdr->type = ICMP_ECHO;
285#if CONFIG_XF_NET_APPS_ENABLE_IPV6
287 struct sockaddr_in6 *to6 = (
struct sockaddr_in6 *)&
ctx->target_addr;
288 to6->sin6_family = AF_INET6;
289 inet6_addr_from_ip6addr(&to6->sin6_addr, ip_2_ip6(&p_cfg->
target_addr));
290 ctx->packet_hdr->type = ICMP6_TYPE_EREQ;
296 if (netif_index_to_name(p_cfg->
interface, iface.ifr_name) == NULL) {
297 XF_LOGE(
TAG,
"fail to find interface name with netif index %d",
301 if (setsockopt(
ctx->sock, SOL_SOCKET, SO_BINDTODEVICE, &iface,
sizeof(iface)) != 0) {
302 XF_LOGE(
TAG,
"fail to setsockopt SO_BINDTODEVICE");
326 return ctx->ping_running_flag;
351 ctx->packet_hdr->seqno++;
353 ctx->packet_hdr->chksum = 0;
354 if (
ctx->packet_hdr->type == ICMP_ECHO) {
355 ctx->packet_hdr->chksum = inet_chksum(
ctx->packet_hdr,
ctx->icmp_pkt_size);
358 socklen_t socklen = (
ctx->target_addr_type == IPADDR_TYPE_V4)
359 ?
sizeof(
struct sockaddr_in)
360 :
sizeof(
struct sockaddr_in6);
361 ssize_t sent = sendto(
ctx->sock,
ctx->packet_hdr,
ctx->icmp_pkt_size, 0,
362 (
struct sockaddr *)&
ctx->target_addr, socklen);
364 if (sent != (ssize_t)
ctx->icmp_pkt_size) {
366 socklen_t opt_len =
sizeof(opt_val);
367 getsockopt(
ctx->sock, SOL_SOCKET, SO_ERROR, &opt_val, &opt_len);
380 struct sockaddr_storage from;
382 int fromlen = (
ctx->target_addr_type == IPADDR_TYPE_V4)
383 ?
sizeof(
struct sockaddr_in)
384 :
sizeof(
struct sockaddr_in6);
385 uint16_t data_head = 0;
387 while ((len = recvfrom(
ctx->sock, buf,
sizeof(buf), 0,
388 (
struct sockaddr *)&from, (socklen_t *)&fromlen)) > 0) {
389 if (from.ss_family == AF_INET) {
391 struct sockaddr_in *from4 = (
struct sockaddr_in *)&from;
392 inet_addr_to_ip4addr(ip_2_ip4(&
ctx->recv_addr), &from4->sin_addr);
393 IP_SET_TYPE_VAL(
ctx->recv_addr, IPADDR_TYPE_V4);
394 data_head = (uint16_t)(
sizeof(
struct ip_hdr) +
sizeof(
struct icmp_echo_hdr));
396#if CONFIG_XF_NET_APPS_ENABLE_IPV6
399 struct sockaddr_in6 *from6 = (
struct sockaddr_in6 *)&from;
400 inet6_addr_to_ip6addr(ip_2_ip6(&
ctx->recv_addr), &from6->sin6_addr);
401 IP_SET_TYPE_VAL(
ctx->recv_addr, IPADDR_TYPE_V6);
402 data_head = (uint16_t)(
sizeof(
struct ip6_hdr) +
sizeof(
struct icmp6_echo_hdr));
405 if (len >= data_head) {
406 if (IP_IS_V4_VAL(
ctx->recv_addr)) {
407 struct ip_hdr *iphdr = (
struct ip_hdr *)buf;
408 struct icmp_echo_hdr *iecho = (
struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4));
409 if ((iecho->id ==
ctx->packet_hdr->id) && (iecho->seqno ==
ctx->packet_hdr->seqno)) {
411 ctx->ttl = iphdr->_ttl;
412 ctx->tos = iphdr->_tos;
413 ctx->recv_len = lwip_ntohs(IPH_LEN(iphdr)) - data_head;
417#if CONFIG_XF_NET_APPS_ENABLE_IPV6
418 else if (IP_IS_V6_VAL(
ctx->recv_addr)) {
419 struct ip6_hdr *iphdr = (
struct ip6_hdr *)buf;
420 struct icmp6_echo_hdr *iecho6 = (
struct icmp6_echo_hdr *)(buf +
sizeof(
struct ip6_hdr));
421 if ((iecho6->id ==
ctx->packet_hdr->id) && (iecho6->seqno ==
ctx->packet_hdr->seqno)) {
423 ctx->recv_len = IP6H_PLEN(iphdr) -
sizeof(
struct icmp6_echo_hdr);
429 fromlen = (
ctx->target_addr_type == IPADDR_TYPE_V4)
430 ?
sizeof(
struct sockaddr_in)
431 :
sizeof(
struct sockaddr_in6);
443 uint32_t interval_ticks;
457 if (xf_ret !=
XF_OK) {
463 ctx->packet_hdr->seqno = 0;
464 ctx->transmitted = 0;
466 ctx->total_time_ms = 0;
470 && ((
ctx->count == 0xFFFFFFFF) || (
ctx->packet_hdr->seqno <
ctx->count))) {
477 ctx->ping_running_flag =
true;
486 ctx->total_time_ms +=
ctx->elapsed_time_ms;
490 ctx->cb_func(event_id, (
void *)
ctx,
ctx->user_args);
494 if (interval_ticks) {
500 ctx->ping_running_flag =
false;
506 if (
ctx->auto_delete_flag) {
511 if (
ctx->packet_hdr) {
514 if (
ctx->sock >= 0) {
515 closesocket(
ctx->sock);
517 ctx->task_exit_flag =
true;
523 if (
ctx->auto_delete_flag) {
uint32_t xf_osal_kernel_ms_to_ticks(uint32_t ms)
将 ms 数转为滴答数.
uint32_t xf_osal_kernel_get_tick_count(void)
获取 RTOS 内核滴答计数。
xf_err_t xf_osal_thread_delete(xf_osal_thread_t thread)
终止线程的执行。
xf_osal_thread_t xf_osal_thread_create(xf_osal_thread_func_t func, void *argument, const xf_osal_thread_attr_t *attr)
创建一个线程并将其添加到活动线程中。
xf_err_t xf_osal_delay_until(uint32_t ticks)
(睡眠)等到指定时间刻度。
uint32_t xf_osal_thread_notify_get(void)
获取当前正在运行的线程的当前线程标志。
xf_err_t xf_osal_delay_ms(uint32_t ms)
(睡眠)等待超时,以 ms 为单位。
xf_err_t xf_osal_thread_notify_clear(uint32_t notify)
清除当前运行线程的指定线程标志。
xf_err_t xf_osal_thread_notify_wait(uint32_t notify, uint32_t options, uint32_t timeout)
当前运行线程等待一个或多个线程标志变为有信号状态。
xf_err_t xf_osal_thread_notify_set(xf_osal_thread_t thread, uint32_t notify)
设置线程的指定线程标志。
#define XF_OSAL_WAIT_ANY
标志选项。 xf_osal_event_wait() 或 xf_osal_thread_notify_wait().
xf_err_t xf_ping_new_session(const xf_ping_cfg_t *p_cfg, xf_ping_cb_t cb_func, void *user_args, xf_ping_t *hdl_out)
创建 ping 会话。
xf_err_t xf_ping_restart(xf_ping_t hdl, const xf_ping_cfg_t *p_cfg, xf_ping_cfg_update_flags_t *p_flags)
重新启动 ping 会话。
struct _xf_ping_ctx_t * xf_ping_t
ping 会话句柄。
xf_err_t xf_ping_stop(xf_ping_t hdl)
停止 ping 会话。
#define XF_PING_THREAD_NAME
xf_err_t xf_ping_start(xf_ping_t hdl)
启动 ping 会话。
bool xf_ping_is_running(xf_ping_t hdl)
检查 ping 是否正在运行。
int32_t xf_ping_event_id_t
ping 事件 id。见 xf_ping_event_code_t.
void(* xf_ping_cb_t)(xf_ping_event_id_t event_id, xf_ping_t hdl, void *user_args)
ping 回调函数原型。
xf_err_t xf_ping_delete_session(xf_ping_t hdl)
删除 ping 会话。
xf_us_t xf_sys_time_get_us(void)
获取系统时间的时间戳,单位微秒(us)
#define BITS_SET0(var, bits_mask)
设置 32 位变量 var 的对应位掩码 bits_mask 为 1 的地方为 0。
#define BITS_SET1(var, bits_mask)
设置 32 位变量 var 的对应位掩码 bits_mask 为 1 的地方为 1。
int32_t xf_err_t
整形错误类型。 错误码具体值见 xf_err_code_t.
const char * xf_err_to_name(xf_err_t code)
返回 xf_err_code_t 错误代码对应的错误信息字符串。
#define xf_memset(ptr, value, size)
uint32_t b_auto_delete_flag
#define XF_LOGE(tag, format,...)
static xf_err_t xf_ping_send(xf_ping_ctx_t *ctx)
#define THREAD_NOTIFY_BIT
#define XF_GOTO_ON_FALSE(a, err_code, goto_tag, log_tag, format,...)
#define PING_TIME_DIFF_MS(_end, _start)
static void xf_ping_thread(void *args)
static int xf_ping_receive(xf_ping_ctx_t *ctx)
#define PING_CHECK_START_TIMEOUT_MS