github.com/gdamore/mangos@v1.4.0/pipe.go (about) 1 // Copyright 2015 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 mangos 16 17 import ( 18 "math/rand" 19 "sync" 20 "time" 21 ) 22 23 var pipes struct { 24 byid map[uint32]*pipe 25 nextid uint32 26 sync.Mutex 27 } 28 29 // pipe wraps the Pipe data structure with the stuff we need to keep 30 // for the core. It implements the Endpoint interface. 31 type pipe struct { 32 pipe Pipe 33 closeq chan struct{} // only closed, never passes data 34 id uint32 35 index int // index in master list of pipes for socket 36 37 l *listener 38 d *dialer 39 sock *socket 40 closing bool // true if we were closed 41 42 sync.Mutex 43 } 44 45 func init() { 46 pipes.byid = make(map[uint32]*pipe) 47 pipes.nextid = uint32(rand.NewSource(time.Now().UnixNano()).Int63()) 48 } 49 50 func newPipe(tranpipe Pipe) *pipe { 51 p := &pipe{pipe: tranpipe, index: -1} 52 p.closeq = make(chan struct{}) 53 for { 54 pipes.Lock() 55 p.id = pipes.nextid & 0x7fffffff 56 pipes.nextid++ 57 if p.id != 0 && pipes.byid[p.id] == nil { 58 pipes.byid[p.id] = p 59 pipes.Unlock() 60 break 61 } 62 pipes.Unlock() 63 } 64 return p 65 } 66 67 func (p *pipe) GetID() uint32 { 68 return p.id 69 } 70 71 func (p *pipe) Close() error { 72 var hook PortHook 73 p.Lock() 74 sock := p.sock 75 if sock != nil { 76 hook = sock.porthook 77 } 78 if p.closing { 79 p.Unlock() 80 return nil 81 } 82 p.closing = true 83 p.Unlock() 84 close(p.closeq) 85 if sock != nil { 86 sock.remPipe(p) 87 } 88 p.pipe.Close() 89 pipes.Lock() 90 delete(pipes.byid, p.id) 91 pipes.Unlock() 92 if hook != nil { 93 hook(PortActionRemove, p) 94 } 95 return nil 96 } 97 98 func (p *pipe) SendMsg(msg *Message) error { 99 100 if err := p.pipe.Send(msg); err != nil { 101 p.Close() 102 return err 103 } 104 return nil 105 } 106 107 func (p *pipe) RecvMsg() *Message { 108 109 msg, err := p.pipe.Recv() 110 if err != nil { 111 p.Close() 112 return nil 113 } 114 msg.Port = p 115 return msg 116 } 117 118 func (p *pipe) Address() string { 119 switch { 120 case p.l != nil: 121 return p.l.Address() 122 case p.d != nil: 123 return p.d.Address() 124 } 125 return "" 126 } 127 128 func (p *pipe) GetProp(name string) (interface{}, error) { 129 return p.pipe.GetProp(name) 130 } 131 132 func (p *pipe) IsOpen() bool { 133 return p.pipe.IsOpen() 134 } 135 136 func (p *pipe) IsClient() bool { 137 return p.d != nil 138 } 139 140 func (p *pipe) IsServer() bool { 141 return p.l != nil 142 } 143 144 func (p *pipe) LocalProtocol() uint16 { 145 return p.pipe.LocalProtocol() 146 } 147 148 func (p *pipe) RemoteProtocol() uint16 { 149 return p.pipe.RemoteProtocol() 150 } 151 152 func (p *pipe) Dialer() Dialer { 153 return p.d 154 } 155 156 func (p *pipe) Listener() Listener { 157 return p.l 158 }