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

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

48
 	unsigned int size;
48
 	unsigned int size;
49
 	/** Timeout (in ms) */
49
 	/** Timeout (in ms) */
50
 	unsigned long timeout;
50
 	unsigned long timeout;
51
+	/** Number of packets to send (or zero for no limit) */
52
+	unsigned int count;
51
 };
53
 };
52
 
54
 
53
 /** "ping" option list */
55
 /** "ping" option list */
56
 		      struct ping_options, size, parse_integer ),
58
 		      struct ping_options, size, parse_integer ),
57
 	OPTION_DESC ( "timeout", 't', required_argument,
59
 	OPTION_DESC ( "timeout", 't', required_argument,
58
 		      struct ping_options, timeout, parse_timeout ),
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
 /** "ping" command descriptor */
65
 /** "ping" command descriptor */
87
 	hostname = argv[optind];
91
 	hostname = argv[optind];
88
 
92
 
89
 	/* Ping */
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
 		return rc;
96
 		return rc;
92
 
97
 
93
 	return 0;
98
 	return 0;

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

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

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

11
 
11
 
12
 #include <stdint.h>
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
 #endif /* _USR_PINGMGMT_H */
17
 #endif /* _USR_PINGMGMT_H */

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

58
  * @v hostname		Hostname
58
  * @v hostname		Hostname
59
  * @v timeout		Timeout between pings, in ticks
59
  * @v timeout		Timeout between pings, in ticks
60
  * @v len		Payload length
60
  * @v len		Payload length
61
+ * @v count		Number of packets to send (or zero for no limit)
61
  * @ret rc		Return status code
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
 	int rc;
66
 	int rc;
65
 
67
 
66
 	/* Create pinger */
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
 		printf ( "Could not start ping: %s\n", strerror ( rc ) );
71
 		printf ( "Could not start ping: %s\n", strerror ( rc ) );
70
 		return rc;
72
 		return rc;
71
 	}
73
 	}

Loading…
Cancel
Save