nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/protocol/xrespondent/xrespondent.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 xrespondent implements the raw RESPONDENT protocol, which is the 16 // response side of survey pattern. (SURVEYOR is the survey generator.) 17 package xrespondent 18 19 import ( 20 "encoding/binary" 21 "sync" 22 "time" 23 24 "nanomsg.org/go/mangos/v2/protocol" 25 ) 26 27 // Protocol identity information. 28 const ( 29 Self = protocol.ProtoRespondent 30 Peer = protocol.ProtoSurveyor 31 SelfName = "respondent" 32 PeerName = "surveyor" 33 ) 34 35 type pipe struct { 36 p protocol.Pipe 37 s *socket 38 closeQ chan struct{} 39 sendQ chan *protocol.Message 40 } 41 42 type socket struct { 43 closed bool 44 closeQ chan struct{} 45 sizeQ chan struct{} 46 recvQ chan *protocol.Message 47 pipes map[uint32]*pipe 48 recvExpire time.Duration 49 sendExpire time.Duration 50 sendQLen int 51 recvQLen int 52 bestEffort bool 53 ttl int 54 sync.Mutex 55 } 56 57 var ( 58 nilQ <-chan time.Time 59 closedQ chan time.Time 60 ) 61 62 const defaultQLen = 128 63 64 func init() { 65 closedQ = make(chan time.Time) 66 close(closedQ) 67 } 68 69 // SendMessage implements sending a message. The message must already 70 // have headers... the first 4 bytes are the identity of the pipe 71 // we should send to. 72 func (s *socket) SendMsg(m *protocol.Message) error { 73 74 s.Lock() 75 if s.closed { 76 s.Unlock() 77 return protocol.ErrClosed 78 } 79 80 if len(m.Header) < 4 { 81 s.Unlock() 82 m.Free() 83 return nil 84 } 85 86 id := binary.BigEndian.Uint32(m.Header) 87 hdr := m.Header 88 m.Header = m.Header[4:] 89 90 p, ok := s.pipes[id] 91 if !ok { 92 s.Unlock() 93 m.Free() 94 return nil 95 } 96 bestEffort := s.bestEffort 97 tq := nilQ 98 if bestEffort { 99 tq = closedQ 100 } else if s.sendExpire > 0 { 101 tq = time.After(s.sendExpire) 102 } 103 s.Unlock() 104 105 select { 106 case p.sendQ <- m: 107 return nil 108 case <-p.closeQ: 109 m.Free() 110 return nil // No way to return the message 111 case <-tq: 112 if bestEffort { 113 m.Free() 114 return nil 115 } 116 // restore the header 117 m.Header = hdr 118 return protocol.ErrSendTimeout 119 } 120 } 121 122 func (s *socket) RecvMsg() (*protocol.Message, error) { 123 timeQ := nilQ 124 s.Lock() 125 if s.recvExpire > 0 { 126 timeQ = time.After(s.recvExpire) 127 } 128 recvQ := s.recvQ 129 sizeQ := s.sizeQ 130 closeQ := s.closeQ 131 s.Unlock() 132 133 for { 134 select { 135 case <-closeQ: 136 return nil, protocol.ErrClosed 137 case <-timeQ: 138 return nil, protocol.ErrRecvTimeout 139 case m := <-recvQ: 140 return m, nil 141 case <-sizeQ: 142 s.Lock() 143 recvQ = s.recvQ 144 sizeQ = s.sizeQ 145 s.Unlock() 146 } 147 } 148 } 149 150 func (p *pipe) receiver() { 151 s := p.s 152 outer: 153 for { 154 155 m := p.p.RecvMsg() 156 if m == nil { 157 break 158 } 159 if len(m.Body) < 4 { 160 m.Free() 161 continue 162 } 163 164 // Outer most value of header is pipe ID 165 m.Header = append(make([]byte, 4), m.Header...) 166 binary.BigEndian.PutUint32(m.Header, p.p.ID()) 167 168 s.Lock() 169 ttl := s.ttl 170 s.Unlock() 171 172 hops := 1 173 finish := false 174 for !finish { 175 if hops >= ttl { 176 m.Free() 177 continue outer 178 } 179 hops++ 180 if len(m.Body) < 4 { 181 m.Free() // Garbled! 182 continue outer 183 } 184 if m.Body[0]&0x80 != 0 { 185 // High order bit set indicates ID and end of 186 // message headers. 187 finish = true 188 } 189 m.Header = append(m.Header, m.Body[:4]...) 190 m.Body = m.Body[4:] 191 } 192 193 s.Lock() 194 recvQ := s.recvQ 195 sizeQ := s.sizeQ 196 s.Unlock() 197 198 select { 199 case recvQ <- m: 200 continue 201 case <-sizeQ: 202 continue 203 case <-p.closeQ: 204 m.Free() 205 break outer 206 } 207 } 208 p.close() 209 } 210 211 // This is a puller, and doesn't permit for priorities. We might want 212 // to refactor this to use a push based scheme later. 213 func (p *pipe) sender() { 214 outer: 215 for { 216 var m *protocol.Message 217 select { 218 case m = <-p.sendQ: 219 case <-p.closeQ: 220 break outer 221 } 222 223 if e := p.p.SendMsg(m); e != nil { 224 break 225 } 226 } 227 p.close() 228 } 229 230 func (p *pipe) close() { 231 _ = p.p.Close() 232 } 233 234 func (s *socket) SetOption(name string, value interface{}) error { 235 switch name { 236 237 case protocol.OptionTTL: 238 if v, ok := value.(int); ok && v > 0 && v < 256 { 239 s.Lock() 240 s.ttl = v 241 s.Unlock() 242 return nil 243 } 244 return protocol.ErrBadValue 245 246 case protocol.OptionRecvDeadline: 247 if v, ok := value.(time.Duration); ok { 248 s.Lock() 249 s.recvExpire = v 250 s.Unlock() 251 return nil 252 } 253 return protocol.ErrBadValue 254 255 case protocol.OptionSendDeadline: 256 if v, ok := value.(time.Duration); ok { 257 s.Lock() 258 s.sendExpire = v 259 s.Unlock() 260 return nil 261 } 262 return protocol.ErrBadValue 263 264 case protocol.OptionBestEffort: 265 if v, ok := value.(bool); ok { 266 s.Lock() 267 s.bestEffort = v 268 s.Unlock() 269 return nil 270 } 271 return protocol.ErrBadValue 272 273 case protocol.OptionWriteQLen: 274 if v, ok := value.(int); ok && v >= 0 { 275 s.Lock() 276 // This does not impact pipes already connected. 277 s.sendQLen = v 278 s.Unlock() 279 return nil 280 } 281 return protocol.ErrBadValue 282 283 case protocol.OptionReadQLen: 284 if v, ok := value.(int); ok && v >= 0 { 285 recvQ := make(chan *protocol.Message, v) 286 sizeQ := make(chan struct{}) 287 s.Lock() 288 close(s.sizeQ) 289 s.recvQLen = v 290 s.recvQ = recvQ 291 s.sizeQ = sizeQ 292 s.Unlock() 293 return nil 294 } 295 return protocol.ErrBadValue 296 } 297 298 return protocol.ErrBadOption 299 } 300 301 func (s *socket) GetOption(option string) (interface{}, error) { 302 switch option { 303 case protocol.OptionRaw: 304 return true, nil 305 case protocol.OptionTTL: 306 s.Lock() 307 v := s.ttl 308 s.Unlock() 309 return v, nil 310 case protocol.OptionRecvDeadline: 311 s.Lock() 312 v := s.recvExpire 313 s.Unlock() 314 return v, nil 315 case protocol.OptionSendDeadline: 316 s.Lock() 317 v := s.sendExpire 318 s.Unlock() 319 return v, nil 320 case protocol.OptionBestEffort: 321 s.Lock() 322 v := s.bestEffort 323 s.Unlock() 324 return v, nil 325 case protocol.OptionWriteQLen: 326 s.Lock() 327 v := s.sendQLen 328 s.Unlock() 329 return v, nil 330 case protocol.OptionReadQLen: 331 s.Lock() 332 v := s.recvQLen 333 s.Unlock() 334 return v, nil 335 } 336 337 return nil, protocol.ErrBadOption 338 } 339 340 func (s *socket) Close() error { 341 s.Lock() 342 if s.closed { 343 s.Unlock() 344 return protocol.ErrClosed 345 } 346 s.closed = true 347 s.Unlock() 348 close(s.closeQ) 349 return nil 350 } 351 352 func (s *socket) AddPipe(pp protocol.Pipe) error { 353 p := &pipe{ 354 p: pp, 355 s: s, 356 closeQ: make(chan struct{}), 357 sendQ: make(chan *protocol.Message, s.sendQLen), 358 } 359 pp.SetPrivate(p) 360 s.Lock() 361 defer s.Unlock() 362 if s.closed { 363 return protocol.ErrClosed 364 } 365 s.pipes[pp.ID()] = p 366 go p.sender() 367 go p.receiver() 368 return nil 369 } 370 371 func (s *socket) RemovePipe(pp protocol.Pipe) { 372 p := pp.GetPrivate().(*pipe) 373 close(p.closeQ) 374 s.Lock() 375 delete(s.pipes, p.p.ID()) 376 s.Unlock() 377 } 378 379 func (s *socket) OpenContext() (protocol.Context, error) { 380 return nil, protocol.ErrProtoOp 381 } 382 383 func (*socket) Info() protocol.Info { 384 return protocol.Info{ 385 Self: Self, 386 Peer: Peer, 387 SelfName: SelfName, 388 PeerName: PeerName, 389 } 390 } 391 392 // NewProtocol returns a new protocol implementation. 393 func NewProtocol() protocol.Protocol { 394 s := &socket{ 395 pipes: make(map[uint32]*pipe), 396 closeQ: make(chan struct{}), 397 sizeQ: make(chan struct{}), 398 recvQ: make(chan *protocol.Message, defaultQLen), 399 sendQLen: defaultQLen, 400 recvQLen: defaultQLen, 401 ttl: 8, 402 } 403 return s 404 } 405 406 // NewSocket allocates a new Socket using the RESPONDENT protocol. 407 func NewSocket() (protocol.Socket, error) { 408 return protocol.MakeSocket(NewProtocol()), nil 409 }