go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/xbus/xbus.go (about) 1 // Copyright 2019 The Mangos Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use file except in compliance with the License. 5 // You may obtain a copy of the license at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package xbus implements the BUS protocol. This sends messages 16 // out to all peers, and receives their responses. It specifically 17 // filters messages sent to itself, so that a single BUS can be used 18 // to loop back to peers. 19 package xbus 20 21 import ( 22 "encoding/binary" 23 "sync" 24 "time" 25 26 "go.nanomsg.org/mangos/v3/protocol" 27 ) 28 29 type pipe struct { 30 p protocol.Pipe 31 s *socket 32 closeQ chan struct{} 33 sendQ chan *protocol.Message 34 } 35 36 type socket struct { 37 closed bool 38 closeQ chan struct{} 39 sizeQ chan struct{} 40 pipes map[uint32]*pipe 41 recvQLen int 42 sendQLen int 43 recvExpire time.Duration 44 recvQ chan *protocol.Message 45 sync.Mutex 46 } 47 48 // Protocol identity information. 49 const ( 50 Self = protocol.ProtoBus 51 Peer = protocol.ProtoBus 52 SelfName = "bus" 53 PeerName = "bus" 54 ) 55 56 var ( 57 nilQ <-chan time.Time 58 ) 59 60 const defaultQLen = 128 61 62 func (s *socket) SendMsg(m *protocol.Message) error { 63 s.Lock() 64 if s.closed { 65 s.Unlock() 66 return protocol.ErrClosed 67 } 68 var id uint32 69 70 if len(m.Header) == 4 { 71 m = m.MakeUnique() 72 // This is coming back to us - its a forwarded message 73 // from an earlier pipe. Note that we could also have 74 // used the m.Pipe but this is how mangos v1 and nanomsg 75 // did it historically. 76 id = binary.BigEndian.Uint32(m.Header) 77 m.Header = m.Header[:0] 78 } 79 80 for _, p := range s.pipes { 81 82 // Don't deliver the message back up to the same pipe it 83 // arrived from. 84 if p.p.ID() == id { 85 continue 86 } 87 m.Clone() 88 select { 89 case p.sendQ <- m: 90 default: 91 // back-pressure, but we do not exert 92 m.Free() 93 } 94 } 95 s.Unlock() 96 m.Free() 97 return nil 98 } 99 100 func (s *socket) RecvMsg() (*protocol.Message, error) { 101 // For now this uses a simple unified queue for the entire 102 // socket. Later we can look at moving this to priority queues 103 // based on socket pipes. 104 for { 105 s.Lock() 106 rq := s.recvQ 107 cq := s.closeQ 108 zq := s.sizeQ 109 tq := nilQ 110 if s.recvExpire > 0 { 111 tq = time.After(s.recvExpire) 112 } 113 s.Unlock() 114 115 select { 116 case <-cq: 117 return nil, protocol.ErrClosed 118 case <-zq: 119 continue 120 case <-tq: 121 return nil, protocol.ErrRecvTimeout 122 case m := <-rq: 123 return m, nil 124 } 125 } 126 } 127 128 func (s *socket) SetOption(name string, value interface{}) error { 129 switch name { 130 131 case protocol.OptionRecvDeadline: 132 if v, ok := value.(time.Duration); ok { 133 s.Lock() 134 s.recvExpire = v 135 s.Unlock() 136 return nil 137 } 138 return protocol.ErrBadValue 139 140 case protocol.OptionWriteQLen: 141 if v, ok := value.(int); ok && v >= 0 { 142 s.Lock() 143 s.sendQLen = v 144 s.Unlock() 145 return nil 146 } 147 return protocol.ErrBadValue 148 149 case protocol.OptionReadQLen: 150 if v, ok := value.(int); ok && v >= 0 { 151 newQ := make(chan *protocol.Message, v) 152 sizeQ := make(chan struct{}) 153 s.Lock() 154 s.recvQLen = v 155 s.recvQ = newQ 156 sizeQ, s.sizeQ = s.sizeQ, sizeQ 157 s.Unlock() 158 close(sizeQ) 159 return nil 160 } 161 return protocol.ErrBadValue 162 } 163 164 return protocol.ErrBadOption 165 } 166 167 func (s *socket) GetOption(option string) (interface{}, error) { 168 switch option { 169 case protocol.OptionRaw: 170 return true, nil 171 case protocol.OptionRecvDeadline: 172 s.Lock() 173 v := s.recvExpire 174 s.Unlock() 175 return v, nil 176 case protocol.OptionWriteQLen: 177 s.Lock() 178 v := s.sendQLen 179 s.Unlock() 180 return v, nil 181 case protocol.OptionReadQLen: 182 s.Lock() 183 v := s.recvQLen 184 s.Unlock() 185 return v, nil 186 } 187 188 return nil, protocol.ErrBadOption 189 } 190 191 func (s *socket) AddPipe(pp protocol.Pipe) error { 192 s.Lock() 193 defer s.Unlock() 194 if s.closed { 195 return protocol.ErrClosed 196 } 197 198 p := &pipe{ 199 p: pp, 200 s: s, 201 closeQ: make(chan struct{}), 202 sendQ: make(chan *protocol.Message, s.sendQLen), 203 } 204 s.pipes[pp.ID()] = p 205 pp.SetPrivate(p) 206 207 go p.sender() 208 go p.receiver() 209 return nil 210 } 211 212 func (s *socket) RemovePipe(pp protocol.Pipe) { 213 if p, ok := pp.GetPrivate().(*pipe); ok { 214 s.Lock() 215 delete(s.pipes, pp.ID()) 216 s.Unlock() 217 close(p.closeQ) 218 } 219 } 220 221 func (s *socket) OpenContext() (protocol.Context, error) { 222 return nil, protocol.ErrProtoOp 223 } 224 225 func (*socket) Info() protocol.Info { 226 return protocol.Info{ 227 Self: Self, 228 Peer: Peer, 229 SelfName: SelfName, 230 PeerName: PeerName, 231 } 232 } 233 234 func (s *socket) Close() error { 235 s.Lock() 236 if s.closed { 237 s.Unlock() 238 return protocol.ErrClosed 239 } 240 s.closed = true 241 s.Unlock() 242 close(s.closeQ) 243 244 return nil 245 } 246 247 func (p *pipe) sender() { 248 outer: 249 for { 250 var m *protocol.Message 251 select { 252 case <-p.closeQ: 253 break outer 254 case m = <-p.sendQ: 255 } 256 257 if err := p.p.SendMsg(m); err != nil { 258 m.Free() 259 break 260 } 261 } 262 p.Close() 263 } 264 265 func (p *pipe) receiver() { 266 s := p.s 267 outer: 268 for { 269 m := p.p.RecvMsg() 270 if m == nil { 271 break 272 } 273 274 // We store the received pipe ID in the header. 275 // This permits a device to be set up as a bouncer. 276 // In that case, this pipe won't get a copy of the 277 // message. 278 279 m.Header = make([]byte, 4) 280 binary.BigEndian.PutUint32(m.Header, p.p.ID()) 281 282 s.Lock() 283 rq := s.recvQ 284 zq := s.sizeQ 285 s.Unlock() 286 287 select { 288 case rq <- m: 289 case <-p.closeQ: 290 m.Free() 291 break outer 292 case <-zq: 293 m.Free() // discard this one 294 break outer 295 } 296 } 297 p.Close() 298 } 299 300 func (p *pipe) Close() { 301 _ = p.p.Close() 302 } 303 304 // NewProtocol returns a new protocol implementation. 305 func NewProtocol() protocol.Protocol { 306 s := &socket{ 307 pipes: make(map[uint32]*pipe), 308 closeQ: make(chan struct{}), 309 sizeQ: make(chan struct{}), 310 recvQ: make(chan *protocol.Message, defaultQLen), 311 sendQLen: defaultQLen, 312 recvQLen: defaultQLen, 313 } 314 return s 315 } 316 317 // NewSocket allocates a raw Socket using the BUS protocol. 318 func NewSocket() (protocol.Socket, error) { 319 return protocol.MakeSocket(NewProtocol()), nil 320 }