Skip to content

Commit 1c34ca7

Browse files
committed
[ping] Allow termination after a specified number of packets
Add the "-c <count>" option to the "ping" command, allowing for automatic termination after a specified number of packets. When a number of packets is specified: - if a serious error (i.e. length mismatch or content mismatch) occurs, then the ping will be immediately terminated with the relevant status code; - if at least one response is received successfully, and all errors are non-serious (i.e. timeouts or out-of-sequence responses), then the ping will be terminated after the final response (or timeout) with a success status; - if no responses are received successfully, then the ping will be terminated after the final timeout with ETIMEDOUT. If no number of packets is specified, then the ping will continue until manually interrupted. Originally-implemented-by: Cedric Levasseur <cyr-ius@ipocus.net> Signed-off-by: Michael Brown <mcb30@ipxe.org>
1 parent d1afe73 commit 1c34ca7

File tree

5 files changed

+51
-7
lines changed

5 files changed

+51
-7
lines changed

src/core/pinger.c

+37-2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ struct pinger {
7070
uint16_t sequence;
7171
/** Response for current sequence number is still pending */
7272
int pending;
73+
/** Number of remaining expiry events (zero to continue indefinitely) */
74+
unsigned int remaining;
75+
/** Return status */
76+
int rc;
7377

7478
/** Callback function
7579
*
@@ -164,7 +168,12 @@ static void pinger_expired ( struct retry_timer *timer, int over __unused ) {
164168
/* If no response has been received, notify the callback function */
165169
if ( pinger->pending )
166170
pinger->callback ( NULL, pinger->sequence, 0, -ETIMEDOUT );
167-
pinger->pending = 1;
171+
172+
/* Check for termination */
173+
if ( pinger->remaining && ( --pinger->remaining == 0 ) ) {
174+
pinger_close ( pinger, pinger->rc );
175+
return;
176+
}
168177

169178
/* Increase sequence number */
170179
pinger->sequence++;
@@ -173,6 +182,7 @@ static void pinger_expired ( struct retry_timer *timer, int over __unused ) {
173182
* case the transmission attempt fails.
174183
*/
175184
start_timer_fixed ( &pinger->timer, pinger->timeout );
185+
pinger->pending = 1;
176186

177187
/* Allocate I/O buffer */
178188
iobuf = xfer_alloc_iob ( &pinger->xfer, pinger->len );
@@ -210,6 +220,7 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf,
210220
struct xfer_metadata *meta ) {
211221
size_t len = iob_len ( iobuf );
212222
uint16_t sequence = meta->offset;
223+
int terminate = 0;
213224
int rc;
214225

215226
/* Clear response pending flag, if applicable */
@@ -218,18 +229,35 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf,
218229

219230
/* Check for errors */
220231
if ( len != pinger->len ) {
232+
/* Incorrect length: terminate immediately if we are
233+
* not pinging indefinitely.
234+
*/
221235
DBGC ( pinger, "PINGER %p received incorrect length %zd "
222236
"(expected %zd)\n", pinger, len, pinger->len );
223237
rc = -EPROTO_LEN;
238+
terminate = ( pinger->remaining != 0 );
224239
} else if ( ( rc = pinger_verify ( pinger, iobuf->data ) ) != 0 ) {
240+
/* Incorrect data: terminate immediately if we are not
241+
* pinging indefinitely.
242+
*/
225243
DBGC ( pinger, "PINGER %p received incorrect data:\n", pinger );
226244
DBGC_HDA ( pinger, 0, iobuf->data, iob_len ( iobuf ) );
245+
terminate = ( pinger->remaining != 0 );
227246
} else if ( sequence != pinger->sequence ) {
247+
/* Incorrect sequence number (probably a delayed response):
248+
* report via callback but otherwise ignore.
249+
*/
228250
DBGC ( pinger, "PINGER %p received sequence %d (expected %d)\n",
229251
pinger, sequence, pinger->sequence );
230252
rc = -EPROTO_SEQ;
253+
terminate = 0;
231254
} else {
255+
/* Success: record that a packet was successfully received,
256+
* and terminate if we expect to send no further packets.
257+
*/
232258
rc = 0;
259+
pinger->rc = 0;
260+
terminate = ( pinger->remaining == 1 );
233261
}
234262

235263
/* Discard I/O buffer */
@@ -238,6 +266,10 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf,
238266
/* Notify callback function */
239267
pinger->callback ( meta->src, sequence, len, rc );
240268

269+
/* Terminate if applicable */
270+
if ( terminate )
271+
pinger_close ( pinger, rc );
272+
241273
return rc;
242274
}
243275

@@ -268,10 +300,11 @@ static struct interface_descriptor pinger_job_desc =
268300
* @v hostname Hostname to ping
269301
* @v timeout Timeout (in ticks)
270302
* @v len Payload length
303+
* @v count Number of packets to send (or zero for no limit)
271304
* @ret rc Return status code
272305
*/
273306
int create_pinger ( struct interface *job, const char *hostname,
274-
unsigned long timeout, size_t len,
307+
unsigned long timeout, size_t len, unsigned int count,
275308
void ( * callback ) ( struct sockaddr *src,
276309
unsigned int sequence, size_t len,
277310
int rc ) ) {
@@ -292,7 +325,9 @@ int create_pinger ( struct interface *job, const char *hostname,
292325
timer_init ( &pinger->timer, pinger_expired, &pinger->refcnt );
293326
pinger->timeout = timeout;
294327
pinger->len = len;
328+
pinger->remaining = ( count ? ( count + 1 /* Initial packet */ ) : 0 );
295329
pinger->callback = callback;
330+
pinger->rc = -ETIMEDOUT;
296331

297332
/* Open socket */
298333
if ( ( rc = xfer_open_named_socket ( &pinger->xfer, SOCK_ECHO, NULL,

src/hci/commands/ping_cmd.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ struct ping_options {
4848
unsigned int size;
4949
/** Timeout (in ms) */
5050
unsigned long timeout;
51+
/** Number of packets to send (or zero for no limit) */
52+
unsigned int count;
5153
};
5254

5355
/** "ping" option list */
@@ -56,6 +58,8 @@ static struct option_descriptor ping_opts[] = {
5658
struct ping_options, size, parse_integer ),
5759
OPTION_DESC ( "timeout", 't', required_argument,
5860
struct ping_options, timeout, parse_timeout ),
61+
OPTION_DESC ( "count", 'c', required_argument,
62+
struct ping_options, count, parse_integer ),
5963
};
6064

6165
/** "ping" command descriptor */
@@ -87,7 +91,8 @@ static int ping_exec ( int argc, char **argv ) {
8791
hostname = argv[optind];
8892

8993
/* Ping */
90-
if ( ( rc = ping ( hostname, opts.timeout, opts.size ) ) != 0 )
94+
if ( ( rc = ping ( hostname, opts.timeout, opts.size,
95+
opts.count ) ) != 0 )
9196
return rc;
9297

9398
return 0;

src/include/ipxe/pinger.h

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
1515

1616
extern int create_pinger ( struct interface *job, const char *hostname,
1717
unsigned long timeout, size_t len,
18+
unsigned int count,
1819
void ( * callback ) ( struct sockaddr *peer,
1920
unsigned int sequence,
2021
size_t len,

src/include/usr/pingmgmt.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
1111

1212
#include <stdint.h>
1313

14-
extern int ping ( const char *hostname, unsigned long timeout, size_t len );
14+
extern int ping ( const char *hostname, unsigned long timeout, size_t len,
15+
unsigned int count );
1516

1617
#endif /* _USR_PINGMGMT_H */

src/usr/pingmgmt.c

+5-3
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,16 @@ static void ping_callback ( struct sockaddr *peer, unsigned int sequence,
5858
* @v hostname Hostname
5959
* @v timeout Timeout between pings, in ticks
6060
* @v len Payload length
61+
* @v count Number of packets to send (or zero for no limit)
6162
* @ret rc Return status code
6263
*/
63-
int ping ( const char *hostname, unsigned long timeout, size_t len ) {
64+
int ping ( const char *hostname, unsigned long timeout, size_t len,
65+
unsigned int count ) {
6466
int rc;
6567

6668
/* Create pinger */
67-
if ( ( rc = create_pinger ( &monojob, hostname, timeout,
68-
len, ping_callback ) ) != 0 ) {
69+
if ( ( rc = create_pinger ( &monojob, hostname, timeout, len,
70+
count, ping_callback ) ) != 0 ) {
6971
printf ( "Could not start ping: %s\n", strerror ( rc ) );
7072
return rc;
7173
}

0 commit comments

Comments
 (0)