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