275 lines
7.7 KiB
C
275 lines
7.7 KiB
C
|
/*
|
||
|
* 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.
|
||
|
*/
|
||
|
|
||
|
#if PRJCONF_NET_EN
|
||
|
|
||
|
#include "cmd_util.h"
|
||
|
#include "cmd_ping.h"
|
||
|
#include "lwip/netdb.h"
|
||
|
#include "net/ping/ping.h"
|
||
|
#include <getopt.h>
|
||
|
|
||
|
#if CMD_DESCRIBE
|
||
|
#define ping_help_info \
|
||
|
"[*] -c count\n" \
|
||
|
"\tStop after sending count ECHO_REQUEST packets. With deadline option,\n" \
|
||
|
"\tping waits for count ECHO_REPLY packets, until the timeout expires.\n" \
|
||
|
"[*] -i interval\n" \
|
||
|
"\tWait interval seconds between sending each packet.\n" \
|
||
|
"\tThe default is to wait for one second between each packet normally.\n" \
|
||
|
"[*] -s packetsize\n" \
|
||
|
"\tSpecifies the number of data bytes to be sent.\n" \
|
||
|
"[*] -W timeout\n" \
|
||
|
"\tTime to wait for a response, in seconds.\n" \
|
||
|
"[*] -w deadline\n" \
|
||
|
"\tSpecify a timeout, in seconds, before ping exits regardless of how many\n" \
|
||
|
"\tpackets have been sent or received.\n" \
|
||
|
"\tIn this case ping does not stop after count packet are sent,\n" \
|
||
|
"\tit waits either for deadline expire or until count probes are answered\n" \
|
||
|
"\tor for some error notification from network.\n" \
|
||
|
"[*] -e exit\n" \
|
||
|
"\tExit the ping thread according to the handle."
|
||
|
#endif /* CMD_DESCRIBE */
|
||
|
|
||
|
typedef struct {
|
||
|
OS_Thread_t ping_thread;
|
||
|
int handle; /* the ping hread handle */
|
||
|
|
||
|
struct ping_data ping_arg;
|
||
|
} cmd_ping_arg;
|
||
|
|
||
|
#define PING_ARG_HANDLE_MAX 2
|
||
|
cmd_ping_arg *s_cmd_ping_arg_handle[PING_ARG_HANDLE_MAX] = {NULL};
|
||
|
|
||
|
#define CMD_PING_DEFAULT_COUNT (3)
|
||
|
#define CMD_PING_DEFAULT_DATA_LONG (0xffff)
|
||
|
#define CMD_PING_DEFAULT_INTERVAL (1)
|
||
|
#define CMD_PING_DEFAULT_TIMEOUT (5*1000)
|
||
|
|
||
|
static int ping_handle_new(struct ping_data *arg)
|
||
|
{
|
||
|
if (arg == NULL)
|
||
|
return -1;
|
||
|
for (int i = 0; i < PING_ARG_HANDLE_MAX; i++) {
|
||
|
if (s_cmd_ping_arg_handle[i] == NULL) {
|
||
|
s_cmd_ping_arg_handle[i] = malloc(sizeof(cmd_ping_arg));
|
||
|
if (s_cmd_ping_arg_handle[i] == NULL) {
|
||
|
printf("ping data malloc err!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
memset(s_cmd_ping_arg_handle[i], 0, sizeof(cmd_ping_arg));
|
||
|
memcpy(&s_cmd_ping_arg_handle[i]->ping_arg, arg, sizeof(*arg));
|
||
|
s_cmd_ping_arg_handle[i]->handle = i;
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static int ping_handle_free(int handle)
|
||
|
{
|
||
|
if (handle < 0 || handle >= PING_ARG_HANDLE_MAX)
|
||
|
return -1;
|
||
|
|
||
|
if (s_cmd_ping_arg_handle[handle] != NULL) {
|
||
|
free(s_cmd_ping_arg_handle[handle]);
|
||
|
s_cmd_ping_arg_handle[handle] = NULL;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void ping_thread_fun(void *arg)
|
||
|
{
|
||
|
cmd_ping_arg *cmd_ping = s_cmd_ping_arg_handle[(int)arg];
|
||
|
|
||
|
ping(&cmd_ping->ping_arg);
|
||
|
|
||
|
OS_Thread_t thread = cmd_ping->ping_thread;
|
||
|
ping_handle_free(cmd_ping->handle);
|
||
|
OS_ThreadDelete(&thread);
|
||
|
}
|
||
|
|
||
|
static int ping_handle_start(int handle)
|
||
|
{
|
||
|
OS_Status ret;
|
||
|
|
||
|
if (handle < 0 || handle >= PING_ARG_HANDLE_MAX)
|
||
|
return -1;
|
||
|
|
||
|
if (s_cmd_ping_arg_handle[handle] == NULL)
|
||
|
return -1;
|
||
|
|
||
|
ret = OS_ThreadCreate(&s_cmd_ping_arg_handle[handle]->ping_thread,
|
||
|
"ping thread",
|
||
|
ping_thread_fun,
|
||
|
(void *)handle,
|
||
|
OS_PRIORITY_NORMAL,
|
||
|
1 * 1024);
|
||
|
if (ret != OS_OK)
|
||
|
return -1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int ping_handle_stop(int handle)
|
||
|
{
|
||
|
if (handle < 0 || handle >= PING_ARG_HANDLE_MAX)
|
||
|
return -1;
|
||
|
|
||
|
if (s_cmd_ping_arg_handle[handle])
|
||
|
s_cmd_ping_arg_handle[handle]->ping_arg.run_flag = 0;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int ping_parse_argv(int argc, char *argv[])
|
||
|
{
|
||
|
int temp = 0;
|
||
|
int handle = -1;
|
||
|
struct ping_data ping_data_t;
|
||
|
int opt = 0;
|
||
|
char *short_opts = "c:i:s:W:w:t:e:";
|
||
|
memset(&ping_data_t, 0, sizeof(ping_data_t));
|
||
|
|
||
|
/* set default value */
|
||
|
ping_data_t.count = CMD_PING_DEFAULT_COUNT;
|
||
|
ping_data_t.data_long = CMD_PING_DEFAULT_DATA_LONG;
|
||
|
ping_data_t.interval = CMD_PING_DEFAULT_INTERVAL;
|
||
|
ping_data_t.timeout = CMD_PING_DEFAULT_TIMEOUT;
|
||
|
|
||
|
opterr = 0; /* close the "invalid option" warning */
|
||
|
while ((opt = getopt(argc, argv, short_opts)) != -1) {
|
||
|
//printf("optind:%d\t opt:%c\t optarg:%s\t argv[optind]:%s\n", optind, opt, optarg, argv[optind]);
|
||
|
switch (opt) {
|
||
|
case 'c':
|
||
|
temp = atoi(optarg);
|
||
|
ping_data_t.count = temp > 0 ? temp : CMD_PING_DEFAULT_COUNT;
|
||
|
break;
|
||
|
case 'i':
|
||
|
temp = atoi(optarg);
|
||
|
ping_data_t.interval = temp > 0 ? temp : CMD_PING_DEFAULT_INTERVAL;
|
||
|
break;
|
||
|
case 's':
|
||
|
ping_data_t.data_long = (uint32_t)atoi(optarg);
|
||
|
if (ping_data_t.data_long > 65500)
|
||
|
ping_data_t.data_long = 65500;
|
||
|
break;
|
||
|
case 'W':
|
||
|
temp = atoi(optarg);
|
||
|
ping_data_t.timeout = temp > 0 ? temp : CMD_PING_DEFAULT_TIMEOUT;
|
||
|
break;
|
||
|
case 'w':
|
||
|
temp = atoi(optarg);
|
||
|
ping_data_t.deadline = temp > 0 ? temp : 1;
|
||
|
break;
|
||
|
case 't':
|
||
|
temp = atoi(optarg);
|
||
|
ping_data_t.ttl = temp > 0 && temp < 255 ? temp : 255;
|
||
|
break;
|
||
|
case 'e':
|
||
|
temp = atoi(optarg);
|
||
|
ping_handle_stop(temp);
|
||
|
goto exit;
|
||
|
break;
|
||
|
case '?':
|
||
|
printf("invalid option -- '%s'\n", argv[optind - 1]);
|
||
|
goto exit;
|
||
|
break;
|
||
|
default:
|
||
|
goto exit;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (optind >= argc) {
|
||
|
printf("err: no destination!\n");
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
struct hostent *host_entry;
|
||
|
unsigned int address = 0;
|
||
|
host_entry = gethostbyname(argv[optind]);
|
||
|
if (host_entry) {
|
||
|
address = *((u_long *)host_entry->h_addr_list[0]);
|
||
|
} else {
|
||
|
printf("invalid ping host.\n");
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_LWIP_V1
|
||
|
ip4_addr_set_u32(&ping_data_t.sin_addr, address);
|
||
|
#elif LWIP_IPV4 /* now only for IPv4 */
|
||
|
ip_addr_set_ip4_u32(&ping_data_t.sin_addr, address);
|
||
|
#else
|
||
|
#error "IPv4 not support!"
|
||
|
#endif
|
||
|
|
||
|
handle = ping_handle_new(&ping_data_t);
|
||
|
if (handle >= 0)
|
||
|
ping_handle_start(handle);
|
||
|
|
||
|
exit:
|
||
|
optind = 1; /* reset the index, optind must be 1, the first arg is argv[1] */
|
||
|
|
||
|
return handle >= 0 ? 0 : -1;
|
||
|
}
|
||
|
|
||
|
static enum cmd_status cmd_ping_help_exec(char *cmd)
|
||
|
{
|
||
|
#if CMD_DESCRIBE
|
||
|
CMD_LOG(1, "%s\n", ping_help_info);
|
||
|
#endif
|
||
|
return CMD_STATUS_ACKED;
|
||
|
}
|
||
|
|
||
|
enum cmd_status cmd_ping_exec(char *cmd)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
int argc;
|
||
|
char *argv[20];
|
||
|
struct ping_data pdata;
|
||
|
memset((void *)&pdata, 0, sizeof(pdata));
|
||
|
|
||
|
if (cmd_strcmp(cmd, "help") == 0 || cmd_strcmp(cmd, "-h") == 0) {
|
||
|
cmd_ping_help_exec(cmd);
|
||
|
return CMD_STATUS_ACKED;
|
||
|
}
|
||
|
|
||
|
argc = cmd_parse_argv(cmd, &argv[1], cmd_nitems(argv) - 1);
|
||
|
argv[0] = "ping";
|
||
|
|
||
|
ret = ping_parse_argv(argc + 1, argv);
|
||
|
|
||
|
if (ret != 0)
|
||
|
return CMD_STATUS_FAIL;
|
||
|
else
|
||
|
return CMD_STATUS_OK;
|
||
|
}
|
||
|
|
||
|
#endif /* PRJCONF_NET_EN */
|