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