go.dedis.ch/onet/v3@v3.2.11-0.20210930124529-e36530bca7ef/protocol.go (about)

     1  package onet
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/google/uuid"
     7  	"go.dedis.ch/onet/v3/log"
     8  	"go.dedis.ch/onet/v3/network"
     9  	"golang.org/x/xerrors"
    10  )
    11  
    12  // ProtocolID uniquely identifies a protocol
    13  type ProtocolID uuid.UUID
    14  
    15  // String returns canonical string representation of the ID
    16  func (pid ProtocolID) String() string {
    17  	return uuid.UUID(pid).String()
    18  }
    19  
    20  // Equal returns true if and only if pid2 equals this ProtocolID.
    21  func (pid ProtocolID) Equal(pid2 ProtocolID) bool {
    22  	return pid == pid2
    23  }
    24  
    25  // IsNil returns true iff the ProtocolID is Nil
    26  func (pid ProtocolID) IsNil() bool {
    27  	return pid.Equal(ProtocolID(uuid.Nil))
    28  }
    29  
    30  // NewProtocol is the function-signature needed to instantiate a new protocol
    31  type NewProtocol func(*TreeNodeInstance) (ProtocolInstance, error)
    32  
    33  // ProtocolInstance is the interface that instances have to use in order to be
    34  // recognized as protocols
    35  type ProtocolInstance interface {
    36  	// Start is called when a leader has created its tree configuration and
    37  	// wants to start a protocol, it calls host.StartProtocol(protocolID), that
    38  	// in turn instantiates a new protocol (with a fresh token), and then calls
    39  	// Start on it.
    40  	Start() error
    41  	// Dispatch is called at the beginning by onet for listening on the channels
    42  	Dispatch() error
    43  
    44  	// ProcessProtocolMsg is a method that is called each time a message
    45  	// arrives for this protocolInstance. TreeNodeInstance implements that
    46  	// method for you using channels or handlers.
    47  	ProcessProtocolMsg(*ProtocolMsg)
    48  	// The token representing this ProtocolInstance
    49  	Token() *Token
    50  	// Shutdown cleans up the resources used by this protocol instance
    51  	Shutdown() error
    52  }
    53  
    54  var protocols = newProtocolStorage()
    55  
    56  // protocolStorage holds all protocols either globally or per-Server.
    57  type protocolStorage struct {
    58  	// Lock used because of the 'serverStarted' flag: it can be changed from a
    59  	// call to 'Server.Start' and is checked when calling
    60  	// 'GlobalProtocolRegister'.
    61  	sync.Mutex
    62  	// Instantiators maps the name of the protocols to the `NewProtocol`-
    63  	// methods.
    64  	instantiators map[string]NewProtocol
    65  	// Flag indicating if a server has already started; here to avoid calls
    66  	// to 'GlobalProtocolRegister' when a server has already started.
    67  	serverStarted bool
    68  }
    69  
    70  // newProtocolStorage returns an initialized ProtocolStorage-struct.
    71  func newProtocolStorage() *protocolStorage {
    72  	return &protocolStorage{
    73  		instantiators: map[string]NewProtocol{},
    74  	}
    75  }
    76  
    77  // ProtocolIDToName returns the name to the corresponding protocolID.
    78  func (ps *protocolStorage) ProtocolIDToName(id ProtocolID) string {
    79  	ps.Lock()
    80  	defer ps.Unlock()
    81  	for n := range ps.instantiators {
    82  		if id.Equal(ProtocolNameToID(n)) {
    83  			return n
    84  		}
    85  	}
    86  	return ""
    87  }
    88  
    89  // ProtocolExists returns whether a certain protocol already has been
    90  // registered.
    91  func (ps *protocolStorage) ProtocolExists(protoID ProtocolID) bool {
    92  	name := ps.ProtocolIDToName(protoID)
    93  	ps.Lock()
    94  	_, ok := ps.instantiators[name]
    95  	ps.Unlock()
    96  	return ok
    97  }
    98  
    99  // Register takes a name and a NewProtocol and stores it in the structure.
   100  // If the protocol already exists, a warning is printed and the NewProtocol is
   101  // *not* stored.
   102  func (ps *protocolStorage) Register(name string, protocol NewProtocol) (ProtocolID, error) {
   103  	ps.Lock()
   104  	defer ps.Unlock()
   105  	id := ProtocolNameToID(name)
   106  	if _, exists := ps.instantiators[name]; exists {
   107  		return ProtocolID(uuid.Nil),
   108  			xerrors.Errorf("Protocol -%s- already exists - not overwriting", name)
   109  	}
   110  	ps.instantiators[name] = protocol
   111  	log.Lvl4("Registered", name, "to", id)
   112  	return id, nil
   113  }
   114  
   115  // ProtocolNameToID returns the ProtocolID corresponding to the given name.
   116  func ProtocolNameToID(name string) ProtocolID {
   117  	url := network.NamespaceURL + "protocolname/" + name
   118  	return ProtocolID(uuid.NewMD5(uuid.NameSpaceURL, []byte(url)))
   119  }
   120  
   121  // GlobalProtocolRegister registers a protocol in the global namespace.
   122  // This is used in protocols that register themselves in the `init`-method.
   123  // All registered protocols will be copied to every instantiated Server. If a
   124  // protocol is tied to a service, use `Server.ProtocolRegisterName`
   125  func GlobalProtocolRegister(name string, protocol NewProtocol) (ProtocolID, error) {
   126  	protocols.Lock()
   127  	// Cannot defer the "Unlock" because "Register" is using the lock too.
   128  	if protocols.serverStarted {
   129  		protocols.Unlock()
   130  		panic("Cannot call 'GlobalProtocolRegister' when a server has already started.")
   131  	}
   132  	protocols.Unlock()
   133  	id, err := protocols.Register(name, protocol)
   134  	if err != nil {
   135  		return id, xerrors.Errorf("registering protocol: %v", err)
   136  	}
   137  	return id, nil
   138  }
   139  
   140  // InformServerStarted allows to set the 'serverStarted' flag to true.
   141  func InformServerStarted() {
   142  	protocols.Lock()
   143  	defer protocols.Unlock()
   144  	protocols.serverStarted = true
   145  }
   146  
   147  // InformAllServersStopped allows to set the 'serverStarted' flag to false.
   148  func InformAllServersStopped() {
   149  	protocols.Lock()
   150  	defer protocols.Unlock()
   151  	protocols.serverStarted = false
   152  }
   153  
   154  // MessageProxy is an interface that allows one protocol to completely define its
   155  // wire protocol format while still using the Overlay.
   156  // Cothority sends different messages dynamically as slices of bytes, whereas
   157  // Google proposes to use union-types:
   158  // https://developers.google.com/protocol-buffers/docs/techniques#union
   159  // This is a wrapper to enable union-types while still keeping compatibility with
   160  // the dynamic cothority-messages. Implementations must provide methods to
   161  // pass from the 'union-types' to 'cothority-dynamic-messages' with the Wrap
   162  // and Unwrap method.
   163  // A default one is provided with defaultMessageProxy so the regular wire-format
   164  // protocol can still be used.
   165  type MessageProxy interface {
   166  	// Wrap takes a message and the overlay information and returns the message
   167  	// that has to be sent directly to the network alongside with any error that
   168  	// happened.
   169  	// If msg is nil, it is only an internal message of the Overlay.
   170  	Wrap(msg interface{}, info *OverlayMsg) (interface{}, error)
   171  	// Unwrap takes the message coming from the network and returns the
   172  	// inner message that is going to be dispatched to the ProtocolInstance, the
   173  	// OverlayMessage needed by the Overlay to function correctly and then any
   174  	// error that might have occurred.
   175  	Unwrap(msg interface{}) (interface{}, *OverlayMsg, error)
   176  	// PacketType returns the packet type ID that this Protocol expects from the
   177  	// network. This is needed in order for the Overlay to receive those
   178  	// messages and dispatch them to the correct MessageProxy.
   179  	PacketType() network.MessageTypeID
   180  	// Name returns the name associated with this MessageProxy. When creating a
   181  	// protocol, if one use a name used by a MessageProxy, this MessageProxy will be
   182  	// used to Wrap and Unwrap messages.
   183  	Name() string
   184  }
   185  
   186  // NewMessageProxy is a function typedef to instantiate a new MessageProxy.
   187  type NewMessageProxy func() MessageProxy
   188  
   189  type messageProxyFactoryStruct struct {
   190  	factories []NewMessageProxy
   191  }
   192  
   193  // RegisterMessageProxy stores the message proxy creation function
   194  func (mpfs *messageProxyFactoryStruct) RegisterMessageProxy(n NewMessageProxy) {
   195  	mpfs.factories = append(mpfs.factories, n)
   196  }
   197  
   198  var messageProxyFactory = messageProxyFactoryStruct{}
   199  
   200  // RegisterMessageProxy saves a new NewMessageProxy under its name.
   201  // When a Server is instantiated, all MessageProxys will be generated and stored
   202  // for this Server.
   203  func RegisterMessageProxy(n NewMessageProxy) {
   204  	messageProxyFactory.RegisterMessageProxy(n)
   205  }
   206  
   207  // messageProxyStore contains all created MessageProxys. It contains the default
   208  // MessageProxy used by the Overlay for backwards-compatibility.
   209  type messageProxyStore struct {
   210  	sync.Mutex
   211  	protos    []MessageProxy
   212  	defaultIO MessageProxy
   213  }
   214  
   215  // RegisterMessageProxy saves directly the given MessageProxy. It's useful if
   216  // one wants different message proxy per server/overlay.
   217  func (p *messageProxyStore) RegisterMessageProxy(mp MessageProxy) {
   218  	if p.getByName(mp.Name()) == p.defaultIO {
   219  		return
   220  	}
   221  	p.Lock()
   222  	defer p.Unlock()
   223  	p.protos = append(p.protos, mp)
   224  }
   225  
   226  func (p *messageProxyStore) getByName(name string) MessageProxy {
   227  	p.Lock()
   228  	defer p.Unlock()
   229  	for _, pio := range p.protos {
   230  		if pio.Name() == name {
   231  			return pio
   232  		}
   233  	}
   234  	return p.defaultIO
   235  }
   236  
   237  func (p *messageProxyStore) getByPacketType(mid network.MessageTypeID) MessageProxy {
   238  	p.Lock()
   239  	defer p.Unlock()
   240  	for _, pio := range p.protos {
   241  		if pio.PacketType().Equal(mid) {
   242  			return pio
   243  		}
   244  	}
   245  	return p.defaultIO
   246  }
   247  
   248  func newMessageProxyStore(s network.Suite, disp network.Dispatcher, proc network.Processor) *messageProxyStore {
   249  	pstore := &messageProxyStore{
   250  		// also add the default one
   251  		defaultIO: &defaultProtoIO{s},
   252  	}
   253  	for name, newIO := range messageProxyFactory.factories {
   254  		io := newIO()
   255  		pstore.protos = append(pstore.protos, io)
   256  		disp.RegisterProcessor(proc, io.PacketType())
   257  		log.Lvl3("Instantiating MessageProxy", name, "at position", len(pstore.protos))
   258  	}
   259  	return pstore
   260  }