github.com/amazechain/amc@v0.1.3/internal/sync/error.go (about) 1 package sync 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "github.com/amazechain/amc/internal/p2p" 8 "github.com/amazechain/amc/internal/p2p/encoder" 9 p2ptypes "github.com/amazechain/amc/internal/p2p/types" 10 "github.com/amazechain/amc/log" 11 12 libp2pcore "github.com/libp2p/go-libp2p/core" 13 "github.com/libp2p/go-libp2p/core/network" 14 ) 15 16 var responseCodeSuccess = byte(0x00) 17 var responseCodeInvalidRequest = byte(0x01) 18 var responseCodeServerError = byte(0x02) 19 20 func (s *Service) generateErrorResponse(code byte, reason string) ([]byte, error) { 21 return createErrorResponse(code, reason, s.cfg.p2p) 22 } 23 24 // ReadStatusCode response from a RPC stream. 25 func ReadStatusCode(stream network.Stream, encoding encoder.NetworkEncoding) (uint8, string, error) { 26 // Set ttfb deadline. 27 SetStreamReadDeadline(stream, ttfbTimeout) 28 b := make([]byte, 1) 29 _, err := stream.Read(b) 30 if err != nil { 31 return 0, "", err 32 } 33 34 if b[0] == responseCodeSuccess { 35 // Set response deadline on a successful response code. 36 SetStreamReadDeadline(stream, respTimeout) 37 38 return 0, "", nil 39 } 40 41 // Set response deadline, when reading error message. 42 SetStreamReadDeadline(stream, respTimeout) 43 msg := &p2ptypes.ErrorMessage{} 44 if err := encoding.DecodeWithMaxLength(stream, msg); err != nil { 45 return 0, "", err 46 } 47 48 return b[0], string(*msg), nil 49 } 50 51 func writeErrorResponseToStream(responseCode byte, reason string, stream libp2pcore.Stream, encoder p2p.EncodingProvider) { 52 resp, err := createErrorResponse(responseCode, reason, encoder) 53 if err != nil { 54 log.Debug("Could not generate a response error", "err", err) 55 } else if _, err := stream.Write(resp); err != nil { 56 log.Debug("Could not write to stream", "err", err) 57 } else { 58 // If sending the error message succeeded, close to send an EOF. 59 closeStream(stream) 60 } 61 } 62 63 func createErrorResponse(code byte, reason string, encoder p2p.EncodingProvider) ([]byte, error) { 64 buf := bytes.NewBuffer([]byte{code}) 65 errMsg := p2ptypes.ErrorMessage(reason) 66 if _, err := encoder.Encoding().EncodeWithMaxLength(buf, &errMsg); err != nil { 67 return nil, err 68 } 69 70 return buf.Bytes(), nil 71 } 72 73 // reads data from the stream without applying any timeouts. 74 func readStatusCodeNoDeadline(stream network.Stream, encoding encoder.NetworkEncoding) (uint8, string, error) { 75 b := make([]byte, 1) 76 _, err := stream.Read(b) 77 if err != nil { 78 return 0, "", err 79 } 80 81 if b[0] == responseCodeSuccess { 82 return 0, "", nil 83 } 84 85 msg := &p2ptypes.ErrorMessage{} 86 if err := encoding.DecodeWithMaxLength(stream, msg); err != nil { 87 return 0, "", err 88 } 89 90 return b[0], string(*msg), nil 91 } 92 93 // only returns true for errors that are valid (no resets or expectedEOF errors). 94 func isValidStreamError(err error) bool { 95 // check the error message itself as well as libp2p doesn't currently 96 // return the correct error type from Close{Read,Write,}. 97 return err != nil && !errors.Is(err, network.ErrReset) && err.Error() != network.ErrReset.Error() 98 } 99 100 func closeStream(stream network.Stream) { 101 if err := stream.Close(); isValidStreamError(err) { 102 log.Debug(fmt.Sprintf("Could not reset stream with protocol %s", stream.Protocol()), "err", err) 103 } 104 } 105 106 func closeStreamAndWait(stream network.Stream) { 107 if err := stream.CloseWrite(); err != nil { 108 _err := stream.Reset() 109 _ = _err 110 if isValidStreamError(err) { 111 log.Debug(fmt.Sprintf("Could not reset stream with protocol %s", stream.Protocol()), "err", err) 112 } 113 return 114 } 115 // Wait for the remote side to respond. 116 // 117 // 1. On success, we expect to read an EOF (remote side received our 118 // response and closed the stream. 119 // 2. On failure (e.g., disconnect), we expect to receive an error. 120 // 3. If the remote side misbehaves, we may receive data. 121 // 122 // However, regardless of what happens, we just close the stream and 123 // walk away. We only read to wait for a response, we close regardless. 124 _, _err := stream.Read([]byte{0}) 125 _ = _err 126 _err = stream.Close() 127 _ = _err 128 }