Request sends an ICMP echo request and wait for a reply or timeout. The async version of Win32 APIs take a callback whose memory is not garbage collected, so we use the synchronous version. It's possible that a slow request will block other requests, so we set the timeout to only 1s.
(ctx context.Context, pk *packet.ICMP, responder ICMPResponder)
| 260 | // The async version of Win32 APIs take a callback whose memory is not garbage collected, so we use the synchronous version. |
| 261 | // It's possible that a slow request will block other requests, so we set the timeout to only 1s. |
| 262 | func (ip *icmpProxy) Request(ctx context.Context, pk *packet.ICMP, responder ICMPResponder) error { |
| 263 | defer func() { |
| 264 | if r := recover(); r != nil { |
| 265 | ip.logger.Error().Interface("error", r).Msgf("Recover panic from sending icmp request/response, error %s", debug.Stack()) |
| 266 | } |
| 267 | }() |
| 268 | |
| 269 | _, requestSpan := responder.RequestSpan(ctx, pk) |
| 270 | defer responder.ExportSpan() |
| 271 | |
| 272 | echo, err := getICMPEcho(pk.Message) |
| 273 | if err != nil { |
| 274 | return err |
| 275 | } |
| 276 | observeICMPRequest(ip.logger, requestSpan, pk.Src.String(), pk.Dst.String(), echo.ID, echo.Seq) |
| 277 | |
| 278 | resp, err := ip.icmpEchoRoundtrip(pk.Dst, echo) |
| 279 | if err != nil { |
| 280 | ip.logger.Err(err).Msg("ICMP echo roundtrip failed") |
| 281 | tracing.EndWithErrorStatus(requestSpan, err) |
| 282 | return err |
| 283 | } |
| 284 | tracing.End(requestSpan) |
| 285 | responder.ExportSpan() |
| 286 | |
| 287 | _, replySpan := responder.ReplySpan(ctx, ip.logger) |
| 288 | err = ip.handleEchoReply(pk, echo, resp, responder) |
| 289 | if err != nil { |
| 290 | ip.logger.Err(err).Msg("Failed to send ICMP reply") |
| 291 | tracing.EndWithErrorStatus(replySpan, err) |
| 292 | return errors.Wrap(err, "failed to handle ICMP echo reply") |
| 293 | } |
| 294 | observeICMPReply(ip.logger, replySpan, pk.Dst.String(), echo.ID, echo.Seq) |
| 295 | replySpan.SetAttributes( |
| 296 | attribute.Int64("rtt", int64(resp.rtt())), |
| 297 | attribute.String("status", resp.status().String()), |
| 298 | ) |
| 299 | tracing.End(replySpan) |
| 300 | return nil |
| 301 | } |
| 302 | |
| 303 | func (ip *icmpProxy) handleEchoReply(request *packet.ICMP, echoReq *icmp.Echo, resp echoResp, responder ICMPResponder) error { |
| 304 | var replyType icmp.Type |
nothing calls this directly
no test coverage detected