nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/protocol/xstar/xstar.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 xstar implements the experimental star protocol. This sends messages 16 // out to all peers, and receives their responses. It also implicitly resends 17 // any message it receives to all of its peers, but it will not rebroadcast 18 // a message to the peer it was received from. 19 package xstar 20 21 import ( 22 "sync" 23 "time" 24 25 "nanomsg.org/go/mangos/v2/protocol" 26 ) 27 28 // Protocol identity information. 29 const ( 30 Self = protocol.ProtoStar 31 Peer = protocol.ProtoStar 32 SelfName = "star" 33 PeerName = "star" 34 ) 35 36 type pipe struct { 37 p protocol.Pipe 38 s *socket 39 closeq chan struct{} 40 sendq chan *protocol.Message 41 } 42 43 type socket struct { 44 closed bool 45 closeq chan struct{} 46 pipes map[uint32]*pipe 47 recvQLen int 48 sendQLen int 49 recvExpire time.Duration 50 recvq chan *protocol.Message 51 ttl int 52 sync.Mutex 53 } 54 55 var ( 56 nilQ <-chan time.Time 57 ) 58 59 const defaultQLen = 128 60 61 func (s *socket) SendMsg(m *protocol.Message) error { 62 s.Lock() 63 if s.closed { 64 s.Unlock() 65 return protocol.ErrClosed 66 } 67 68 // Raw mode messages are required to come wth the header. 69 if len(m.Header) != 4 { 70 s.Unlock() 71 m.Free() 72 return nil 73 } 74 75 for _, p := range s.pipes { 76 77 m.Clone() 78 select { 79 case p.sendq <- m: 80 default: 81 // back-pressure, but we do not exert 82 m.Free() 83 } 84 } 85 s.Unlock() 86 m.Free() 87 return nil 88 } 89 90 func (s *socket) RecvMsg() (*protocol.Message, error) { 91 // For now this uses a simple unified queue for the entire 92 // socket. Later we can look at moving this to priority queues 93 // based on socket pipes. 94 tq := nilQ 95 s.Lock() 96 if s.recvExpire > 0 { 97 tq = time.After(s.recvExpire) 98 } 99 s.Unlock() 100 select { 101 case <-s.closeq: 102 return nil, protocol.ErrClosed 103 case <-tq: 104 return nil, protocol.ErrRecvTimeout 105 case m := <-s.recvq: 106 return m, nil 107 } 108 } 109 110 func (s *socket) SetOption(name string, value interface{}) error { 111 switch name { 112 113 case protocol.OptionTTL: 114 if v, ok := value.(int); ok && v > 0 && v < 256 { 115 s.Lock() 116 s.ttl = v 117 s.Unlock() 118 return nil 119 } 120 return protocol.ErrBadValue 121 122 case protocol.OptionRecvDeadline: 123 if v, ok := value.(time.Duration); ok { 124 s.Lock() 125 s.recvExpire = v 126 s.Unlock() 127 return nil 128 } 129 return protocol.ErrBadValue 130 131 case protocol.OptionWriteQLen: 132 if v, ok := value.(int); ok && v >= 0 { 133 s.Lock() 134 s.sendQLen = v 135 s.Unlock() 136 return nil 137 } 138 return protocol.ErrBadValue 139 140 case protocol.OptionReadQLen: 141 if v, ok := value.(int); ok && v >= 0 { 142 newchan := make(chan *protocol.Message, v) 143 s.Lock() 144 s.recvQLen = v 145 s.recvq = newchan 146 s.Unlock() 147 148 return nil 149 } 150 return protocol.ErrBadValue 151 } 152 153 return protocol.ErrBadOption 154 } 155 156 func (s *socket) GetOption(option string) (interface{}, error) { 157 switch option { 158 case protocol.OptionRaw: 159 return true, nil 160 case protocol.OptionTTL: 161 s.Lock() 162 v := s.ttl 163 s.Unlock() 164 return v, nil 165 case protocol.OptionRecvDeadline: 166 s.Lock() 167 v := s.recvExpire 168 s.Unlock() 169 return v, nil 170 case protocol.OptionWriteQLen: 171 s.Lock() 172 v := s.sendQLen 173 s.Unlock() 174 return v, nil 175 case protocol.OptionReadQLen: 176 s.Lock() 177 v := s.recvQLen 178 s.Unlock() 179 return v, nil 180 } 181 182 return nil, protocol.ErrBadOption 183 } 184 185 func (s *socket) AddPipe(pp protocol.Pipe) error { 186 p := &pipe{ 187 p: pp, 188 s: s, 189 closeq: make(chan struct{}), 190 sendq: make(chan *protocol.Message, s.sendQLen), 191 } 192 pp.SetPrivate(p) 193 s.Lock() 194 defer s.Unlock() 195 if s.closed { 196 return protocol.ErrClosed 197 } 198 s.pipes[pp.ID()] = p 199 200 go p.sender() 201 go p.receiver() 202 return nil 203 } 204 205 func (s *socket) RemovePipe(pp protocol.Pipe) { 206 p := pp.GetPrivate().(*pipe) 207 close(p.closeq) 208 s.Lock() 209 delete(p.s.pipes, p.p.ID()) 210 s.Unlock() 211 } 212 213 func (s *socket) OpenContext() (protocol.Context, error) { 214 return nil, protocol.ErrProtoOp 215 } 216 217 func (*socket) Info() protocol.Info { 218 return protocol.Info{ 219 Self: Self, 220 Peer: Peer, 221 SelfName: SelfName, 222 PeerName: PeerName, 223 } 224 } 225 226 func (s *socket) Close() error { 227 s.Lock() 228 if s.closed { 229 s.Unlock() 230 return protocol.ErrClosed 231 } 232 s.closed = true 233 s.Unlock() 234 235 close(s.closeq) 236 return nil 237 } 238 239 func (p *pipe) sender() { 240 outer: 241 for { 242 var m *protocol.Message 243 select { 244 case <-p.closeq: 245 break outer 246 case m = <-p.sendq: 247 } 248 249 if err := p.p.SendMsg(m); err != nil { 250 m.Free() 251 break 252 } 253 } 254 p.close() 255 } 256 257 func (p *pipe) receiver() { 258 s := p.s 259 outer: 260 for { 261 m := p.p.RecvMsg() 262 if m == nil { 263 break 264 } 265 266 if len(m.Body) < 4 || 267 m.Body[0] != 0 || m.Body[1] != 0 || m.Body[2] != 0 || 268 int(m.Body[3]) >= s.ttl { 269 m.Free() 270 continue 271 } 272 m.Header = m.Body[:4] 273 m.Body = m.Body[4:] 274 m.Header[3]++ 275 276 userm := m.Dup() 277 s.Lock() 278 for _, p2 := range s.pipes { 279 if p2 == p { 280 continue 281 } 282 283 m2 := m.Dup() 284 select { 285 case p2.sendq <- m2: 286 default: 287 m2.Free() 288 } 289 } 290 s.Unlock() 291 m.Free() 292 293 select { 294 case s.recvq <- userm: 295 case <-p.closeq: 296 userm.Free() 297 break outer 298 case <-s.closeq: 299 userm.Free() 300 break outer 301 } 302 } 303 p.close() 304 } 305 306 func (p *pipe) close() { 307 _ = p.p.Close() 308 } 309 310 // NewProtocol returns a new protocol implementation. 311 func NewProtocol() protocol.Protocol { 312 s := &socket{ 313 pipes: make(map[uint32]*pipe), 314 closeq: make(chan struct{}), 315 recvq: make(chan *protocol.Message, defaultQLen), 316 sendQLen: defaultQLen, 317 recvQLen: defaultQLen, 318 ttl: 8, 319 } 320 return s 321 } 322 323 // NewSocket allocates a raw Socket using the BUS protocol. 324 func NewSocket() (protocol.Socket, error) { 325 return protocol.MakeSocket(NewProtocol()), nil 326 }