|
@@ -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,
|