gopkg.in/dedis/onet.v2@v2.0.0-20181115163211-c8f3724038a7/protocol.go (about)

     1  package onet
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"gopkg.in/dedis/onet.v2/log"
     8  	"gopkg.in/dedis/onet.v2/network"
     9  	"gopkg.in/satori/go.uuid.v1"
    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 uuid.Equal(uuid.UUID(pid), uuid.UUID(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 turns instantiate a new protocol (with a fresh token), and then call
    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  	// DispatchMsg is a method that is called each time a message arrives for
    45  	// this protocolInstance. TreeNodeInstance implements that method for you
    46  	// 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  			fmt.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.NewV3(uuid.NamespaceURL, 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  	return protocols.Register(name, protocol)
   134  }
   135  
   136  // InformServerStarted allows to set the 'serverStarted' flag to true.
   137  func InformServerStarted() {
   138  	protocols.Lock()
   139  	defer protocols.Unlock()
   140  	protocols.serverStarted = true
   141  }
   142  
   143  // InformAllServersStopped allows to set the 'serverStarted' flag to false.
   144  func InformAllServersStopped() {
   145  	protocols.Lock()
   146  	defer protocols.Unlock()
   147  	protocols.serverStarted = false
   148  }
   149  
   150  // MessageProxy is an interface that allows one protocol to completely define its
   151  // wire protocol format while still using the Overlay.
   152  // Cothority sends different messages dynamically as slices of bytes, whereas
   153  // Google proposes to use union-types:
   154  // https://developers.google.com/protocol-buffers/docs/techniques#union
   155  // This is a wrapper to enable union-types while still keeping compatibility with
   156  // the dynamic cothority-messages. Implementations must provide methods to
   157  // pass from the 'union-types' to 'cothority-dynamic-messages' with the Wrap
   158  // and Unwrap method.
   159  // A default one is provided with defaultMessageProxy so the regular wire-format
   160  // protocol can still be used.
   161  type MessageProxy interface {
   162  	// Wrap takes a message and the overlay information and returns the message
   163  	// that has to be sent directly to the network alongside with any error that
   164  	// happened.
   165  	// If msg is nil, it is only an internal message of the Overlay.
   166  	Wrap(msg interface{}, info *OverlayMsg) (interface{}, error)
   167  	// Unwrap takes the message coming from the network and returns the
   168  	// inner message that is going to be dispatched to the ProtocolInstance, the
   169  	// OverlayMessage needed by the Overlay to function correctly and then any
   170  	// error that might have occurred.
   171  	Unwrap(msg interface{}) (interface{}, *OverlayMsg, error)
   172  	// PacketType returns the packet type ID that this Protocol expects from the
   173  	// network. This is needed in order for the Overlay to receive those
   174  	// messages and dispatch them to the correct MessageProxy.
   175  	PacketType() network.MessageTypeID
   176  	// Name returns the name associated with this MessageProxy. When creating a
   177  	// protocol, if one use a name used by a MessageProxy, this MessageProxy will be
   178  	// used to Wrap and Unwrap messages.
   179  	Name() string
   180  }
   181  
   182  // NewMessageProxy is a function typedef to instantiate a new MessageProxy.
   183  type NewMessageProxy func() MessageProxy
   184  
   185  type messageProxyFactoryStruct struct {
   186  	factories []NewMessageProxy
   187  }
   188  
   189  // RegisterMessageProxy stores the message proxy creation function
   190  func (mpfs *messageProxyFactoryStruct) RegisterMessageProxy(n NewMessageProxy) {
   191  	mpfs.factories = append(mpfs.factories, n)
   192  }
   193  
   194  var messageProxyFactory = messageProxyFactoryStruct{}
   195  
   196  // RegisterMessageProxy saves a new NewMessageProxy under its name.
   197  // When a Server is instantiated, all MessageProxys will be generated and stored
   198  // for this Server.
   199  func RegisterMessageProxy(n NewMessageProxy) {
   200  	messageProxyFactory.RegisterMessageProxy(n)
   201  }
   202  
   203  // messageProxyStore contains all created MessageProxys. It contains the default
   204  // MessageProxy used by the Overlay for backwards-compatibility.
   205  type messageProxyStore struct {
   206  	sync.Mutex
   207  	protos    []MessageProxy
   208  	defaultIO MessageProxy
   209  }
   210  
   211  // RegisterMessageProxy saves directly the given MessageProxy. It's useful if
   212  // one wants different message proxy per server/overlay.
   213  func (p *messageProxyStore) RegisterMessageProxy(mp MessageProxy) {
   214  	if p.getByName(mp.Name()) == p.defaultIO {
   215  		return
   216  	}
   217  	p.Lock()
   218  	defer p.Unlock()
   219  	p.protos = append(p.protos, mp)
   220  }
   221  
   222  func (p *messageProxyStore) getByName(name string) MessageProxy {
   223  	p.Lock()
   224  	defer p.Unlock()
   225  	for _, pio := range p.protos {
   226  		if pio.Name() == name {
   227  			return pio
   228  		}
   229  	}
   230  	return p.defaultIO
   231  }
   232  
   233  func (p *messageProxyStore) getByPacketType(mid network.MessageTypeID) MessageProxy {
   234  	p.Lock()
   235  	defer p.Unlock()
   236  	for _, pio := range p.protos {
   237  		if pio.PacketType().Equal(mid) {
   238  			return pio
   239  		}
   240  	}
   241  	return p.defaultIO
   242  }
   243  
   244  func newMessageProxyStore(s network.Suite, disp network.Dispatcher, proc network.Processor) *messageProxyStore {
   245  	pstore := &messageProxyStore{
   246  		// also add the default one
   247  		defaultIO: &defaultProtoIO{s},
   248  	}
   249  	for name, newIO := range messageProxyFactory.factories {
   250  		io := newIO()
   251  		pstore.protos = append(pstore.protos, io)
   252  		disp.RegisterProcessor(proc, io.PacketType())
   253  		log.Lvl3("Instantiating MessageProxy", name, "at position", len(pstore.protos))
   254  	}
   255  	return pstore
   256  }