github.com/gdamore/mangos@v1.4.0/protocol/pair/pair.go (about) 1 // Copyright 2018 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 pair implements the PAIR protocol. This protocol is a 1:1 16 // peering protocol. 17 package pair 18 19 import ( 20 "sync" 21 "time" 22 23 "nanomsg.org/go-mangos" 24 ) 25 26 type pair struct { 27 sock mangos.ProtocolSocket 28 peer *pairEp 29 raw bool 30 w mangos.Waiter 31 sync.Mutex 32 } 33 34 type pairEp struct { 35 ep mangos.Endpoint 36 cq chan struct{} 37 } 38 39 func (x *pair) Init(sock mangos.ProtocolSocket) { 40 x.sock = sock 41 x.w.Init() 42 } 43 44 func (x *pair) Shutdown(expire time.Time) { 45 x.w.WaitAbsTimeout(expire) 46 } 47 48 func (x *pair) sender(ep *pairEp) { 49 50 defer x.w.Done() 51 sq := x.sock.SendChannel() 52 cq := x.sock.CloseChannel() 53 54 // This is pretty easy because we have only one peer at a time. 55 // If the peer goes away, we'll just drop the message on the floor. 56 for { 57 select { 58 case m := <-sq: 59 if m == nil { 60 sq = x.sock.SendChannel() 61 continue 62 } 63 if ep.ep.SendMsg(m) != nil { 64 m.Free() 65 return 66 } 67 case <-ep.cq: 68 return 69 case <-cq: 70 return 71 } 72 } 73 } 74 75 func (x *pair) receiver(ep *pairEp) { 76 77 rq := x.sock.RecvChannel() 78 cq := x.sock.CloseChannel() 79 80 for { 81 m := ep.ep.RecvMsg() 82 if m == nil { 83 return 84 } 85 86 select { 87 case rq <- m: 88 case <-cq: 89 return 90 } 91 } 92 } 93 94 func (x *pair) AddEndpoint(ep mangos.Endpoint) { 95 peer := &pairEp{cq: make(chan struct{}), ep: ep} 96 x.Lock() 97 if x.peer != nil { 98 // We already have a connection, reject this one. 99 x.Unlock() 100 ep.Close() 101 return 102 } 103 x.peer = peer 104 x.Unlock() 105 106 x.w.Add() 107 go x.receiver(peer) 108 go x.sender(peer) 109 } 110 111 func (x *pair) RemoveEndpoint(ep mangos.Endpoint) { 112 x.Lock() 113 if peer := x.peer; peer != nil && peer.ep == ep { 114 x.peer = nil 115 close(peer.cq) 116 } 117 x.Unlock() 118 } 119 120 func (*pair) Number() uint16 { 121 return mangos.ProtoPair 122 } 123 124 func (*pair) Name() string { 125 return "pair" 126 } 127 128 func (*pair) PeerNumber() uint16 { 129 return mangos.ProtoPair 130 } 131 132 func (*pair) PeerName() string { 133 return "pair" 134 } 135 136 func (x *pair) SetOption(name string, v interface{}) error { 137 var ok bool 138 switch name { 139 case mangos.OptionRaw: 140 if x.raw, ok = v.(bool); !ok { 141 return mangos.ErrBadValue 142 } 143 return nil 144 default: 145 return mangos.ErrBadOption 146 } 147 } 148 149 func (x *pair) GetOption(name string) (interface{}, error) { 150 switch name { 151 case mangos.OptionRaw: 152 return x.raw, nil 153 default: 154 return nil, mangos.ErrBadOption 155 } 156 } 157 158 // NewSocket allocates a new Socket using the PAIR protocol. 159 func NewSocket() (mangos.Socket, error) { 160 return mangos.MakeSocket(&pair{}), nil 161 }