sdk-hwV1.3/lichee/xr806/appos/project/demo/at_demo/ping.c

221 lines
6.5 KiB
C
Raw Normal View History

2024-05-07 10:09:20 +00:00
/*
* Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <lwip/tcpip.h>
#include <lwip/inet.h>
#include "lwip/sockets.h"
#include <lwip/icmp.h>
#include <lwip/inet_chksum.h>
#include "lwip/mem.h"
#include "net/ping/ping.h"
#include "lwip/ip.h"
#include "lwip/netdb.h"
#include "atcmd/at_command.h"
#include "atcmd.h"
static u16_t PING_IDs = 0x1234;
#define PING_TO 5000 /* timeout to wait every reponse(ms) */
#define PING_ID 0xABCD
#define PING_DATA_SIZE 100 /* size of send frame buff, not include ICMP frma head */
#define GET_TICKS OS_GetTicks
static void generate_ping_echo(u8_t *buf, u32_t len, u16_t seq)
{
u32_t i;
u32_t data_len = len - sizeof(struct icmp_echo_hdr);
struct icmp_echo_hdr *pecho;
pecho = (struct icmp_echo_hdr *)buf;
ICMPH_TYPE_SET(pecho, ICMP_ECHO);
ICMPH_CODE_SET(pecho, 0);
pecho->chksum = 0;
pecho->id = PING_IDs;
pecho->seqno = htons(seq);
/* fill the additional data buffer with some data */
for (i = 0; i < data_len; i++) {
buf[sizeof(struct icmp_echo_hdr) + i] = (unsigned char)i;
}
/* Checksum of icmp header and data */
pecho->chksum = inet_chksum(buf, len);
}
s32_t ping(struct ping_data *data)
{
struct sockaddr_in ToAddr;
struct sockaddr_in FromAddr;
socklen_t FromLen;
int iSockID, iStatus;
fd_set ReadFds;
struct timeval Timeout;
u8_t *ping_buf, *reply_buf;
u32_t ping_size, reply_size;
struct ip_hdr *iphdr;
struct icmp_echo_hdr *pecho;
u16_t ping_seq_num = 1;
s32_t ping_pass = 0;
u32_t i;
u32_t TimeStart, TimeNow, TimeElapse;
PING_IDs++;
if (PING_IDs == 0x7FFF)
PING_IDs = 0x1234;
memset(&FromAddr, 0, sizeof(FromAddr));
FromLen = sizeof(FromAddr);
iSockID = socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP);
if (iSockID < 0) {
at_dump("create socket fail.\n");
return -1;
}
int val = 1;
ioctlsocket(iSockID, FIONBIO, (void *)&val); /* set noblocking */
memset(&ToAddr, 0, sizeof(ToAddr));
ToAddr.sin_len = sizeof(ToAddr);
ToAddr.sin_family = AF_INET;
//ToAddr.sin_port = data->port;
#ifdef CONFIG_LWIP_V1
ToAddr.sin_addr.s_addr = ip4_addr_get_u32(&(data->sin_addr));
#else
ToAddr.sin_addr.s_addr = ip_addr_get_ip4_u32(&(data->sin_addr));
#endif
ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
ping_buf = (u8_t *) mem_malloc((mem_size_t) ping_size);
if (!ping_buf) {
return -1;
}
reply_buf = (u8_t *) mem_malloc(PING_DATA_SIZE + 50); /* reserve more buf */
if (!reply_buf) {
mem_free(ping_buf);
return -1;
}
for (i = 0; i < data->count; i++) {
generate_ping_echo(ping_buf, ping_size, ping_seq_num);
OS_Sleep(1);
sendto(iSockID, ping_buf, ping_size, 0, (struct sockaddr *)&ToAddr, sizeof(ToAddr));
TimeStart = GET_TICKS();
while (1) {
FD_ZERO(&ReadFds);
FD_SET(iSockID, &ReadFds);
Timeout.tv_sec = 0;
Timeout.tv_usec = 50*1000; /* 50ms */
iStatus = lwip_select(FD_SETSIZE, &ReadFds, NULL, NULL, &Timeout);
if (iStatus > 0 && FD_ISSET(iSockID, &ReadFds)) {
/* block mode can't be used, we wait here if receiving party has sended,
* but we can set select to timeout mode to lower cpu's utilization */
reply_size = recvfrom(iSockID, reply_buf, (PING_DATA_SIZE + 50), 0,
(struct sockaddr *)&FromAddr, &FromLen);
if (reply_size >= (int)(sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) {
TimeNow = GET_TICKS();
if (TimeNow >= TimeStart) {
TimeElapse = TimeNow - TimeStart;
} else {
TimeElapse = 0xffffffffUL - TimeStart + TimeNow;
}
iphdr = (struct ip_hdr *)reply_buf;
pecho = (struct icmp_echo_hdr *)(reply_buf + (IPH_HL(iphdr) * 4));
if ((pecho->id == PING_IDs) && (pecho->seqno == htons(ping_seq_num))) {
/* do some ping result processing */
at_dump("+%d\n", TimeElapse);
ping_pass++;
break;
}
}
}
TimeNow = GET_TICKS();
if (TimeNow >= TimeStart) {
TimeElapse = TimeNow - TimeStart;
} else {
TimeElapse = 0xffffffffUL - TimeStart + TimeNow;
}
if (TimeElapse >= PING_TO) { /* giveup this wait, if wait timeout */
at_dump("+timeout\n");
break;
}
}
ping_seq_num++;
}
mem_free(ping_buf);
mem_free(reply_buf);
closesocket(iSockID);
if (ping_pass > 0)
return ping_pass;
else
return -1;
}
static int ping_get_host_by_name(char *name, unsigned int *address)
{
struct hostent *host_entry;
host_entry = gethostbyname(name);
if (host_entry) {
*(address) = *((u_long *)host_entry->h_addr_list[0]);
return 0; // OK
} else {
return 1; // Error
}
}
static struct ping_data pdata;
s32 test_ping(char *hostname, int count)
{
unsigned int address = 0;
memset((void *)&pdata, 0, sizeof(pdata));
if (ping_get_host_by_name(hostname, &address) != 0) {
ATCMD_ERR("invalid ping host.\n");
return -1;
}
#ifdef CONFIG_LWIP_V1
ip4_addr_set_u32(&pdata.sin_addr, address);
#elif LWIP_IPV4 /* now only for IPv4 */
ip_addr_set_ip4_u32(&pdata.sin_addr, address);
#else
#error "IPv4 not support!"
#endif
pdata.count = count;
ping(&pdata);
return 0;
}