From 9489659890d05d6e2e526033d4cc2064ce247706 Mon Sep 17 00:00:00 2001 From: Zhe Weng Date: Tue, 14 Nov 2023 16:26:48 +0800 Subject: [PATCH] netutils/ping: Optimize stack usage of `icmp_ping` Can reduce 88~144 Bytes on ARMv7-A depending on optimization level. Signed-off-by: Zhe Weng --- netutils/ping/icmp_ping.c | 156 +++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 71 deletions(-) diff --git a/netutils/ping/icmp_ping.c b/netutils/ping/icmp_ping.c index b02c6e148..f13ca3aaf 100644 --- a/netutils/ping/icmp_ping.c +++ b/netutils/ping/icmp_ping.c @@ -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 ****************************************************************************/ @@ -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; } @@ -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; @@ -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); @@ -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 */ @@ -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; + priv->retry = false; + priv->recvfd.fd = priv->sockfd; + priv->recvfd.events = POLLIN; + priv->recvfd.revents = 0; - recvfd.fd = sockfd; - recvfd.events = POLLIN; - 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); @@ -296,22 +309,24 @@ 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) { @@ -319,7 +334,7 @@ void icmp_ping(FAR const struct ping_info_s *info) if (ntohs(inhdr->id) != result.id) { icmp_callback(&result, ICMP_W_IDDIFF, ntohs(inhdr->id)); - retry = true; + priv->retry = true; } else #endif @@ -327,26 +342,25 @@ void icmp_ping(FAR const struct ping_info_s *info) { 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 @@ -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; @@ -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); }