forked from miolini/upnp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
upnp.go
200 lines (183 loc) · 5 KB
/
upnp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package upnp
import (
"errors"
"fmt"
"log"
"sync"
)
/*
* Obtain Gateway
*/
//All the ports management
type MappingPortStruct struct {
lock *sync.Mutex
mappingPorts map[string][][]int
}
//Adding a port mapping record
//Only the mapping management
func (this *MappingPortStruct) addMapping(localPort, remotePort int, protocol string) {
this.lock.Lock()
defer this.lock.Unlock()
if this.mappingPorts == nil {
one := make([]int, 0)
one = append(one, localPort)
two := make([]int, 0)
two = append(two, remotePort)
portMapping := [][]int{one, two}
this.mappingPorts = map[string][][]int{protocol: portMapping}
return
}
portMapping := this.mappingPorts[protocol]
if portMapping == nil {
one := make([]int, 0)
one = append(one, localPort)
two := make([]int, 0)
two = append(two, remotePort)
this.mappingPorts[protocol] = [][]int{one, two}
return
}
one := portMapping[0]
two := portMapping[1]
one = append(one, localPort)
two = append(two, remotePort)
this.mappingPorts[protocol] = [][]int{one, two}
}
//Delete a mapping record
//Only the mapping management
func (this *MappingPortStruct) delMapping(remotePort int, protocol string) {
this.lock.Lock()
defer this.lock.Unlock()
if this.mappingPorts == nil {
return
}
tmp := MappingPortStruct{lock: new(sync.Mutex)}
mappings := this.mappingPorts[protocol]
for i := 0; i < len(mappings[0]); i++ {
if mappings[1][i] == remotePort {
//Mapping to be deleted
break
}
tmp.addMapping(mappings[0][i], mappings[1][i], protocol)
}
this.mappingPorts = tmp.mappingPorts
}
func (this *MappingPortStruct) GetAllMapping() map[string][][]int {
return this.mappingPorts
}
type Upnp struct {
Active bool //This protocol is available upnp
LocalHost string //The machine ip address
GatewayInsideIP string //LAN gateway ip
GatewayOutsideIP string //Gateway public network ip
OutsideMappingPort map[string]int //Mapping external port
InsideMappingPort map[string]int //Mapping the local port
Gateway *Gateway //Gateway Information
CtrlUrl string //Control request url
MappingPort MappingPortStruct //Mapping has been added {"TCP":[1990],"UDP":[1991]}
}
// Get the ip address of the local network
// Get the LAN gateway ip
func (this *Upnp) SearchGateway() (err error) {
defer func(err error) {
if errTemp := recover(); errTemp != nil {
log.Println("upnp module being given", errTemp)
err = errTemp.(error)
}
}(err)
if this.LocalHost == "" {
this.MappingPort = MappingPortStruct{
lock: new(sync.Mutex),
// mappingPorts: map[string][][]int{},
}
this.LocalHost, err = GetLocalIntenetIp()
if err != nil {
return err
}
}
searchGateway := SearchGateway{upnp: this}
ok, err := searchGateway.Send()
if err != nil {
return err
} else if ok {
return nil
}
return errors.New("No gateway device")
}
func (this *Upnp) deviceStatus() {
}
//See Device Description, get control request url
func (this *Upnp) deviceDesc() (err error) {
if this.GatewayInsideIP == "" {
if err := this.SearchGateway(); err != nil {
return err
}
}
device := DeviceDesc{upnp: this}
if _, err := device.Send(); err != nil {
return err
}
this.Active = true
// log.Println("Gain control request url:", this.CtrlUrl)
return
}
//View the ip address
func (this *Upnp) ExternalIPAddr() (err error) {
if this.CtrlUrl == "" {
if err := this.deviceDesc(); err != nil {
return err
}
}
eia := ExternalIPAddress{upnp: this}
eia.Send()
return nil
// log.Println("Obtain public network ip address:", this.GatewayOutsideIP)
}
//Adding a port mapping
func (this *Upnp) AddPortMapping(localPort, remotePort int, protocol string) (err error) {
defer func(err *error) {
if errTemp := recover(); errTemp != nil {
*err = fmt.Errorf("panic err: %s", err)
}
}(&err)
if this.GatewayOutsideIP == "" {
if err := this.ExternalIPAddr(); err != nil {
return err
}
}
addPort := AddPortMapping{upnp: this}
if issuccess := addPort.Send(localPort, remotePort, protocol); issuccess {
this.MappingPort.addMapping(localPort, remotePort, protocol)
return nil
} else {
this.Active = false
return errors.New("Adding a port mapping failed")
}
}
func (this *Upnp) DelPortMapping(remotePort int, protocol string) bool {
delMapping := DelPortMapping{upnp: this}
issuccess := delMapping.Send(remotePort, protocol)
if issuccess {
this.MappingPort.delMapping(remotePort, protocol)
log.Println("To delete a port mapping: remote:", remotePort)
}
return issuccess
}
//Recycling port
func (this *Upnp) Reclaim() {
mappings := this.MappingPort.GetAllMapping()
tcpMapping, ok := mappings["TCP"]
if ok {
for i := 0; i < len(tcpMapping[0]); i++ {
this.DelPortMapping(tcpMapping[1][i], "TCP")
}
}
udpMapping, ok := mappings["UDP"]
if ok {
for i := 0; i < len(udpMapping[0]); i++ {
this.DelPortMapping(udpMapping[0][i], "UDP")
}
}
}
func (this *Upnp) GetAllMapping() map[string][][]int {
return this.MappingPort.GetAllMapping()
}