|
30 | 30 |
|
31 | 31 | #include "upnp.h" |
32 | 32 |
|
33 | | -#include <miniwget.h> |
34 | | -#include <upnpcommands.h> |
35 | | - |
36 | | -#include <stdlib.h> |
37 | | - |
38 | | -bool UPNP::is_common_device(const String &dev) const { |
39 | | - return dev.is_empty() || |
40 | | - dev.contains("InternetGatewayDevice") || |
41 | | - dev.contains("WANIPConnection") || |
42 | | - dev.contains("WANPPPConnection") || |
43 | | - dev.contains("rootdevice"); |
44 | | -} |
45 | | - |
46 | | -int UPNP::discover(int timeout, int ttl, const String &device_filter) { |
47 | | - ERR_FAIL_COND_V_MSG(timeout < 0, UPNP_RESULT_INVALID_PARAM, "The response's wait time can't be negative."); |
48 | | - ERR_FAIL_COND_V_MSG(ttl < 0 || ttl > 255, UPNP_RESULT_INVALID_PARAM, "The time-to-live must be set between 0 and 255 (inclusive)."); |
49 | | - |
50 | | - devices.clear(); |
51 | | - |
52 | | - int error = 0; |
53 | | - struct UPNPDev *devlist; |
54 | | - |
55 | | - CharString cs = discover_multicast_if.utf8(); |
56 | | - const char *m_if = cs.length() ? cs.get_data() : nullptr; |
57 | | - if (is_common_device(device_filter)) { |
58 | | - devlist = upnpDiscover(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error); |
59 | | - } else { |
60 | | - devlist = upnpDiscoverAll(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error); |
61 | | - } |
62 | | - |
63 | | - if (error != UPNPDISCOVER_SUCCESS) { |
64 | | - switch (error) { |
65 | | - case UPNPDISCOVER_SOCKET_ERROR: |
66 | | - return UPNP_RESULT_SOCKET_ERROR; |
67 | | - case UPNPDISCOVER_MEMORY_ERROR: |
68 | | - return UPNP_RESULT_MEM_ALLOC_ERROR; |
69 | | - default: |
70 | | - return UPNP_RESULT_UNKNOWN_ERROR; |
71 | | - } |
72 | | - } |
73 | | - |
74 | | - if (!devlist) { |
75 | | - return UPNP_RESULT_NO_DEVICES; |
76 | | - } |
77 | | - |
78 | | - struct UPNPDev *dev = devlist; |
79 | | - |
80 | | - while (dev) { |
81 | | - if (device_filter.is_empty() || strstr(dev->st, device_filter.utf8().get_data())) { |
82 | | - add_device_to_list(dev, devlist); |
83 | | - } |
84 | | - |
85 | | - dev = dev->pNext; |
86 | | - } |
87 | | - |
88 | | - freeUPNPDevlist(devlist); |
89 | | - |
90 | | - return UPNP_RESULT_SUCCESS; |
91 | | -} |
92 | | - |
93 | | -void UPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) { |
94 | | - Ref<UPNPDevice> new_device; |
95 | | - new_device.instantiate(); |
96 | | - |
97 | | - new_device->set_description_url(dev->descURL); |
98 | | - new_device->set_service_type(dev->st); |
99 | | - |
100 | | - parse_igd(new_device, devlist); |
101 | | - |
102 | | - devices.push_back(new_device); |
103 | | -} |
104 | | - |
105 | | -char *UPNP::load_description(const String &url, int *size, int *status_code) const { |
106 | | - return (char *)miniwget(url.utf8().get_data(), size, 0, status_code); |
107 | | -} |
108 | | - |
109 | | -void UPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) { |
110 | | - int size = 0; |
111 | | - int status_code = -1; |
112 | | - char *xml = load_description(dev->get_description_url(), &size, &status_code); |
113 | | - |
114 | | - if (status_code != 200) { |
115 | | - dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_ERROR); |
116 | | - return; |
117 | | - } |
118 | | - |
119 | | - if (!xml || size < 1) { |
120 | | - dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_EMPTY); |
121 | | - return; |
122 | | - } |
123 | | - |
124 | | - struct UPNPUrls urls = {}; |
125 | | - struct IGDdatas data; |
126 | | - |
127 | | - parserootdesc(xml, size, &data); |
128 | | - free(xml); |
129 | | - xml = nullptr; |
130 | | - |
131 | | - GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0); |
132 | | - |
133 | | - char addr[16]; |
134 | | -#if MINIUPNPC_API_VERSION >= 18 |
135 | | - int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16, nullptr, 0); |
136 | | -#else |
137 | | - int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16); |
138 | | -#endif |
139 | | - |
140 | | - if (i != 1) { |
141 | | - FreeUPNPUrls(&urls); |
142 | | - |
143 | | - switch (i) { |
144 | | - case 0: |
145 | | - dev->set_igd_status(UPNPDevice::IGD_STATUS_NO_IGD); |
146 | | - return; |
147 | | - case 2: |
148 | | - dev->set_igd_status(UPNPDevice::IGD_STATUS_DISCONNECTED); |
149 | | - return; |
150 | | - case 3: |
151 | | - dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_DEVICE); |
152 | | - return; |
153 | | - default: |
154 | | - dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_ERROR); |
155 | | - return; |
156 | | - } |
157 | | - } |
158 | | - |
159 | | - if (urls.controlURL[0] == '\0') { |
160 | | - FreeUPNPUrls(&urls); |
161 | | - dev->set_igd_status(UPNPDevice::IGD_STATUS_INVALID_CONTROL); |
162 | | - return; |
163 | | - } |
164 | | - |
165 | | - dev->set_igd_control_url(urls.controlURL); |
166 | | - dev->set_igd_service_type(data.first.servicetype); |
167 | | - dev->set_igd_our_addr(addr); |
168 | | - dev->set_igd_status(UPNPDevice::IGD_STATUS_OK); |
169 | | - |
170 | | - FreeUPNPUrls(&urls); |
171 | | -} |
172 | | - |
173 | | -int UPNP::upnp_result(int in) { |
174 | | - switch (in) { |
175 | | - case UPNPCOMMAND_SUCCESS: |
176 | | - return UPNP_RESULT_SUCCESS; |
177 | | - case UPNPCOMMAND_UNKNOWN_ERROR: |
178 | | - return UPNP_RESULT_UNKNOWN_ERROR; |
179 | | - case UPNPCOMMAND_INVALID_ARGS: |
180 | | - return UPNP_RESULT_INVALID_ARGS; |
181 | | - case UPNPCOMMAND_HTTP_ERROR: |
182 | | - return UPNP_RESULT_HTTP_ERROR; |
183 | | - case UPNPCOMMAND_INVALID_RESPONSE: |
184 | | - return UPNP_RESULT_INVALID_RESPONSE; |
185 | | - case UPNPCOMMAND_MEM_ALLOC_ERROR: |
186 | | - return UPNP_RESULT_MEM_ALLOC_ERROR; |
187 | | - |
188 | | - case 402: |
189 | | - return UPNP_RESULT_INVALID_ARGS; |
190 | | - case 403: |
191 | | - return UPNP_RESULT_NOT_AUTHORIZED; |
192 | | - case 501: |
193 | | - return UPNP_RESULT_ACTION_FAILED; |
194 | | - case 606: |
195 | | - return UPNP_RESULT_NOT_AUTHORIZED; |
196 | | - case 714: |
197 | | - return UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY; |
198 | | - case 715: |
199 | | - return UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED; |
200 | | - case 716: |
201 | | - return UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED; |
202 | | - case 718: |
203 | | - return UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING; |
204 | | - case 724: |
205 | | - return UPNP_RESULT_SAME_PORT_VALUES_REQUIRED; |
206 | | - case 725: |
207 | | - return UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED; |
208 | | - case 726: |
209 | | - return UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD; |
210 | | - case 727: |
211 | | - return UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD; |
212 | | - case 728: |
213 | | - return UPNP_RESULT_NO_PORT_MAPS_AVAILABLE; |
214 | | - case 729: |
215 | | - return UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM; |
216 | | - case 732: |
217 | | - return UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED; |
218 | | - case 733: |
219 | | - return UPNP_RESULT_INCONSISTENT_PARAMETERS; |
220 | | - } |
221 | | - |
222 | | - return UPNP_RESULT_UNKNOWN_ERROR; |
223 | | -} |
224 | | - |
225 | | -int UPNP::get_device_count() const { |
226 | | - return devices.size(); |
227 | | -} |
228 | | - |
229 | | -Ref<UPNPDevice> UPNP::get_device(int index) const { |
230 | | - ERR_FAIL_INDEX_V(index, devices.size(), nullptr); |
231 | | - |
232 | | - return devices.get(index); |
233 | | -} |
234 | | - |
235 | | -void UPNP::add_device(Ref<UPNPDevice> device) { |
236 | | - ERR_FAIL_COND(device.is_null()); |
237 | | - |
238 | | - devices.push_back(device); |
239 | | -} |
240 | | - |
241 | | -void UPNP::set_device(int index, Ref<UPNPDevice> device) { |
242 | | - ERR_FAIL_INDEX(index, devices.size()); |
243 | | - ERR_FAIL_COND(device.is_null()); |
244 | | - |
245 | | - devices.set(index, device); |
246 | | -} |
247 | | - |
248 | | -void UPNP::remove_device(int index) { |
249 | | - ERR_FAIL_INDEX(index, devices.size()); |
250 | | - |
251 | | - devices.remove_at(index); |
252 | | -} |
253 | | - |
254 | | -void UPNP::clear_devices() { |
255 | | - devices.clear(); |
256 | | -} |
257 | | - |
258 | | -Ref<UPNPDevice> UPNP::get_gateway() const { |
259 | | - ERR_FAIL_COND_V_MSG(devices.is_empty(), nullptr, "Couldn't find any UPNPDevices."); |
260 | | - |
261 | | - for (int i = 0; i < devices.size(); i++) { |
262 | | - Ref<UPNPDevice> dev = get_device(i); |
263 | | - |
264 | | - if (dev.is_valid() && dev->is_valid_gateway()) { |
265 | | - return dev; |
266 | | - } |
267 | | - } |
268 | | - |
269 | | - return nullptr; |
270 | | -} |
271 | | - |
272 | | -void UPNP::set_discover_multicast_if(const String &m_if) { |
273 | | - discover_multicast_if = m_if; |
274 | | -} |
275 | | - |
276 | | -String UPNP::get_discover_multicast_if() const { |
277 | | - return discover_multicast_if; |
278 | | -} |
279 | | - |
280 | | -void UPNP::set_discover_local_port(int port) { |
281 | | - discover_local_port = port; |
282 | | -} |
283 | | - |
284 | | -int UPNP::get_discover_local_port() const { |
285 | | - return discover_local_port; |
286 | | -} |
287 | | - |
288 | | -void UPNP::set_discover_ipv6(bool ipv6) { |
289 | | - discover_ipv6 = ipv6; |
290 | | -} |
291 | | - |
292 | | -bool UPNP::is_discover_ipv6() const { |
293 | | - return discover_ipv6; |
294 | | -} |
295 | | - |
296 | | -String UPNP::query_external_address() const { |
297 | | - Ref<UPNPDevice> dev = get_gateway(); |
298 | | - |
299 | | - if (dev.is_null()) { |
300 | | - return ""; |
301 | | - } |
302 | | - |
303 | | - return dev->query_external_address(); |
304 | | -} |
305 | | - |
306 | | -int UPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { |
307 | | - Ref<UPNPDevice> dev = get_gateway(); |
308 | | - |
309 | | - if (dev.is_null()) { |
310 | | - return UPNP_RESULT_NO_GATEWAY; |
311 | | - } |
312 | | - |
313 | | - return dev->add_port_mapping(port, port_internal, desc, proto, duration); |
314 | | -} |
315 | | - |
316 | | -int UPNP::delete_port_mapping(int port, String proto) const { |
317 | | - Ref<UPNPDevice> dev = get_gateway(); |
318 | | - |
319 | | - if (dev.is_null()) { |
320 | | - return UPNP_RESULT_NO_GATEWAY; |
321 | | - } |
322 | | - |
323 | | - return dev->delete_port_mapping(port, proto); |
324 | | -} |
| 33 | +UPNP *(*UPNP::_create)(bool p_notify_postinitialize) = nullptr; |
325 | 34 |
|
326 | 35 | void UPNP::_bind_methods() { |
327 | 36 | ClassDB::bind_method(D_METHOD("get_device_count"), &UPNP::get_device_count); |
@@ -382,9 +91,3 @@ void UPNP::_bind_methods() { |
382 | 91 | BIND_ENUM_CONSTANT(UPNP_RESULT_NO_DEVICES); |
383 | 92 | BIND_ENUM_CONSTANT(UPNP_RESULT_UNKNOWN_ERROR); |
384 | 93 | } |
385 | | - |
386 | | -UPNP::UPNP() { |
387 | | -} |
388 | | - |
389 | | -UPNP::~UPNP() { |
390 | | -} |
0 commit comments