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 }