package network import ( "context" "errors" "fmt" "io" "net" "time" ) // ErrReset is returned when reading or writing on a reset stream. var ErrReset = errors.New("stream reset") type StreamErrorCode uint32 type StreamError struct { ErrorCode StreamErrorCode Remote bool TransportError error } func (s *StreamError) Error() string { side := "local" if s.Remote { side = "remote" } if s.TransportError != nil { return fmt.Sprintf("stream reset (%s): code: 0x%x: transport error: %s", side, s.ErrorCode, s.TransportError) } return fmt.Sprintf("stream reset (%s): code: 0x%x", side, s.ErrorCode) } func (s *StreamError) Is(target error) bool { if tse, ok := target.(*StreamError); ok { return tse.ErrorCode == s.ErrorCode && tse.Remote == s.Remote } return false } func (s *StreamError) Unwrap() []error { return []error{ErrReset, s.TransportError} } const ( StreamNoError StreamErrorCode = 0 StreamProtocolNegotiationFailed StreamErrorCode = 0x1001 StreamResourceLimitExceeded StreamErrorCode = 0x1002 StreamRateLimited StreamErrorCode = 0x1003 StreamProtocolViolation StreamErrorCode = 0x1004 StreamSupplanted StreamErrorCode = 0x1005 StreamGarbageCollected StreamErrorCode = 0x1006 StreamShutdown StreamErrorCode = 0x1007 StreamGated StreamErrorCode = 0x1008 StreamCodeOutOfRange StreamErrorCode = 0x1009 ) // MuxedStream is a bidirectional io pipe within a connection. type MuxedStream interface { io.Reader io.Writer // Close closes the stream. // // * Any buffered data for writing will be flushed. // * Future reads will fail. // * Any in-progress reads/writes will be interrupted. // // Close may be asynchronous and _does not_ guarantee receipt of the // data. // // Close closes the stream for both reading and writing. // Close is equivalent to calling `CloseRead` and `CloseWrite`. Importantly, Close will not wait for any form of acknowledgment. // If acknowledgment is required, the caller must call `CloseWrite`, then wait on the stream for a response (or an EOF), // then call Close() to free the stream object. // // When done with a stream, the user must call either Close() or `Reset()` to discard the stream, even after calling `CloseRead` and/or `CloseWrite`. io.Closer // CloseWrite closes the stream for writing but leaves it open for // reading. // // CloseWrite does not free the stream, users must still call Close or // Reset. CloseWrite() error // CloseRead closes the stream for reading but leaves it open for // writing. // // When CloseRead is called, all in-progress Read calls are interrupted with a non-EOF error and // no further calls to Read will succeed. // // The handling of new incoming data on the stream after calling this function is implementation defined. // // CloseRead does not free the stream, users must still call Close or // Reset. CloseRead() error // Reset closes both ends of the stream. Use this to tell the remote // side to hang up and go away. Reset() error // ResetWithError aborts both ends of the stream with `errCode`. `errCode` is sent // to the peer on a best effort basis. For transports that do not support sending // error codes to remote peer, the behavior is identical to calling Reset ResetWithError(errCode StreamErrorCode) error SetDeadline(time.Time) error SetReadDeadline(time.Time) error SetWriteDeadline(time.Time) error } // MuxedConn represents a connection to a remote peer that has been // extended to support stream multiplexing. // // A MuxedConn allows a single net.Conn connection to carry many logically // independent bidirectional streams of binary data. // // Together with network.ConnSecurity, MuxedConn is a component of the // transport.CapableConn interface, which represents a "raw" network // connection that has been "upgraded" to support the libp2p capabilities // of secure communication and stream multiplexing. type MuxedConn interface { // Close closes the stream muxer and the the underlying net.Conn. io.Closer // CloseWithError closes the connection with errCode. The errCode is sent // to the peer. CloseWithError(errCode ConnErrorCode) error // IsClosed returns whether a connection is fully closed, so it can // be garbage collected. IsClosed() bool // OpenStream creates a new stream. OpenStream(context.Context) (MuxedStream, error) // AcceptStream accepts a stream opened by the other side. AcceptStream() (MuxedStream, error) // As finds the first conn in MuxedConn's wrapped types that matches target, // and if one is found, sets target to that conn value and returns true. // Otherwise, it returns false. Similar to errors.As. // // target must be a pointer to the type you are matching against. // // This is an EXPERIMENTAL API. Getting access to the underlying type can // lead to hard to debug issues. For example, if you mutate connection state // on the underlying type, hooks that relied on only mutating that state // from the wrapped connection would never be called. // // You very likely do not need to use this method. As(target any) bool } // Multiplexer wraps a net.Conn with a stream multiplexing // implementation and returns a MuxedConn that supports opening // multiple streams over the underlying net.Conn type Multiplexer interface { // NewConn constructs a new connection NewConn(c net.Conn, isServer bool, scope PeerScope) (MuxedConn, error) }