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 }