Skip to content

Commit

Permalink
catch panics (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-seemann authored Apr 19, 2022
1 parent 95fabd7 commit 6a557b8
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 11 deletions.
37 changes: 30 additions & 7 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import (
"crypto/rand"
"encoding/binary"
"errors"
"fmt"
"io"
"os"
"runtime/debug"
"strconv"
"strings"
)
Expand All @@ -28,7 +31,14 @@ const (
// to inform the muxer of the protocol that will be used to communicate
// on this ReadWriteCloser. It returns an error if, for example,
// the muxer does not know how to handle this protocol.
func SelectProtoOrFail(proto string, rwc io.ReadWriteCloser) error {
func SelectProtoOrFail(proto string, rwc io.ReadWriteCloser) (err error) {
defer func() {
if rerr := recover(); rerr != nil {
fmt.Fprintf(os.Stderr, "caught panic: %s\n%s\n", rerr, debug.Stack())
err = fmt.Errorf("panic selecting protocol: %s", rerr)
}
}()

errCh := make(chan error, 1)
go func() {
var buf bytes.Buffer
Expand Down Expand Up @@ -56,7 +66,14 @@ func SelectProtoOrFail(proto string, rwc io.ReadWriteCloser) error {

// SelectOneOf will perform handshakes with the protocols on the given slice
// until it finds one which is supported by the muxer.
func SelectOneOf(protos []string, rwc io.ReadWriteCloser) (string, error) {
func SelectOneOf(protos []string, rwc io.ReadWriteCloser) (proto string, err error) {
defer func() {
if rerr := recover(); rerr != nil {
fmt.Fprintf(os.Stderr, "caught panic: %s\n%s\n", rerr, debug.Stack())
err = fmt.Errorf("panic selecting one of protocols: %s", rerr)
}
}()

if len(protos) == 0 {
return "", ErrNoProtocols
}
Expand All @@ -78,9 +95,16 @@ func SelectOneOf(protos []string, rwc io.ReadWriteCloser) (string, error) {

const simOpenProtocol = "/libp2p/simultaneous-connect"

// Performs protocol negotiation with the simultaneous open extension; the returned boolean
// indicator will be true if we should act as a server.
func SelectWithSimopenOrFail(protos []string, rwc io.ReadWriteCloser) (string, bool, error) {
// SelectWithSimopenOrFail performs protocol negotiation with the simultaneous open extension.
// The returned boolean indicator will be true if we should act as a server.
func SelectWithSimopenOrFail(protos []string, rwc io.ReadWriteCloser) (proto string, isServer bool, err error) {
defer func() {
if rerr := recover(); rerr != nil {
fmt.Fprintf(os.Stderr, "caught panic: %s\n%s\n", rerr, debug.Stack())
err = fmt.Errorf("panic selecting protocol with simopen: %s", rerr)
}
}()

if len(protos) == 0 {
return "", false, ErrNoProtocols
}
Expand All @@ -97,8 +121,7 @@ func SelectWithSimopenOrFail(protos []string, rwc io.ReadWriteCloser) (string, b
werrCh <- err
}()

err := readMultistreamHeader(rwc)
if err != nil {
if err := readMultistreamHeader(rwc); err != nil {
return "", false, err
}

Expand Down
32 changes: 28 additions & 4 deletions multistream.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"bufio"
"errors"
"fmt"
"os"
"runtime/debug"

"io"
"sync"
Expand Down Expand Up @@ -186,7 +188,14 @@ func (msm *MultistreamMuxer) findHandler(proto string) *Handler {
// a multistream, the protocol used, the handler and an error. It is lazy
// because the write-handshake is performed on a subroutine, allowing this
// to return before that handshake is completed.
func (msm *MultistreamMuxer) NegotiateLazy(rwc io.ReadWriteCloser) (io.ReadWriteCloser, string, HandlerFunc, error) {
func (msm *MultistreamMuxer) NegotiateLazy(rwc io.ReadWriteCloser) (rwc_ io.ReadWriteCloser, proto string, handler HandlerFunc, err error) {
defer func() {
if rerr := recover(); rerr != nil {
fmt.Fprintf(os.Stderr, "caught panic: %s\n%s\n", rerr, debug.Stack())
err = fmt.Errorf("panic in lazy multistream negotiation: %s", rerr)
}
}()

pval := make(chan string, 1)
writeErr := make(chan error, 1)
defer close(pval)
Expand All @@ -197,6 +206,15 @@ func (msm *MultistreamMuxer) NegotiateLazy(rwc io.ReadWriteCloser) (io.ReadWrite

started := make(chan struct{})
go lzc.waitForHandshake.Do(func() {
defer func() {
if rerr := recover(); rerr != nil {
fmt.Fprintf(os.Stderr, "caught panic: %s\n%s\n", rerr, debug.Stack())
err := fmt.Errorf("panic in lazy multistream negotiation, waiting for handshake: %s", rerr)
lzc.werr = err
writeErr <- err
}
}()

close(started)

defer close(writeErr)
Expand Down Expand Up @@ -262,10 +280,16 @@ loop:

// Negotiate performs protocol selection and returns the protocol name and
// the matching handler function for it (or an error).
func (msm *MultistreamMuxer) Negotiate(rwc io.ReadWriteCloser) (string, HandlerFunc, error) {
func (msm *MultistreamMuxer) Negotiate(rwc io.ReadWriteCloser) (proto string, handler HandlerFunc, err error) {
defer func() {
if rerr := recover(); rerr != nil {
fmt.Fprintf(os.Stderr, "caught panic: %s\n%s\n", rerr, debug.Stack())
err = fmt.Errorf("panic in multistream negotiation: %s", rerr)
}
}()

// Send our protocol ID
err := delimWriteBuffered(rwc, []byte(ProtocolID))
if err != nil {
if err := delimWriteBuffered(rwc, []byte(ProtocolID)); err != nil {
return "", nil, err
}

Expand Down

0 comments on commit 6a557b8

Please sign in to comment.