go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/xreq/xreq.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 xreq implements the raw REQ protocol, which is the request side of 16 // the request/response pattern. (REP is the response.) 17 package xreq 18 19 import ( 20 "sync" 21 "time" 22 23 "go.nanomsg.org/mangos/v3/protocol" 24 ) 25 26 // Protocol identity information. 27 const ( 28 Self = protocol.ProtoReq 29 Peer = protocol.ProtoRep 30 SelfName = "req" 31 PeerName = "rep" 32 ) 33 34 type pipe struct { 35 p protocol.Pipe 36 s *socket 37 closeQ chan struct{} 38 } 39 40 type socket struct { 41 closed bool 42 recvQ chan *protocol.Message 43 sendQ chan *protocol.Message 44 closeQ chan struct{} 45 sizeQ chan struct{} 46 recvExpire time.Duration 47 sendExpire time.Duration 48 sendQLen int 49 recvQLen int 50 bestEffort bool 51 sync.Mutex 52 } 53 54 var ( 55 nilQ <-chan time.Time 56 closedQ chan time.Time 57 ) 58 59 const defaultQLen = 128 60 61 func init() { 62 closedQ = make(chan time.Time) 63 close(closedQ) 64 } 65 66 // SendMsg implements sending a message. The message must come with 67 // its headers already prepared. This will be at a minimum the request 68 // ID at the end of the header, plus any leading backtrace information 69 // coming from a paired REP socket. 70 func (s *socket) SendMsg(m *protocol.Message) error { 71 s.Lock() 72 bestEffort := s.bestEffort 73 timeQ := nilQ 74 if bestEffort { 75 timeQ = closedQ 76 } else if s.sendExpire > 0 { 77 timeQ = time.After(s.sendExpire) 78 } 79 sendQ := s.sendQ 80 sizeQ := s.sizeQ 81 closeQ := s.closeQ 82 s.Unlock() 83 84 select { 85 case sendQ <- m: 86 return nil 87 case <-sizeQ: 88 m.Free() 89 return nil 90 case <-closeQ: 91 return protocol.ErrClosed 92 case <-timeQ: 93 if bestEffort { 94 m.Free() 95 return nil 96 } 97 return protocol.ErrSendTimeout 98 } 99 } 100 101 func (s *socket) RecvMsg() (*protocol.Message, error) { 102 for { 103 timeQ := nilQ 104 s.Lock() 105 if s.recvExpire > 0 { 106 timeQ = time.After(s.recvExpire) 107 } 108 sizeQ := s.sizeQ 109 recvQ := s.recvQ 110 closeQ := s.closeQ 111 s.Unlock() 112 select { 113 case <-closeQ: 114 return nil, protocol.ErrClosed 115 case <-timeQ: 116 return nil, protocol.ErrRecvTimeout 117 case m := <-recvQ: 118 return m, nil 119 case <-sizeQ: 120 continue 121 } 122 } 123 } 124 125 func (p *pipe) receiver() { 126 s := p.s 127 outer: 128 for { 129 m := p.p.RecvMsg() 130 if m == nil { 131 break 132 } 133 134 if len(m.Body) < 4 { 135 m.Free() 136 continue 137 } 138 139 m.Header = m.Body[:4] 140 m.Body = m.Body[4:] 141 142 s.Lock() 143 recvQ := s.recvQ 144 sizeQ := s.sizeQ 145 s.Unlock() 146 147 select { 148 case recvQ <- m: 149 continue 150 case <-sizeQ: // resize discards 151 m.Free() 152 continue 153 case <-p.closeQ: 154 m.Free() 155 break outer 156 } 157 } 158 p.close() 159 } 160 161 // This is a puller, and doesn't permit for priorities. We might want 162 // to refactor this to use a push based scheme later. 163 func (p *pipe) sender() { 164 s := p.s 165 outer: 166 for { 167 s.Lock() 168 sendQ := s.sendQ 169 sizeQ := s.sizeQ 170 s.Unlock() 171 172 var m *protocol.Message 173 select { 174 case m = <-sendQ: 175 case <-sizeQ: 176 continue 177 case <-p.closeQ: 178 break outer 179 } 180 181 if e := p.p.SendMsg(m); e != nil { 182 break 183 } 184 } 185 p.close() 186 } 187 188 func (p *pipe) close() { 189 _ = p.p.Close() 190 } 191 192 func (s *socket) SetOption(name string, value interface{}) error { 193 switch name { 194 195 case protocol.OptionRecvDeadline: 196 if v, ok := value.(time.Duration); ok { 197 s.Lock() 198 s.recvExpire = v 199 s.Unlock() 200 return nil 201 } 202 return protocol.ErrBadValue 203 204 case protocol.OptionSendDeadline: 205 if v, ok := value.(time.Duration); ok { 206 s.Lock() 207 s.sendExpire = v 208 s.Unlock() 209 return nil 210 } 211 return protocol.ErrBadValue 212 213 case protocol.OptionBestEffort: 214 if v, ok := value.(bool); ok { 215 s.Lock() 216 s.bestEffort = v 217 s.Unlock() 218 return nil 219 } 220 return protocol.ErrBadValue 221 222 case protocol.OptionWriteQLen: 223 if v, ok := value.(int); ok && v >= 0 { 224 225 newQ := make(chan *protocol.Message, v) 226 sizeQ := make(chan struct{}) 227 s.Lock() 228 s.sendQLen = v 229 s.sendQ = newQ 230 sizeQ, s.sizeQ = s.sizeQ, sizeQ 231 s.Unlock() 232 close(sizeQ) 233 return nil 234 } 235 return protocol.ErrBadValue 236 237 case protocol.OptionReadQLen: 238 if v, ok := value.(int); ok && v >= 0 { 239 newQ := make(chan *protocol.Message, v) 240 sizeQ := make(chan struct{}) 241 s.Lock() 242 s.recvQLen = v 243 s.recvQ = newQ 244 sizeQ, s.sizeQ = s.sizeQ, sizeQ 245 s.Unlock() 246 close(sizeQ) 247 return nil 248 } 249 return protocol.ErrBadValue 250 } 251 252 return protocol.ErrBadOption 253 } 254 255 func (s *socket) GetOption(option string) (interface{}, error) { 256 switch option { 257 case protocol.OptionRaw: 258 return true, nil 259 case protocol.OptionRecvDeadline: 260 s.Lock() 261 v := s.recvExpire 262 s.Unlock() 263 return v, nil 264 case protocol.OptionSendDeadline: 265 s.Lock() 266 v := s.sendExpire 267 s.Unlock() 268 return v, nil 269 case protocol.OptionBestEffort: 270 s.Lock() 271 v := s.bestEffort 272 s.Unlock() 273 return v, nil 274 case protocol.OptionWriteQLen: 275 s.Lock() 276 v := s.sendQLen 277 s.Unlock() 278 return v, nil 279 case protocol.OptionReadQLen: 280 s.Lock() 281 v := s.recvQLen 282 s.Unlock() 283 return v, nil 284 } 285 286 return nil, protocol.ErrBadOption 287 } 288 289 func (s *socket) Close() error { 290 s.Lock() 291 292 if s.closed { 293 s.Unlock() 294 return protocol.ErrClosed 295 } 296 s.closed = true 297 s.sendQ = nil 298 s.Unlock() 299 close(s.closeQ) 300 return nil 301 } 302 303 func (s *socket) AddPipe(pp protocol.Pipe) error { 304 s.Lock() 305 defer s.Unlock() 306 p := &pipe{ 307 p: pp, 308 s: s, 309 closeQ: make(chan struct{}), 310 } 311 pp.SetPrivate(p) 312 if s.closed { 313 return protocol.ErrClosed 314 } 315 316 go p.sender() 317 go p.receiver() 318 return nil 319 } 320 321 func (s *socket) RemovePipe(pp protocol.Pipe) { 322 p := pp.GetPrivate().(*pipe) 323 close(p.closeQ) 324 } 325 326 func (s *socket) OpenContext() (protocol.Context, error) { 327 return nil, protocol.ErrProtoOp 328 } 329 330 func (*socket) Info() protocol.Info { 331 return protocol.Info{ 332 Self: Self, 333 Peer: Peer, 334 SelfName: SelfName, 335 PeerName: PeerName, 336 } 337 } 338 339 // NewProtocol returns a new protocol implementation. 340 func NewProtocol() protocol.Protocol { 341 s := &socket{ 342 closeQ: make(chan struct{}), 343 sizeQ: make(chan struct{}), 344 recvQ: make(chan *protocol.Message, defaultQLen), 345 sendQ: make(chan *protocol.Message, defaultQLen), 346 sendQLen: defaultQLen, 347 recvQLen: defaultQLen, 348 } 349 return s 350 } 351 352 // NewSocket allocates a new Socket using the REQ protocol. 353 func NewSocket() (protocol.Socket, error) { 354 return protocol.MakeSocket(NewProtocol()), nil 355 }