Browse Source

[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>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
1c34ca70d1
5 changed files with 51 additions and 7 deletions
  1. 37
    2
      src/core/pinger.c
  2. 6
    1
      src/hci/commands/ping_cmd.c
  3. 1
    0
      src/include/ipxe/pinger.h
  4. 2
    1
      src/include/usr/pingmgmt.h
  5. 5
    3
      src/usr/pingmgmt.c

+ 37
- 2
src/core/pinger.c View File

@@ -70,6 +70,10 @@ struct pinger {
70 70
 	uint16_t sequence;
71 71
 	/** Response for current sequence number is still pending */
72 72
 	int pending;
73
+	/** Number of remaining expiry events (zero to continue indefinitely) */
74
+	unsigned int remaining;
75
+	/** Return status */
76
+	int rc;
73 77
 
74 78
 	/** Callback function
75 79
 	 *
@@ -164,7 +168,12 @@ static void pinger_expired ( struct retry_timer *timer, int over __unused ) {
164 168
 	/* If no response has been received, notify the callback function */
165 169
 	if ( pinger->pending )
166 170
 		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
+	}
168 177
 
169 178
 	/* Increase sequence number */
170 179
 	pinger->sequence++;
@@ -173,6 +182,7 @@ static void pinger_expired ( struct retry_timer *timer, int over __unused ) {
173 182
 	 * case the transmission attempt fails.
174 183
 	 */
175 184
 	start_timer_fixed ( &pinger->timer, pinger->timeout );
185
+	pinger->pending = 1;
176 186
 
177 187
 	/* Allocate I/O buffer */
178 188
 	iobuf = xfer_alloc_iob ( &pinger->xfer, pinger->len );
@@ -210,6 +220,7 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf,
210 220
 			    struct xfer_metadata *meta ) {
211 221
 	size_t len = iob_len ( iobuf );
212 222
 	uint16_t sequence = meta->offset;
223
+	int terminate = 0;
213 224
 	int rc;
214 225
 
215 226
 	/* Clear response pending flag, if applicable */
@@ -218,18 +229,35 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf,
218 229
 
219 230
 	/* Check for errors */
220 231
 	if ( len != pinger->len ) {
232
+		/* Incorrect length: terminate immediately if we are
233
+		 * not pinging indefinitely.
234
+		 */
221 235
 		DBGC ( pinger, "PINGER %p received incorrect length %zd "
222 236
 		       "(expected %zd)\n", pinger, len, pinger->len );
223 237
 		rc = -EPROTO_LEN;
238
+		terminate = ( pinger->remaining != 0 );
224 239
 	} else if ( ( rc = pinger_verify ( pinger, iobuf->data ) ) != 0 ) {
240
+		/* Incorrect data: terminate immediately if we are not
241
+		 * pinging indefinitely.
242
+		 */
225 243
 		DBGC ( pinger, "PINGER %p received incorrect data:\n", pinger );
226 244
 		DBGC_HDA ( pinger, 0, iobuf->data, iob_len ( iobuf ) );
245
+		terminate = ( pinger->remaining != 0 );
227 246
 	} else if ( sequence != pinger->sequence ) {
247
+		/* Incorrect sequence number (probably a delayed response):
248
+		 * report via callback but otherwise ignore.
249
+		 */
228 250
 		DBGC ( pinger, "PINGER %p received sequence %d (expected %d)\n",
229 251
 		       pinger, sequence, pinger->sequence );
230 252
 		rc = -EPROTO_SEQ;
253
+		terminate = 0;
231 254
 	} else {
255
+		/* Success: record that a packet was successfully received,
256
+		 * and terminate if we expect to send no further packets.
257
+		 */
232 258
 		rc = 0;
259
+		pinger->rc = 0;
260
+		terminate = ( pinger->remaining == 1 );
233 261
 	}
234 262
 
235 263
 	/* Discard I/O buffer */
@@ -238,6 +266,10 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf,
238 266
 	/* Notify callback function */
239 267
 	pinger->callback ( meta->src, sequence, len, rc );
240 268
 
269
+	/* Terminate if applicable */
270
+	if ( terminate )
271
+		pinger_close ( pinger, rc );
272
+
241 273
 	return rc;
242 274
 }
243 275
 
@@ -268,10 +300,11 @@ static struct interface_descriptor pinger_job_desc =
268 300
  * @v hostname		Hostname to ping
269 301
  * @v timeout		Timeout (in ticks)
270 302
  * @v len		Payload length
303
+ * @v count		Number of packets to send (or zero for no limit)
271 304
  * @ret rc		Return status code
272 305
  */
273 306
 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,
275 308
 		    void ( * callback ) ( struct sockaddr *src,
276 309
 					  unsigned int sequence, size_t len,
277 310
 					  int rc ) ) {
@@ -292,7 +325,9 @@ int create_pinger ( struct interface *job, const char *hostname,
292 325
 	timer_init ( &pinger->timer, pinger_expired, &pinger->refcnt );
293 326
 	pinger->timeout = timeout;
294 327
 	pinger->len = len;
328
+	pinger->remaining = ( count ? ( count + 1 /* Initial packet */ ) : 0 );
295 329
 	pinger->callback = callback;
330
+	pinger->rc = -ETIMEDOUT;
296 331
 
297 332
 	/* Open socket */
298 333
 	if ( ( rc = xfer_open_named_socket ( &pinger->xfer, SOCK_ECHO, NULL,

+ 6
- 1
src/hci/commands/ping_cmd.c View File

@@ -48,6 +48,8 @@ struct ping_options {
48 48
 	unsigned int size;
49 49
 	/** Timeout (in ms) */
50 50
 	unsigned long timeout;
51
+	/** Number of packets to send (or zero for no limit) */
52
+	unsigned int count;
51 53
 };
52 54
 
53 55
 /** "ping" option list */
@@ -56,6 +58,8 @@ static struct option_descriptor ping_opts[] = {
56 58
 		      struct ping_options, size, parse_integer ),
57 59
 	OPTION_DESC ( "timeout", 't', required_argument,
58 60
 		      struct ping_options, timeout, parse_timeout ),
61
+	OPTION_DESC ( "count", 'c', required_argument,
62
+		      struct ping_options, count, parse_integer ),
59 63
 };
60 64
 
61 65
 /** "ping" command descriptor */
@@ -87,7 +91,8 @@ static int ping_exec ( int argc, char **argv ) {
87 91
 	hostname = argv[optind];
88 92
 
89 93
 	/* Ping */
90
-	if ( ( rc = ping ( hostname, opts.timeout, opts.size ) ) != 0 )
94
+	if ( ( rc = ping ( hostname, opts.timeout, opts.size,
95
+			   opts.count ) ) != 0 )
91 96
 		return rc;
92 97
 
93 98
 	return 0;

+ 1
- 0
src/include/ipxe/pinger.h View File

@@ -15,6 +15,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
15 15
 
16 16
 extern int create_pinger ( struct interface *job, const char *hostname,
17 17
 			   unsigned long timeout, size_t len,
18
+			   unsigned int count,
18 19
 			   void ( * callback ) ( struct sockaddr *peer,
19 20
 						 unsigned int sequence,
20 21
 						 size_t len,

+ 2
- 1
src/include/usr/pingmgmt.h View File

@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
11 11
 
12 12
 #include <stdint.h>
13 13
 
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 );
15 16
 
16 17
 #endif /* _USR_PINGMGMT_H */

+ 5
- 3
src/usr/pingmgmt.c View File

@@ -58,14 +58,16 @@ static void ping_callback ( struct sockaddr *peer, unsigned int sequence,
58 58
  * @v hostname		Hostname
59 59
  * @v timeout		Timeout between pings, in ticks
60 60
  * @v len		Payload length
61
+ * @v count		Number of packets to send (or zero for no limit)
61 62
  * @ret rc		Return status code
62 63
  */
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 ) {
64 66
 	int rc;
65 67
 
66 68
 	/* 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 ) {
69 71
 		printf ( "Could not start ping: %s\n", strerror ( rc ) );
70 72
 		return rc;
71 73
 	}

Loading…
Cancel
Save