Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

netutils/ping: Optimize stack usage of icmp_ping #2248

Merged
merged 1 commit into from
Jan 2, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 85 additions & 71 deletions netutils/ping/icmp_ping.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,28 @@

#define ICMP_IOBUFFER_SIZE(x) (sizeof(struct icmp_hdr_s) + (x))

/****************************************************************************
* Private Types
****************************************************************************/

/* Data needed for ping, reduce stack usage. */

struct ping_priv_s
{
struct sockaddr_in destaddr;
struct sockaddr_in fromaddr;
struct icmp_hdr_s outhdr;
struct pollfd recvfd;
socklen_t addrlen;
clock_t kickoff;
clock_t start;
ssize_t nsent;
ssize_t nrecvd;
long elapsed;
bool retry;
int sockfd;
};

/****************************************************************************
* Private Data
****************************************************************************/
Expand Down Expand Up @@ -107,14 +129,14 @@ static int ping_gethostip(FAR const char *hostname, FAR struct in_addr *dest)
#ifdef CONFIG_LIBC_NETDB
/* Netdb DNS client support is enabled */

FAR struct addrinfo hint;
FAR struct addrinfo *info;
FAR struct sockaddr_in *addr;
static const struct addrinfo s_hint =
{
.ai_family = AF_INET
};

memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_INET;

if (getaddrinfo(hostname, NULL, &hint, &info) != OK)
if (getaddrinfo(hostname, NULL, &s_hint, &info) != OK)
{
return ERROR;
}
Expand Down Expand Up @@ -166,21 +188,10 @@ static void icmp_callback(FAR struct ping_result_s *result,
void icmp_ping(FAR const struct ping_info_s *info)
{
struct ping_result_s result;
struct sockaddr_in destaddr;
struct sockaddr_in fromaddr;
struct icmp_hdr_s outhdr;
FAR struct ping_priv_s *priv;
FAR struct icmp_hdr_s *inhdr;
struct pollfd recvfd;
FAR uint8_t *iobuffer;
FAR uint8_t *ptr;
long elapsed;
clock_t kickoff;
clock_t start;
socklen_t addrlen;
ssize_t nsent;
ssize_t nrecvd;
bool retry;
int sockfd;
int ret;
int ch;
int i;
Expand All @@ -200,34 +211,36 @@ void icmp_ping(FAR const struct ping_info_s *info)
return;
}

/* Allocate memory to hold ping buffer */
/* Allocate memory to hold private data and ping buffer */

iobuffer = (FAR uint8_t *)malloc(result.outsize);
if (iobuffer == NULL)
priv = malloc(sizeof(*priv) + result.outsize);
if (priv == NULL)
{
icmp_callback(&result, ICMP_E_MEMORY, 0);
return;
}

sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (sockfd < 0)
iobuffer = (FAR uint8_t *)(priv + 1);

priv->sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (priv->sockfd < 0)
{
icmp_callback(&result, ICMP_E_SOCKET, errno);
free(iobuffer);
free(priv);
return;
}

kickoff = clock();
priv->kickoff = clock();

memset(&destaddr, 0, sizeof(struct sockaddr_in));
destaddr.sin_family = AF_INET;
destaddr.sin_port = 0;
destaddr.sin_addr.s_addr = result.dest.s_addr;
memset(&priv->destaddr, 0, sizeof(struct sockaddr_in));
priv->destaddr.sin_family = AF_INET;
priv->destaddr.sin_port = 0;
priv->destaddr.sin_addr.s_addr = result.dest.s_addr;

memset(&outhdr, 0, sizeof(struct icmp_hdr_s));
outhdr.type = ICMP_ECHO_REQUEST;
outhdr.id = htons(result.id);
outhdr.seqno = htons(result.seqno);
memset(&priv->outhdr, 0, sizeof(struct icmp_hdr_s));
priv->outhdr.type = ICMP_ECHO_REQUEST;
priv->outhdr.id = htons(result.id);
priv->outhdr.seqno = htons(result.seqno);

icmp_callback(&result, ICMP_I_BEGIN, 0);

Expand All @@ -240,7 +253,7 @@ void icmp_ping(FAR const struct ping_info_s *info)

/* Copy the ICMP header into the I/O buffer */

memcpy(iobuffer, &outhdr, sizeof(struct icmp_hdr_s));
memcpy(iobuffer, &priv->outhdr, sizeof(struct icmp_hdr_s));

/* Add some easily verifiable payload data */

Expand All @@ -256,33 +269,33 @@ void icmp_ping(FAR const struct ping_info_s *info)
}
}

start = clock();
nsent = sendto(sockfd, iobuffer, result.outsize, 0,
(FAR struct sockaddr *)&destaddr,
sizeof(struct sockaddr_in));
if (nsent < 0)
priv->start = clock();
priv->nsent = sendto(priv->sockfd, iobuffer, result.outsize, 0,
(FAR struct sockaddr *)&priv->destaddr,
sizeof(struct sockaddr_in));
if (priv->nsent < 0)
{
icmp_callback(&result, ICMP_E_SENDTO, errno);
goto done;
}
else if (nsent != result.outsize)
else if (priv->nsent != result.outsize)
{
icmp_callback(&result, ICMP_E_SENDSMALL, nsent);
icmp_callback(&result, ICMP_E_SENDSMALL, priv->nsent);
goto done;
}

result.nrequests++;

elapsed = 0;
priv->elapsed = 0;
do
{
retry = false;

recvfd.fd = sockfd;
recvfd.events = POLLIN;
recvfd.revents = 0;
priv->retry = false;
priv->recvfd.fd = priv->sockfd;
priv->recvfd.events = POLLIN;
priv->recvfd.revents = 0;

ret = poll(&recvfd, 1, info->timeout - elapsed / USEC_PER_MSEC);
ret = poll(&priv->recvfd, 1,
info->timeout - priv->elapsed / USEC_PER_MSEC);
if (ret < 0)
{
icmp_callback(&result, ICMP_E_POLL, errno);
Expand All @@ -296,57 +309,58 @@ void icmp_ping(FAR const struct ping_info_s *info)

/* Get the ICMP response (ignoring the sender) */

addrlen = sizeof(struct sockaddr_in);
nrecvd = recvfrom(sockfd, iobuffer, result.outsize, 0,
(FAR struct sockaddr *)&fromaddr, &addrlen);
if (nrecvd < 0)
priv->addrlen = sizeof(struct sockaddr_in);
priv->nrecvd = recvfrom(priv->sockfd, iobuffer,
result.outsize, 0,
(FAR struct sockaddr *)&priv->fromaddr,
&priv->addrlen);
if (priv->nrecvd < 0)
{
icmp_callback(&result, ICMP_E_RECVFROM, errno);
goto done;
}
else if (nrecvd < sizeof(struct icmp_hdr_s))
else if (priv->nrecvd < sizeof(struct icmp_hdr_s))
{
icmp_callback(&result, ICMP_E_RECVSMALL, nrecvd);
icmp_callback(&result, ICMP_E_RECVSMALL, priv->nrecvd);
goto done;
}

elapsed = TICK2USEC(clock() - start);
inhdr = (FAR struct icmp_hdr_s *)iobuffer;
priv->elapsed = TICK2USEC(clock() - priv->start);
inhdr = (FAR struct icmp_hdr_s *)iobuffer;

if (inhdr->type == ICMP_ECHO_REPLY)
{
#ifndef CONFIG_SIM_NETUSRSOCK
if (ntohs(inhdr->id) != result.id)
{
icmp_callback(&result, ICMP_W_IDDIFF, ntohs(inhdr->id));
retry = true;
priv->retry = true;
}
else
#endif
if (ntohs(inhdr->seqno) > result.seqno)
{
icmp_callback(&result, ICMP_W_SEQNOBIG,
ntohs(inhdr->seqno));
retry = true;
priv->retry = true;
}
else if (ntohs(inhdr->seqno) < result.seqno)
{
icmp_callback(&result, ICMP_W_SEQNOSMALL,
ntohs(inhdr->seqno));
retry = true;
priv->retry = true;
}
else
{
bool verified = true;
long pktdelay = elapsed;

icmp_callback(&result, ICMP_I_ROUNDTRIP, pktdelay);
icmp_callback(&result, ICMP_I_ROUNDTRIP, priv->elapsed);

/* Verify the payload data */

if (nrecvd != result.outsize)
if (priv->nrecvd != result.outsize)
{
icmp_callback(&result, ICMP_W_RECVBIG, nrecvd);
icmp_callback(&result, ICMP_W_RECVBIG, priv->nrecvd);
verified = false;
}
else
Expand Down Expand Up @@ -383,20 +397,20 @@ void icmp_ping(FAR const struct ping_info_s *info)
icmp_callback(&result, ICMP_W_TYPE, inhdr->type);
}
}
while (retry && info->delay > elapsed / USEC_PER_MSEC &&
info->timeout > elapsed / USEC_PER_MSEC);
while (priv->retry && info->delay > priv->elapsed / USEC_PER_MSEC &&
info->timeout > priv->elapsed / USEC_PER_MSEC);

/* Wait if necessary to preserved the requested ping rate */

elapsed = TICK2MSEC(clock() - start);
if (elapsed < info->delay)
priv->elapsed = TICK2MSEC(clock() - priv->start);
if (priv->elapsed < info->delay)
{
struct timespec rqt;
unsigned int remaining;
unsigned int sec;
unsigned int frac; /* In deciseconds */

remaining = info->delay - elapsed;
remaining = info->delay - priv->elapsed;
sec = remaining / MSEC_PER_SEC;
frac = remaining - MSEC_PER_SEC * sec;

Expand All @@ -406,11 +420,11 @@ void icmp_ping(FAR const struct ping_info_s *info)
nanosleep(&rqt, NULL);
}

outhdr.seqno = htons(++result.seqno);
priv->outhdr.seqno = htons(++result.seqno);
}

done:
icmp_callback(&result, ICMP_I_FINISH, TICK2USEC(clock() - kickoff));
close(sockfd);
free(iobuffer);
icmp_callback(&result, ICMP_I_FINISH, TICK2USEC(clock() - priv->kickoff));
close(priv->sockfd);
free(priv);
}
Loading