Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51581e1578 | ||
|
|
1148c6156e | ||
|
|
256433a00b | ||
|
|
2559aec92d | ||
|
|
9e2ae4aca4 | ||
|
|
c12cc8e5be | ||
|
|
03d58e9e62 | ||
|
|
17739435de | ||
|
|
4118d0bbd2 | ||
|
|
f4ac760178 | ||
|
|
cb1c8df547 | ||
|
|
7db6e58273 | ||
|
|
bb362f307d | ||
|
|
ced1dc10c1 | ||
|
|
4f02450bf9 | ||
|
|
2f21a3e370 | ||
|
|
ff575a3460 | ||
|
|
d9c78c75f0 | ||
|
|
4b796ae740 | ||
|
|
c7722143b9 | ||
|
|
6a68a01eb9 | ||
|
|
310c486f6a | ||
|
|
e7be847784 | ||
|
|
4318000f8f | ||
|
|
cf82bdbebd | ||
|
|
85e5a01576 | ||
|
|
7d9edc0874 | ||
|
|
12a208f75e | ||
|
|
ec14874363 | ||
|
|
c5717ecd84 | ||
|
|
c343a88c10 | ||
|
|
9a7d38de77 | ||
|
|
1a251de6be | ||
|
|
c6b1a4bb48 | ||
|
|
2df1ed9157 | ||
|
|
bd6ca986d8 | ||
|
|
bf553fe65c | ||
|
|
8a01dda5d6 | ||
|
|
f2c4eb5047 | ||
|
|
1f42889936 | ||
|
|
1fc7a50f3e | ||
|
|
7aca744635 | ||
|
|
c7c0e1351a | ||
|
|
4f2cdf3a84 | ||
|
|
79899e6b71 | ||
|
|
ad6733b519 | ||
|
|
9c19f16539 | ||
|
|
0d81b2005f | ||
|
|
21fe0c8499 | ||
|
|
fb3393eb3a | ||
|
|
101475c2f6 | ||
|
|
c31823aa94 | ||
|
|
c99d83f15c | ||
|
|
71b0666ec5 | ||
|
|
0123d33780 | ||
|
|
3a5eb48c4a | ||
|
|
df1313bc37 | ||
|
|
bb15b14388 | ||
|
|
c70b8c42c5 | ||
|
|
63973a52e0 | ||
|
|
a5c57fe882 | ||
|
|
79bde3f9b1 | ||
|
|
0b7ef78122 | ||
|
|
279b2e1123 | ||
|
|
e122c91519 | ||
|
|
e758406d52 | ||
|
|
e587264b3d | ||
|
|
69694a2fab | ||
|
|
c808fa54c7 | ||
|
|
130e3a77d8 | ||
|
|
199d7b63a1 | ||
|
|
bb0d4dae07 | ||
|
|
d019855439 | ||
|
|
b8020c0c21 | ||
|
|
baa666022f | ||
|
|
aed6fa83bd | ||
|
|
5f2e6c4320 | ||
|
|
b5a01bc42e | ||
|
|
36c2d457fc | ||
|
|
013bf29fff | ||
|
|
002928c399 | ||
|
|
ec395048b6 | ||
|
|
85b099b8cf | ||
|
|
a2def14969 | ||
|
|
4109ffdb6b | ||
|
|
96650e14ea | ||
|
|
dbd359ad6a | ||
|
|
18e1a817b3 | ||
|
|
34e3490ce9 | ||
|
|
693652b2a9 | ||
|
|
fea8a0f780 | ||
|
|
f39de90837 | ||
|
|
eba92bd3ca | ||
|
|
2481d25f0f | ||
|
|
57e0e30600 | ||
|
|
6396f0391a | ||
|
|
3cecdcdd7d | ||
|
|
824a619b90 | ||
|
|
ef1323bbfd | ||
|
|
56eb09406b | ||
|
|
c17dbe6ddb | ||
|
|
2fa9d47b61 | ||
|
|
aff63e6c3f | ||
|
|
8195c601d5 | ||
|
|
05b760d0f8 | ||
|
|
5bf5388759 | ||
|
|
59f5c596d6 | ||
|
|
0c456c2235 | ||
|
|
2be88a44ed | ||
|
|
b30b9599a2 | ||
|
|
8fb1f6a647 | ||
|
|
35d78bb010 | ||
|
|
ba4804ed7c | ||
|
|
650655abbe | ||
|
|
e50ea80dfa | ||
|
|
92bbeab6f6 | ||
|
|
5ca55aa533 | ||
|
|
c9add8c68e | ||
|
|
b719f30b8e | ||
|
|
2bdd938338 | ||
|
|
fc3547b8e4 | ||
|
|
64a11ca0f4 | ||
|
|
834087d1ad | ||
|
|
46c153a0fe | ||
|
|
a26e229445 | ||
|
|
15001a87d3 | ||
|
|
58c08c0c02 | ||
|
|
10bf8d4a8a | ||
|
|
308aa4678f | ||
|
|
4b84449f59 | ||
|
|
a6420ae966 | ||
|
|
951ca852f5 | ||
|
|
c0ac7095fa | ||
|
|
ae92a0ceff | ||
|
|
ddae075733 | ||
|
|
9ebd8736e0 | ||
|
|
7974fb5c6e | ||
|
|
803dd83e67 | ||
|
|
43c32aad3d | ||
|
|
fdbdcfee65 | ||
|
|
216e7bcdaf | ||
|
|
89715b7195 | ||
|
|
b7b3b2cb5f | ||
|
|
8f01bcfb8d | ||
|
|
af971ea9be | ||
|
|
c2036e4aed | ||
|
|
19bf048b68 | ||
|
|
c653e6d886 | ||
|
|
e523280cb0 | ||
|
|
24b9237669 | ||
|
|
e48bd0b2b5 | ||
|
|
aa2e7dc794 | ||
|
|
a55df42978 | ||
|
|
1e96a600d7 | ||
|
|
2b1fbca318 | ||
|
|
671771d3cd | ||
|
|
ca2716eef7 | ||
|
|
2dfb9b9638 | ||
|
|
9062f62375 | ||
|
|
e89706d251 | ||
|
|
a16ba84502 | ||
|
|
ed51eaf449 | ||
|
|
3c0afd730b | ||
|
|
5eab3e3d96 | ||
|
|
da8662bb4a | ||
|
|
3ae52e2095 | ||
|
|
26474ee99e | ||
|
|
af02707298 | ||
|
|
cc75e002cd | ||
|
|
d6ecfd42b5 | ||
|
|
59b86027e9 | ||
|
|
fd5836d4e7 | ||
|
|
07cfd90dc6 | ||
|
|
a3e3b3e790 | ||
|
|
db02a0c52a | ||
|
|
b36683ba09 | ||
|
|
e6bdc9363c | ||
|
|
7a510000bb | ||
|
|
3ff9a43b7d | ||
|
|
d462e91659 | ||
|
|
b5b87d7735 | ||
|
|
6146daf5e8 | ||
|
|
b8e68030d0 | ||
|
|
dcd4d6b422 | ||
|
|
d969229f6a | ||
|
|
1f9059f2b5 | ||
|
|
f9ca3c9d87 | ||
|
|
8cbb4e13ee | ||
|
|
2074d25441 | ||
|
|
aaef2bb820 | ||
|
|
8de102e607 | ||
|
|
e495671563 | ||
|
|
3e0bc5acdc | ||
|
|
22223fa6c4 | ||
|
|
1dcf57c046 | ||
|
|
cec74a9460 | ||
|
|
c5b7a69801 | ||
|
|
4e0c24acbe | ||
|
|
c8dfdaa5ff | ||
|
|
d1ab288d73 | ||
|
|
e70ee045bf | ||
|
|
342d399a2a | ||
|
|
13ef64769d | ||
|
|
1499a7ec64 | ||
|
|
7e029a5981 | ||
|
|
8a6e102a82 | ||
|
|
bd9e2e5fc7 | ||
|
|
dba6c537f2 | ||
|
|
e9f1b25e55 | ||
|
|
378a69aba9 | ||
|
|
80fff292d8 | ||
|
|
c72311a708 | ||
|
|
d61d55e3ea | ||
|
|
ea56249661 | ||
|
|
8eb32fa824 | ||
|
|
ac9aa4783a | ||
|
|
4403734d97 | ||
|
|
5e6a79c4ac | ||
|
|
636ab5c12c | ||
|
|
44f08a4739 | ||
|
|
f7f333477c | ||
|
|
188141a628 | ||
|
|
d2a5f53f8d | ||
|
|
4746bbc972 | ||
|
|
22500914e1 | ||
|
|
4e1b4d051d | ||
|
|
238e234106 | ||
|
|
457b54149d | ||
|
|
dc4464471e | ||
|
|
60f0b42b1c | ||
|
|
5eec1c1f39 | ||
|
|
f7bbafa93d | ||
|
|
d06273e38a | ||
|
|
ef5b26350d | ||
|
|
7c83071b01 | ||
|
|
8b4893965f | ||
|
|
4645e7709b | ||
|
|
2ed15fbfbc | ||
|
|
9540e91e4c | ||
|
|
31bf313a4f | ||
|
|
21ddee6690 | ||
|
|
c6e150ae2a | ||
|
|
f8576ca88c | ||
|
|
1cccfa09fb | ||
|
|
63eafbcac2 | ||
|
|
e3ddb75a2a | ||
|
|
1068e67032 | ||
|
|
40536fde63 | ||
|
|
227b862cba | ||
|
|
85053cb210 | ||
|
|
c215fef8dd | ||
|
|
f553f3f6bd | ||
|
|
d789013789 | ||
|
|
0789fff6df | ||
|
|
460e28f7e5 | ||
|
|
873a07030f | ||
|
|
d0c640af7f | ||
|
|
2d239779a5 | ||
|
|
d3e8e66b9f | ||
|
|
03948eafd3 | ||
|
|
9087bc82a0 | ||
|
|
8206a751f0 | ||
|
|
1ec7b79ad6 | ||
|
|
d0e49a2d8f | ||
|
|
d7fda3016e | ||
|
|
d74f1a56f3 | ||
|
|
4bbf2ab535 | ||
|
|
b648f459c4 | ||
|
|
8d188ff013 | ||
|
|
af54ca3547 | ||
|
|
36f5504375 | ||
|
|
fc8063b334 | ||
|
|
eebc239348 | ||
|
|
a1124b8ded | ||
|
|
c6d255ef63 | ||
|
|
81949ae2fe | ||
|
|
631586b0b7 | ||
|
|
a7592c2db7 | ||
|
|
0e24e2a9ef | ||
|
|
14297ef0d9 | ||
|
|
b6fcc0dfac | ||
|
|
0a3cc7da52 | ||
|
|
409a7769c6 | ||
|
|
1582a47bb9 | ||
|
|
f80064e0a3 | ||
|
|
90b9cf2d46 | ||
|
|
0b5118423d | ||
|
|
e075ade748 | ||
|
|
cca72126f2 | ||
|
|
96210188b0 | ||
|
|
ba16bee5d1 | ||
|
|
91ed01dbcc | ||
|
|
972b41f803 | ||
|
|
ef5b8046f0 | ||
|
|
5f723d1bda | ||
|
|
28e8b6090c | ||
|
|
b700a4e77b | ||
|
|
b42fdf3bdc | ||
|
|
4fb3315091 | ||
|
|
0d873b6da1 | ||
|
|
962149ef63 | ||
|
|
9964f8e717 | ||
|
|
2d88530c98 | ||
|
|
43569c254c | ||
|
|
24b28e59c8 | ||
|
|
093916abfe | ||
|
|
bb542332dc | ||
|
|
712724e0ff | ||
|
|
af8f0eb9b2 | ||
|
|
aaaba64f81 | ||
|
|
90d6466d56 | ||
|
|
b15698e6d2 | ||
|
|
67a311a76b | ||
|
|
b59e015b8b | ||
|
|
f05da5c0e1 | ||
|
|
7ee65bfe5d | ||
|
|
3cfaf47637 | ||
|
|
342be9a594 | ||
|
|
f33b6bc226 | ||
|
|
0d945a81d7 | ||
|
|
75188800b1 | ||
|
|
e51cfce8e3 | ||
|
|
2cbd1898e8 | ||
|
|
0231585d06 | ||
|
|
e980577531 | ||
|
|
d1aff197b9 | ||
|
|
5576115389 | ||
|
|
e6ee2527e5 | ||
|
|
e9524f1b95 | ||
|
|
acb20e2d28 | ||
|
|
cd3a58224f | ||
|
|
cb1aab93db | ||
|
|
85478b8fc8 | ||
|
|
461d6ed3e0 | ||
|
|
5a74bbb0b3 | ||
|
|
7a5ed7cc65 | ||
|
|
4964892e59 | ||
|
|
ba4d57ba70 | ||
|
|
7030c64bde | ||
|
|
0955667f0d | ||
|
|
5974acc3c7 | ||
|
|
139d2d65d7 | ||
|
|
816d7786ac | ||
|
|
47d5242dd7 | ||
|
|
8114ce70d2 | ||
|
|
742e45c6eb | ||
|
|
4db257c104 | ||
|
|
abc7da4c87 | ||
|
|
5d8c191df7 | ||
|
|
91f2cd0b95 | ||
|
|
4b63ef3123 | ||
|
|
c6502e9f2d | ||
|
|
da5966d474 | ||
|
|
b3d71320bc | ||
|
|
18f614ef8a | ||
|
|
5f78d0594c | ||
|
|
417cf09967 | ||
|
|
a51b751814 | ||
|
|
37b2ebfcaa | ||
|
|
14c1d48c66 | ||
|
|
f00dd6f7c4 | ||
|
|
3a6c7b96fd | ||
|
|
1b2685949a | ||
|
|
37baccab99 | ||
|
|
db4b757843 | ||
|
|
cd1b95220a | ||
|
|
4c1abfaa71 | ||
|
|
d0b29f3d8e | ||
|
|
6309b21252 | ||
|
|
8da9acd1fe | ||
|
|
f84b6e9020 | ||
|
|
604b49f7d3 | ||
|
|
71b397902a | ||
|
|
a67935404d | ||
|
|
4f039cac22 | ||
|
|
d8e38bedf0 | ||
|
|
a624e617ed | ||
|
|
75a96b10bb | ||
|
|
e05a8a7460 | ||
|
|
8aa8d6ff6b | ||
|
|
6d821132f5 | ||
|
|
a8f2f94bf6 | ||
|
|
6659c6af3a | ||
|
|
91ebcc0680 | ||
|
|
6e969d0bc6 | ||
|
|
0143b537a8 | ||
|
|
07881d9f4f | ||
|
|
b52bdeb038 | ||
|
|
04904c5c9e | ||
|
|
854fd3f1f9 | ||
|
|
ab7ac777d7 | ||
|
|
31c65140c4 | ||
|
|
4241e4fedb | ||
|
|
6395907887 | ||
|
|
31a62a63f6 | ||
|
|
b5c87b68f8 | ||
|
|
c8f3c15cf5 | ||
|
|
d7ff3c809f | ||
|
|
28deb34742 | ||
|
|
66c3599019 | ||
|
|
672add6cab | ||
|
|
e9cbde3188 | ||
|
|
0b75671c21 | ||
|
|
89244d0e58 | ||
|
|
4fc758799f | ||
|
|
55de1ff8c6 | ||
|
|
77e479a8bc | ||
|
|
66ff3db2e2 | ||
|
|
af7c346e23 | ||
|
|
e0cbce96c5 | ||
|
|
640dca71cf | ||
|
|
8783d92f23 | ||
|
|
0f1943259e | ||
|
|
7a79ee68d9 | ||
|
|
9e09b28f50 | ||
|
|
5ea570c978 | ||
|
|
0c5fe1dd79 | ||
|
|
25a29a4e0a | ||
|
|
b2f4359234 | ||
|
|
8e6df5fe85 | ||
|
|
754b7326f3 | ||
|
|
cd17927990 | ||
|
|
a33778cb87 | ||
|
|
d1b93741d7 | ||
|
|
b04bf809e3 | ||
|
|
f0e45e970c | ||
|
|
4915f452f5 | ||
|
|
a0379f0598 | ||
|
|
1c2e97b0c1 | ||
|
|
bd40dd3ec2 | ||
|
|
9993435cf9 | ||
|
|
8d2bafb279 | ||
|
|
3785fc4524 | ||
|
|
bd8ecd9dfd | ||
|
|
962cf6b076 | ||
|
|
890f28ae71 | ||
|
|
90aa5ef8a5 | ||
|
|
373535f329 | ||
|
|
35f8ed82a0 | ||
|
|
0617262cd2 | ||
|
|
1ef482d6df | ||
|
|
452c3529a8 | ||
|
|
c3701783b1 | ||
|
|
a2141e61f7 | ||
|
|
46797c982b | ||
|
|
98003ecf5d | ||
|
|
ee6d76e932 | ||
|
|
c9015aa9ba | ||
|
|
ddeaf2c893 | ||
|
|
8005970842 | ||
|
|
aa77d688ec | ||
|
|
e98fac2046 | ||
|
|
593d1ff7b5 | ||
|
|
959b1c4b13 | ||
|
|
c7297d41b2 | ||
|
|
9158573fda | ||
|
|
cea6945963 | ||
|
|
52d46dcaf4 | ||
|
|
6e5b7c3a7b | ||
|
|
0bdcdac2da | ||
|
|
83619b25e6 | ||
|
|
bfcb8227f5 | ||
|
|
b5153ced9d | ||
|
|
6b9ba1e2b1 | ||
|
|
c866a3f1a8 | ||
|
|
a56a825dfb | ||
|
|
fa341f03a0 | ||
|
|
0383d20465 | ||
|
|
4e0ed3d3d6 | ||
|
|
e6102fed35 | ||
|
|
c1e08c1138 | ||
|
|
e95f797307 | ||
|
|
e99ba9a06a | ||
|
|
df962d5898 | ||
|
|
7d30b475ba | ||
|
|
0ef09a0ed4 | ||
|
|
38bfed4a93 | ||
|
|
b3cd6f13a5 | ||
|
|
e3a1b1859d | ||
|
|
a06380e9ca | ||
|
|
233c13228e | ||
|
|
f1b63bddbe | ||
|
|
0c8ee93e3e | ||
|
|
49cb7789f7 | ||
|
|
92eac10560 | ||
|
|
74d29c4b40 | ||
|
|
30f8505647 | ||
|
|
ba98ecd081 | ||
|
|
2c721a478c | ||
|
|
168de31fb9 | ||
|
|
3e8e02c953 | ||
|
|
10157c5831 | ||
|
|
f4c187e980 |
No files matched your search
@@ -0,0 +1,37 @@
|
||||
# 1.5.0 (future)
|
||||
- MOBILE: Single-tap for menu entry selection
|
||||
- MOBILE: Long-tap a setting to reset to default
|
||||
- ANDROID: Autoconf fallback
|
||||
- ANDROID: Mouse support / Emulated mouse support
|
||||
- AUTOCONF: Fix partial matches for pad name
|
||||
- CHEEVOS: Fix crashes in the cheevos description menu
|
||||
- CHEEVOS: WIP leaderboards support
|
||||
- COMMON: Threading fixes
|
||||
- COMMON: 9-slice texture drawing support
|
||||
- CORETEXT/APPLE: Ability to load menu display font drivers and loading of custom font.
|
||||
- DOS: Add keyboard driver
|
||||
- DOS: Improve color accuracy and scaling
|
||||
- GUI: Various settings are now only visible when advanced settings is enabled
|
||||
- GUI: Allow changing icon theme on the fly
|
||||
- GUI: Add a symbol page in the OSK
|
||||
- GUI: Better dialogs for XMB
|
||||
- LOCALIZATION: Add/update Korean translation
|
||||
- LOCALIZATION: Rewrite German translation
|
||||
- LOCALIZATION: Update several English sublabels
|
||||
- LOCALIZATION: Update several Japanese labels
|
||||
- NET: Allow manual netplay content loading
|
||||
- NET: Announcing network games to the public lobby is optional now
|
||||
- NET: Bake in miniupnpc
|
||||
- NET: Fix netplay join for contentless cores
|
||||
- NET: Lan games show next to lobbies with (lan) and connect via the private IP address
|
||||
- NET: Use new lobby system with MITM support
|
||||
- NET: Fix netplay rooms being pushed on the wrong tab
|
||||
- NUKLEAR: Update to current version
|
||||
- SCANNER: Always add 7z & zip to supported extensions
|
||||
- VULKAN: Find supported composite alpha in swapchain
|
||||
- VULKAN: Add snow/bokeh shader pipeline effects - at parity with GL now
|
||||
- WIIU: Keyboard support
|
||||
- WINDOWS: Logging to file no longer spawns an empty window
|
||||
- WINDOWS: Fix loading of core/content via file menu
|
||||
|
||||
# 1.4.1
|
||||
@@ -28,7 +28,7 @@ ifneq ($(findstring DOS,$(OS)),)
|
||||
endif
|
||||
|
||||
ifneq ($(findstring Win32,$(OS)),)
|
||||
LDFLAGS += -static-libgcc
|
||||
LDFLAGS += -static-libgcc -lwinmm
|
||||
endif
|
||||
|
||||
include Makefile.common
|
||||
|
||||
@@ -186,6 +186,7 @@ OBJ += frontend/frontend.o \
|
||||
file_path_str.o \
|
||||
$(LIBRETRO_COMM_DIR)/hash/rhash.o \
|
||||
audio/audio_driver.o \
|
||||
audio/audio_mixer.o \
|
||||
input/input_driver.o \
|
||||
gfx/video_coord_array.o \
|
||||
gfx/video_driver.o \
|
||||
@@ -198,6 +199,7 @@ OBJ += frontend/frontend.o \
|
||||
dynamic.o \
|
||||
cores/dynamic_dummy.o \
|
||||
$(LIBRETRO_COMM_DIR)/queues/message_queue.o \
|
||||
managers/core_manager.o \
|
||||
managers/state_manager.o \
|
||||
gfx/drivers_font_renderer/bitmapfont.o \
|
||||
tasks/task_autodetect.o \
|
||||
@@ -264,6 +266,7 @@ OBJ += intl/msg_hash_de.o \
|
||||
intl/msg_hash_fr.o \
|
||||
intl/msg_hash_it.o \
|
||||
intl/msg_hash_ja.o \
|
||||
intl/msg_hash_ko.o \
|
||||
intl/msg_hash_nl.o \
|
||||
intl/msg_hash_pl.o \
|
||||
intl/msg_hash_pt.o \
|
||||
@@ -451,9 +454,9 @@ ifeq ($(HAVE_NEON),1)
|
||||
endif
|
||||
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/audio/conversion/s16_to_float.o \
|
||||
$(LIBRETRO_COMM_DIR)/audio/conversion/float_to_s16.o \
|
||||
$(LIBRETRO_COMM_DIR)/audio/audio_mix.o \
|
||||
$(LIBRETRO_COMM_DIR)/formats/wav/rwav.o
|
||||
$(LIBRETRO_COMM_DIR)/audio/conversion/float_to_s16.o \
|
||||
$(LIBRETRO_COMM_DIR)/audio/audio_mix.o \
|
||||
$(LIBRETRO_COMM_DIR)/formats/wav/rwav.o
|
||||
|
||||
ifeq ($(HAVE_NEON),1)
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/audio/conversion/s16_to_float_neon.o \
|
||||
@@ -1114,6 +1117,7 @@ endif
|
||||
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/formats/bmp/rbmp_encode.o \
|
||||
$(LIBRETRO_COMM_DIR)/formats/json/jsonsax.o \
|
||||
$(LIBRETRO_COMM_DIR)/formats/json/jsonsax_full.o \
|
||||
$(LIBRETRO_COMM_DIR)/formats/image_transfer.o
|
||||
|
||||
ifdef HAVE_COMPRESSION
|
||||
@@ -1165,6 +1169,7 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
network/net_http_special.o \
|
||||
tasks/task_http.o \
|
||||
tasks/task_netplay_lan_scan.o \
|
||||
tasks/task_netplay_nat_traversal.o \
|
||||
tasks/task_wifi.o \
|
||||
tasks/task_netplay_find_content.o
|
||||
|
||||
@@ -1190,14 +1195,15 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
network/netplay/netplay_io.o \
|
||||
network/netplay/netplay_sync.o \
|
||||
network/netplay/netplay_discovery.o \
|
||||
network/netplay/netplay_buf.o
|
||||
network/netplay/netplay_buf.o \
|
||||
network/netplay/netplay_room_parse.o
|
||||
|
||||
# Retro Achievements (also depends on threads)
|
||||
|
||||
ifeq ($(HAVE_CHEEVOS), 1)
|
||||
ifeq ($(HAVE_THREADS), 1)
|
||||
DEFINES += -DHAVE_CHEEVOS
|
||||
OBJ += cheevos.o \
|
||||
OBJ += cheevos/cheevos.o \
|
||||
$(LIBRETRO_COMM_DIR)/utils/md5.o
|
||||
endif
|
||||
endif
|
||||
@@ -1208,7 +1214,26 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_MINIUPNPC), 1)
|
||||
LIBS += -lminiupnpc
|
||||
ifeq ($(HAVE_BUILTINMINIUPNPC), 1)
|
||||
DEFINES += -DHAVE_BUILTINMINIUPNPC -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR
|
||||
DEFINES += -I$(DEPS_DIR)
|
||||
OBJ += \
|
||||
$(DEPS_DIR)/miniupnpc/igd_desc_parse.o \
|
||||
$(DEPS_DIR)/miniupnpc/upnpreplyparse.o \
|
||||
$(DEPS_DIR)/miniupnpc/upnpcommands.o \
|
||||
$(DEPS_DIR)/miniupnpc/upnperrors.o \
|
||||
$(DEPS_DIR)/miniupnpc/connecthostport.o \
|
||||
$(DEPS_DIR)/miniupnpc/portlistingparse.o \
|
||||
$(DEPS_DIR)/miniupnpc/receivedata.o \
|
||||
$(DEPS_DIR)/miniupnpc/upnpdev.o \
|
||||
$(DEPS_DIR)/miniupnpc/minissdpc.o \
|
||||
$(DEPS_DIR)/miniupnpc/miniwget.o \
|
||||
$(DEPS_DIR)/miniupnpc/miniupnpc.o \
|
||||
$(DEPS_DIR)/miniupnpc/minixml.o \
|
||||
$(DEPS_DIR)/miniupnpc/minisoap.o
|
||||
else
|
||||
LIBS += -lminiupnpc
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -1273,7 +1298,7 @@ endif
|
||||
ifneq ($(findstring DOS,$(OS)),)
|
||||
OBJ += gfx/drivers/vga_gfx.o gfx/drivers_font/vga_font.o \
|
||||
input/drivers/dos_input.o input/drivers_joypad/dos_joypad.o \
|
||||
frontend/drivers/platform_dos.o
|
||||
frontend/drivers/platform_dos.o input/drivers_keyboard/keyboard_event_dos.o
|
||||
|
||||
ifeq ($(HAVE_MENU_COMMON), 1)
|
||||
OBJ += menu/drivers_display/menu_display_vga.o
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#endif
|
||||
|
||||
#include "audio_driver.h"
|
||||
#include "audio_mixer.h"
|
||||
#include "audio_thread_wrapper.h"
|
||||
#include "../record/record_driver.h"
|
||||
#include "../frontend/frontend_driver.h"
|
||||
@@ -165,7 +166,7 @@ static void compute_audio_buffer_statistics(void)
|
||||
unsigned low_water_count = 0;
|
||||
unsigned high_water_count = 0;
|
||||
unsigned samples = MIN(
|
||||
audio_driver_free_samples_count,
|
||||
(unsigned)audio_driver_free_samples_count,
|
||||
AUDIO_BUFFER_FREE_SAMPLES_COUNT);
|
||||
|
||||
if (samples < 3)
|
||||
@@ -174,7 +175,7 @@ static void compute_audio_buffer_statistics(void)
|
||||
for (i = 1; i < samples; i++)
|
||||
accum += audio_driver_free_samples_buf[i];
|
||||
|
||||
avg = accum / (samples - 1);
|
||||
avg = (unsigned)accum / (samples - 1);
|
||||
|
||||
for (i = 1; i < samples; i++)
|
||||
{
|
||||
@@ -186,8 +187,8 @@ static void compute_audio_buffer_statistics(void)
|
||||
avg_filled = 1.0f - (float)avg / audio_driver_buffer_size;
|
||||
deviation = (float)stddev / audio_driver_buffer_size;
|
||||
|
||||
low_water_size = audio_driver_buffer_size * 3 / 4;
|
||||
high_water_size = audio_driver_buffer_size / 4;
|
||||
low_water_size = (unsigned)(audio_driver_buffer_size * 3 / 4);
|
||||
high_water_size = (unsigned)(audio_driver_buffer_size / 4);
|
||||
|
||||
for (i = 1; i < samples; i++)
|
||||
{
|
||||
@@ -554,7 +555,7 @@ static bool audio_driver_flush(const int16_t *data, size_t samples)
|
||||
dsp_data.output_frames = 0;
|
||||
|
||||
dsp_data.input = audio_driver_input_data;
|
||||
dsp_data.input_frames = samples >> 1;
|
||||
dsp_data.input_frames = (unsigned)(samples >> 1);
|
||||
|
||||
performance_counter_init(audio_dsp, "audio_dsp");
|
||||
performance_counter_start_plus(is_perfcnt_enable, audio_dsp);
|
||||
@@ -575,9 +576,9 @@ static bool audio_driver_flush(const int16_t *data, size_t samples)
|
||||
/* Readjust the audio input rate. */
|
||||
unsigned write_idx = audio_driver_free_samples_count++ &
|
||||
(AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1);
|
||||
int half_size = audio_driver_buffer_size / 2;
|
||||
int half_size = (int)(audio_driver_buffer_size / 2);
|
||||
int avail =
|
||||
current_audio->write_avail(audio_driver_context_audio_data);
|
||||
(int)current_audio->write_avail(audio_driver_context_audio_data);
|
||||
int delta_mid = avail - half_size;
|
||||
double direction = (double)delta_mid / half_size;
|
||||
double adjust = 1.0 + settings->audio.rate_control_delta * direction;
|
||||
@@ -610,7 +611,7 @@ static bool audio_driver_flush(const int16_t *data, size_t samples)
|
||||
performance_counter_stop_plus(is_perfcnt_enable, resampler_proc);
|
||||
|
||||
output_data = audio_driver_output_samples_buf;
|
||||
output_frames = src_data.output_frames;
|
||||
output_frames = (unsigned)src_data.output_frames;
|
||||
|
||||
if (!audio_driver_use_float)
|
||||
{
|
||||
@@ -816,7 +817,7 @@ bool audio_driver_find_driver(void)
|
||||
|
||||
driver_ctl(RARCH_DRIVER_CTL_FIND_INDEX, &drv);
|
||||
|
||||
i = drv.len;
|
||||
i = (int)drv.len;
|
||||
|
||||
if (i >= 0)
|
||||
current_audio = (const audio_driver_t*)audio_driver_find_handle(i);
|
||||
|
||||
@@ -0,0 +1,595 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2017 - Andre Leiradella
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "audio_mixer.h"
|
||||
|
||||
#include "audio_driver.h"
|
||||
#include <audio/audio_resampler.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <formats/rwav.h>
|
||||
#include <memalign.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STB_VORBIS
|
||||
#define STB_VORBIS_NO_PUSHDATA_API
|
||||
#define STB_VORBIS_NO_STDIO
|
||||
#define STB_VORBIS_NO_CRT
|
||||
|
||||
#include "../deps/stb/stb_vorbis.h"
|
||||
#endif
|
||||
|
||||
#define AUDIO_MIXER_MAX_VOICES 8
|
||||
#define AUDIO_MIXER_TEMP_OGG_BUFFER 8192
|
||||
|
||||
#define AUDIO_MIXER_TYPE_NONE 0
|
||||
#define AUDIO_MIXER_TYPE_WAV 1
|
||||
#define AUDIO_MIXER_TYPE_OGG 2
|
||||
|
||||
struct audio_mixer_sound_t
|
||||
{
|
||||
unsigned type;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/* wav */
|
||||
unsigned frames;
|
||||
const float* pcm;
|
||||
} wav;
|
||||
|
||||
#ifdef HAVE_STB_VORBIS
|
||||
struct
|
||||
{
|
||||
/* ogg */
|
||||
unsigned size;
|
||||
const void* data;
|
||||
} ogg;
|
||||
#endif
|
||||
} types;
|
||||
};
|
||||
|
||||
struct audio_mixer_voice_t
|
||||
{
|
||||
unsigned type;
|
||||
bool repeat;
|
||||
float volume;
|
||||
audio_mixer_sound_t* sound;
|
||||
audio_mixer_stop_cb_t stop_cb;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/* wav */
|
||||
unsigned position;
|
||||
} wav;
|
||||
|
||||
#ifdef HAVE_STB_VORBIS
|
||||
struct
|
||||
{
|
||||
/* ogg */
|
||||
unsigned position;
|
||||
unsigned samples;
|
||||
stb_vorbis* stream;
|
||||
float* buffer;
|
||||
unsigned buf_samples;
|
||||
void* resampler_data;
|
||||
float ratio;
|
||||
const retro_resampler_t* resampler;
|
||||
} ogg;
|
||||
#endif
|
||||
} types;
|
||||
};
|
||||
|
||||
static audio_mixer_voice_t s_voices[AUDIO_MIXER_MAX_VOICES];
|
||||
static unsigned s_rate = 0;
|
||||
|
||||
static bool wav2float(const rwav_t* wav, float** pcm, size_t* samples_out)
|
||||
{
|
||||
size_t i;
|
||||
float sample = 0.0f;
|
||||
const uint8_t* u8 = NULL;
|
||||
const int16_t* s16 = NULL;
|
||||
float* f = NULL;
|
||||
|
||||
/* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */
|
||||
*samples_out = wav->numsamples * 2;
|
||||
f = (float*)memalign_alloc(16,
|
||||
((*samples_out + 15) & ~15) * sizeof(float));
|
||||
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
*pcm = f;
|
||||
|
||||
if (wav->numchannels == 1)
|
||||
{
|
||||
if (wav->bitspersample == 8)
|
||||
{
|
||||
u8 = (const uint8_t*)wav->samples;
|
||||
|
||||
for (i = wav->numsamples; i != 0; i--)
|
||||
{
|
||||
sample = (float)*u8++ / 255.0f;
|
||||
sample = sample * 2.0f - 1.0f;
|
||||
*f++ = sample;
|
||||
*f++ = sample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s16 = (const int16_t*)wav->samples;
|
||||
|
||||
for (i = wav->numsamples; i != 0; i--)
|
||||
{
|
||||
sample = (float)((int)*s16++ + 32768) / 65535.0f;
|
||||
sample = sample * 2.0f - 1.0f;
|
||||
*f++ = sample;
|
||||
*f++ = sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (wav->numchannels == 2)
|
||||
{
|
||||
if (wav->bitspersample == 8)
|
||||
{
|
||||
u8 = (const uint8_t*)wav->samples;
|
||||
|
||||
for (i = wav->numsamples; i != 0; i--)
|
||||
{
|
||||
sample = (float)*u8++ / 255.0f;
|
||||
sample = sample * 2.0f - 1.0f;
|
||||
*f++ = sample;
|
||||
sample = (float)*u8++ / 255.0f;
|
||||
sample = sample * 2.0f - 1.0f;
|
||||
*f++ = sample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s16 = (const int16_t*)wav->samples;
|
||||
|
||||
for (i = wav->numsamples; i != 0; i--)
|
||||
{
|
||||
sample = (float)((int)*s16++ + 32768) / 65535.0f;
|
||||
sample = sample * 2.0f - 1.0f;
|
||||
*f++ = sample;
|
||||
sample = (float)((int)*s16++ + 32768) / 65535.0f;
|
||||
sample = sample * 2.0f - 1.0f;
|
||||
*f++ = sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool one_shot_resample(const float* in, size_t samples_in,
|
||||
unsigned rate, float** out, size_t* samples_out)
|
||||
{
|
||||
struct resampler_data info;
|
||||
void* data = NULL;
|
||||
const retro_resampler_t* resampler = NULL;
|
||||
float ratio = (double)s_rate / (double)rate;
|
||||
|
||||
if (!retro_resampler_realloc(&data, &resampler, NULL, ratio))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
|
||||
* add four more samples in the formula below just as safeguard, because
|
||||
* resampler->process sometimes reports more output samples than the
|
||||
* formula below calculates. Ideally, audio resamplers should have a
|
||||
* function to return the number of samples they will output given a
|
||||
* count of input samples.
|
||||
*/
|
||||
*samples_out = samples_in * ratio + 4;
|
||||
*out = (float*)memalign_alloc(16,
|
||||
((*samples_out + 15) & ~15) * sizeof(float));
|
||||
|
||||
if (*out == NULL)
|
||||
return false;
|
||||
|
||||
info.data_in = in;
|
||||
info.data_out = *out;
|
||||
info.input_frames = samples_in / 2;
|
||||
info.output_frames = 0;
|
||||
info.ratio = ratio;
|
||||
|
||||
resampler->process(data, &info);
|
||||
resampler->free(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
void audio_mixer_init(unsigned rate)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
s_rate = rate;
|
||||
|
||||
for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++)
|
||||
s_voices[i].type = AUDIO_MIXER_TYPE_NONE;
|
||||
}
|
||||
|
||||
void audio_mixer_done(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++)
|
||||
s_voices[i].type = AUDIO_MIXER_TYPE_NONE;
|
||||
}
|
||||
|
||||
audio_mixer_sound_t* audio_mixer_load_wav(const char* path)
|
||||
{
|
||||
/* WAV data */
|
||||
rwav_t wav;
|
||||
/* Raw WAV bytes */
|
||||
void* buffer = NULL;
|
||||
ssize_t size = 0;
|
||||
/* WAV samples converted to float */
|
||||
float* pcm = NULL;
|
||||
float* resampled = NULL;
|
||||
size_t samples = 0;
|
||||
/* Result */
|
||||
audio_mixer_sound_t* sound = NULL;
|
||||
|
||||
if (filestream_read_file(path, &buffer, &size) == 0)
|
||||
return NULL;
|
||||
|
||||
if (rwav_load(&wav, buffer, size) != RWAV_ITERATE_DONE)
|
||||
{
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
if (!wav2float(&wav, &pcm, &samples))
|
||||
return NULL;
|
||||
|
||||
if (wav.samplerate != s_rate)
|
||||
{
|
||||
if (!one_shot_resample(pcm, samples,
|
||||
wav.samplerate, &resampled, &samples))
|
||||
return NULL;
|
||||
|
||||
memalign_free((void*)pcm);
|
||||
pcm = resampled;
|
||||
}
|
||||
|
||||
sound = (audio_mixer_sound_t*)malloc(sizeof(audio_mixer_sound_t));
|
||||
|
||||
if (!sound)
|
||||
{
|
||||
memalign_free((void*)pcm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sound->type = AUDIO_MIXER_TYPE_WAV;
|
||||
sound->types.wav.frames = (unsigned)(samples / 2);
|
||||
sound->types.wav.pcm = pcm;
|
||||
|
||||
rwav_free(&wav);
|
||||
return sound;
|
||||
}
|
||||
|
||||
audio_mixer_sound_t* audio_mixer_load_ogg(const char* path)
|
||||
{
|
||||
#ifdef HAVE_STB_VORBIS
|
||||
ssize_t size;
|
||||
void* buffer = NULL;
|
||||
audio_mixer_sound_t* sound = NULL;
|
||||
|
||||
if (filestream_read_file(path, &buffer, &size) == 0)
|
||||
return NULL;
|
||||
|
||||
sound = (audio_mixer_sound_t*)malloc(sizeof(audio_mixer_sound_t));
|
||||
|
||||
if (!sound)
|
||||
{
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sound->type = AUDIO_MIXER_TYPE_OGG;
|
||||
sound->types.ogg.size = size;
|
||||
sound->types.ogg.data = buffer;
|
||||
|
||||
return sound;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void audio_mixer_destroy(audio_mixer_sound_t* sound)
|
||||
{
|
||||
switch (sound->type)
|
||||
{
|
||||
case AUDIO_MIXER_TYPE_WAV:
|
||||
memalign_free((void*)sound->types.wav.pcm);
|
||||
break;
|
||||
case AUDIO_MIXER_TYPE_OGG:
|
||||
#ifdef HAVE_STB_VORBIS
|
||||
memalign_free((void*)sound->types.ogg.data);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
free(sound);
|
||||
}
|
||||
|
||||
static bool audio_mixer_play_wav(audio_mixer_sound_t* sound,
|
||||
audio_mixer_voice_t* voice, bool repeat, float volume,
|
||||
audio_mixer_stop_cb_t stop_cb)
|
||||
{
|
||||
voice->type = AUDIO_MIXER_TYPE_WAV;
|
||||
voice->repeat = repeat;
|
||||
voice->volume = volume;
|
||||
voice->sound = sound;
|
||||
voice->stop_cb = stop_cb;
|
||||
voice->types.wav.position = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_STB_VORBIS
|
||||
static bool audio_mixer_play_ogg(
|
||||
audio_mixer_sound_t* sound,
|
||||
audio_mixer_voice_t* voice,
|
||||
bool repeat, float volume,
|
||||
audio_mixer_stop_cb_t stop_cb)
|
||||
{
|
||||
stb_vorbis_info info;
|
||||
int res = 0;
|
||||
float ratio = 0.0f;
|
||||
unsigned samples = 0;
|
||||
|
||||
voice->repeat = repeat;
|
||||
voice->volume = volume;
|
||||
voice->sound = sound;
|
||||
voice->stop_cb = stop_cb;
|
||||
|
||||
voice->types.ogg.stream = stb_vorbis_open_memory(
|
||||
(const unsigned char*)sound->types.ogg.data,
|
||||
sound->types.ogg.size, &res, NULL);
|
||||
|
||||
if (!voice->types.ogg.stream)
|
||||
return false;
|
||||
|
||||
info = stb_vorbis_get_info(voice->types.ogg.stream);
|
||||
|
||||
/* Only stereo supported for now */
|
||||
if (info.channels != 2)
|
||||
{
|
||||
stb_vorbis_close(voice->types.ogg.stream);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.sample_rate != s_rate)
|
||||
{
|
||||
voice->types.ogg.ratio = ratio = (double)s_rate / (double)info.sample_rate;
|
||||
|
||||
if (!retro_resampler_realloc(&voice->types.ogg.resampler_data,
|
||||
&voice->types.ogg.resampler, NULL, ratio))
|
||||
{
|
||||
stb_vorbis_close(voice->types.ogg.stream);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
samples =
|
||||
voice->types.ogg.buf_samples = (unsigned)(AUDIO_MIXER_TEMP_OGG_BUFFER * ratio);
|
||||
voice->types.ogg.buffer = (float*)memalign_alloc(16,
|
||||
((samples + 15) & ~15) * sizeof(float));
|
||||
|
||||
if (!voice->types.ogg.buffer)
|
||||
{
|
||||
voice->types.ogg.resampler->free(voice->types.ogg.resampler_data);
|
||||
stb_vorbis_close(voice->types.ogg.stream);
|
||||
return false;
|
||||
}
|
||||
|
||||
voice->type = AUDIO_MIXER_TYPE_OGG;
|
||||
voice->types.ogg.position = voice->types.ogg.samples = 0;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat,
|
||||
float volume, audio_mixer_stop_cb_t stop_cb)
|
||||
{
|
||||
unsigned i;
|
||||
audio_mixer_voice_t* voice = NULL;
|
||||
bool res = false;
|
||||
|
||||
for (i = 0, voice = s_voices; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
|
||||
{
|
||||
if (voice->type == AUDIO_MIXER_TYPE_NONE)
|
||||
{
|
||||
switch (sound->type)
|
||||
{
|
||||
case AUDIO_MIXER_TYPE_WAV:
|
||||
res = audio_mixer_play_wav(sound, voice, repeat, volume, stop_cb);
|
||||
break;
|
||||
case AUDIO_MIXER_TYPE_OGG:
|
||||
#ifdef HAVE_STB_VORBIS
|
||||
res = audio_mixer_play_ogg(sound, voice, repeat, volume, stop_cb);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res)
|
||||
return voice;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void audio_mixer_stop(audio_mixer_voice_t* voice)
|
||||
{
|
||||
voice->stop_cb(voice, AUDIO_MIXER_SOUND_STOPPED);
|
||||
}
|
||||
|
||||
static void mix_wav(float* buffer, size_t num_frames, audio_mixer_voice_t* voice)
|
||||
{
|
||||
int i;
|
||||
unsigned buf_free = (unsigned)(num_frames * 2);
|
||||
const audio_mixer_sound_t* sound = voice->sound;
|
||||
unsigned pcm_available = sound->types.wav.frames
|
||||
* 2 - voice->types.wav.position;
|
||||
const float* pcm = sound->types.wav.pcm + voice->types.wav.position;
|
||||
float volume = voice->volume;
|
||||
|
||||
again:
|
||||
if (pcm_available < buf_free)
|
||||
{
|
||||
for (i = pcm_available; i != 0; i--)
|
||||
*buffer++ += *pcm++ * volume;
|
||||
|
||||
if (voice->repeat)
|
||||
{
|
||||
if (voice->stop_cb)
|
||||
voice->stop_cb(voice, AUDIO_MIXER_SOUND_REPEATED);
|
||||
|
||||
buf_free -= pcm_available;
|
||||
pcm_available = sound->types.wav.frames * 2;
|
||||
pcm = sound->types.wav.pcm;
|
||||
voice->types.wav.position = 0;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (voice->stop_cb)
|
||||
voice->stop_cb(voice, AUDIO_MIXER_SOUND_FINISHED);
|
||||
|
||||
voice->type = AUDIO_MIXER_TYPE_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = buf_free; i != 0; i--)
|
||||
*buffer++ += *pcm++ * volume;
|
||||
|
||||
voice->types.wav.position += buf_free;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_STB_VORBIS
|
||||
static void mix_ogg(float* buffer, size_t num_frames, audio_mixer_voice_t* voice)
|
||||
{
|
||||
int i;
|
||||
float temp_buffer[AUDIO_MIXER_TEMP_OGG_BUFFER];
|
||||
struct resampler_data info;
|
||||
unsigned buf_free = num_frames * 2;
|
||||
unsigned temp_samples = 0;
|
||||
float volume = voice->volume;
|
||||
float* pcm = NULL;
|
||||
#if 0
|
||||
const audio_mixer_sound_t* sound = voice->sound;
|
||||
#endif
|
||||
|
||||
if (voice->types.ogg.position == voice->types.ogg.samples)
|
||||
{
|
||||
again:
|
||||
temp_samples = stb_vorbis_get_samples_float_interleaved(
|
||||
voice->types.ogg.stream, 2, temp_buffer,
|
||||
AUDIO_MIXER_TEMP_OGG_BUFFER) * 2;
|
||||
|
||||
if (temp_samples == 0)
|
||||
{
|
||||
if (voice->repeat)
|
||||
{
|
||||
if (voice->stop_cb)
|
||||
voice->stop_cb(voice, AUDIO_MIXER_SOUND_REPEATED);
|
||||
|
||||
stb_vorbis_seek_start(voice->types.ogg.stream);
|
||||
goto again;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (voice->stop_cb)
|
||||
voice->stop_cb(voice, AUDIO_MIXER_SOUND_FINISHED);
|
||||
|
||||
voice->type = AUDIO_MIXER_TYPE_NONE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
info.data_in = temp_buffer;
|
||||
info.data_out = voice->types.ogg.buffer;
|
||||
info.input_frames = temp_samples / 2;
|
||||
info.output_frames = 0;
|
||||
info.ratio = voice->types.ogg.ratio;
|
||||
|
||||
voice->types.ogg.resampler->process(voice->types.ogg.resampler_data, &info);
|
||||
voice->types.ogg.position = 0;
|
||||
voice->types.ogg.samples = voice->types.ogg.buf_samples;
|
||||
}
|
||||
|
||||
pcm = voice->types.ogg.buffer + voice->types.ogg.position;
|
||||
|
||||
if (voice->types.ogg.samples < buf_free)
|
||||
{
|
||||
for (i = voice->types.ogg.samples; i != 0; i--)
|
||||
*buffer++ += *pcm++ * volume;
|
||||
|
||||
buf_free -= voice->types.ogg.samples;
|
||||
goto again;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
for (i = buf_free; i != 0; --i )
|
||||
*buffer++ += *pcm++ * volume;
|
||||
|
||||
voice->types.ogg.position += buf_free;
|
||||
voice->types.ogg.samples -= buf_free;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void audio_mixer_mix(float* buffer, size_t num_frames)
|
||||
{
|
||||
unsigned i;
|
||||
size_t j = 0;
|
||||
float* sample = NULL;
|
||||
audio_mixer_voice_t* voice = NULL;
|
||||
|
||||
for (i = 0, voice = s_voices; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
|
||||
{
|
||||
if (voice->type == AUDIO_MIXER_TYPE_WAV)
|
||||
mix_wav(buffer, num_frames, voice);
|
||||
#ifdef HAVE_STB_VORBIS
|
||||
else if (voice->type == AUDIO_MIXER_TYPE_OGG)
|
||||
mix_ogg(buffer, num_frames, voice);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0, sample = buffer; j < num_frames; j++, sample++)
|
||||
{
|
||||
if (*sample < -1.0f)
|
||||
*sample = -1.0f;
|
||||
else if (*sample > 1.0f)
|
||||
*sample = 1.0f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2017 - Andre Leiradella
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_MIXER__H
|
||||
#define __AUDIO_MIXER__H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct audio_mixer_sound_t audio_mixer_sound_t;
|
||||
typedef struct audio_mixer_voice_t audio_mixer_voice_t;
|
||||
|
||||
typedef void (*audio_mixer_stop_cb_t)(audio_mixer_voice_t* voice, unsigned reason);
|
||||
|
||||
/* Reasons passed to the stop callback. */
|
||||
#define AUDIO_MIXER_SOUND_FINISHED 0
|
||||
#define AUDIO_MIXER_SOUND_STOPPED 1
|
||||
#define AUDIO_MIXER_SOUND_REPEATED 2
|
||||
|
||||
void audio_mixer_init(unsigned rate);
|
||||
void audio_mixer_done(void);
|
||||
|
||||
audio_mixer_sound_t* audio_mixer_load_wav(const char* path);
|
||||
audio_mixer_sound_t* audio_mixer_load_ogg(const char* path);
|
||||
|
||||
void audio_mixer_destroy(audio_mixer_sound_t* sound);
|
||||
|
||||
audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat, float volume, audio_mixer_stop_cb_t stop_cb);
|
||||
void audio_mixer_stop(audio_mixer_voice_t* voice);
|
||||
|
||||
void audio_mixer_mix(float* buffer, size_t num_frames);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -348,7 +348,7 @@ static void resampler_CC_upsample(void *re_, struct resampler_data *data)
|
||||
}
|
||||
|
||||
|
||||
#elif defined (__ARM_NEON__)
|
||||
#elif defined (__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
|
||||
|
||||
#define CC_RESAMPLER_IDENT "NEON"
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ bool camera_driver_ctl(enum rarch_camera_ctl_state state, void *data)
|
||||
|
||||
driver_ctl(RARCH_DRIVER_CTL_FIND_INDEX, &drv);
|
||||
|
||||
i = drv.len;
|
||||
i = (int)drv.len;
|
||||
|
||||
if (i >= 0)
|
||||
camera_driver = (const camera_driver_t*)camera_driver_find_handle(i);
|
||||
|
||||
@@ -23,26 +23,28 @@
|
||||
#include <libretro.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
#include "menu/menu_driver.h"
|
||||
#include "menu/menu_entries.h"
|
||||
#include "../menu/menu_driver.h"
|
||||
#include "../menu/menu_entries.h"
|
||||
#endif
|
||||
|
||||
#include "cheevos.h"
|
||||
#include "command.h"
|
||||
#include "dynamic.h"
|
||||
#include "network/net_http_special.h"
|
||||
#include "tasks/tasks_internal.h"
|
||||
#include "configuration.h"
|
||||
#include "performance_counters.h"
|
||||
#include "msg_hash.h"
|
||||
#include "runloop.h"
|
||||
#include "core.h"
|
||||
|
||||
#include "verbosity.h"
|
||||
#include "../command.h"
|
||||
#include "../dynamic.h"
|
||||
#include "../configuration.h"
|
||||
#include "../performance_counters.h"
|
||||
#include "../msg_hash.h"
|
||||
#include "../runloop.h"
|
||||
#include "../core.h"
|
||||
|
||||
#include "../network/net_http_special.h"
|
||||
#include "../tasks/tasks_internal.h"
|
||||
|
||||
#include "../verbosity.h"
|
||||
|
||||
/* Define this macro to prevent cheevos from being deactivated. */
|
||||
#undef CHEEVOS_DONT_DEACTIVATE
|
||||
@@ -82,6 +84,9 @@
|
||||
#define CHEEVOS_JSON_KEY_CONSOLE_ID 0x071656e5U
|
||||
#define CHEEVOS_JSON_KEY_TOKEN 0x0e2dbd26U
|
||||
#define CHEEVOS_JSON_KEY_FLAGS 0x0d2e96b2U
|
||||
#define CHEEVOS_JSON_KEY_LEADERBOARDS 0xf1247d2dU
|
||||
#define CHEEVOS_JSON_KEY_MEM 0x0b8807e4U
|
||||
#define CHEEVOS_JSON_KEY_FORMAT 0xb341208eU
|
||||
|
||||
enum
|
||||
{
|
||||
@@ -241,9 +246,11 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
int in_cheevos;
|
||||
int in_lboards;
|
||||
uint32_t field_hash;
|
||||
unsigned core_count;
|
||||
unsigned unofficial_count;
|
||||
unsigned lboard_count;
|
||||
} cheevos_countud_t;
|
||||
|
||||
typedef struct
|
||||
@@ -255,13 +262,15 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
int in_cheevos;
|
||||
int in_lboards;
|
||||
int is_console_id;
|
||||
unsigned core_count;
|
||||
unsigned unofficial_count;
|
||||
unsigned lboard_count;
|
||||
|
||||
cheevos_field_t *field;
|
||||
cheevos_field_t id, memaddr, title, desc, points, author;
|
||||
cheevos_field_t modified, created, badge, flags;
|
||||
cheevos_field_t modified, created, badge, flags, format;
|
||||
} cheevos_readud_t;
|
||||
|
||||
typedef struct
|
||||
@@ -271,6 +280,32 @@ typedef struct
|
||||
const uint32_t *ext_hashes;
|
||||
} cheevos_finder_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cheevos_var_t var;
|
||||
int multiplier;
|
||||
} cheevos_term_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cheevos_term_t *terms;
|
||||
unsigned count;
|
||||
} cheevos_expr_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned id;
|
||||
const char *title;
|
||||
const char *description;
|
||||
int active;
|
||||
int last_value;
|
||||
|
||||
cheevos_condition_t start;
|
||||
cheevos_condition_t cancel;
|
||||
cheevos_condition_t submit;
|
||||
cheevos_expr_t value;
|
||||
} cheevos_leaderboard_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int console_id;
|
||||
@@ -278,25 +313,34 @@ typedef struct
|
||||
|
||||
cheevoset_t core;
|
||||
cheevoset_t unofficial;
|
||||
cheevos_leaderboard_t *leaderboards;
|
||||
unsigned lboard_count;
|
||||
|
||||
char token[32];
|
||||
|
||||
retro_ctx_memory_info_t meminfo[4];
|
||||
} cheevos_locals_t;
|
||||
|
||||
|
||||
static cheevos_locals_t cheevos_locals =
|
||||
{
|
||||
0,
|
||||
true,
|
||||
{NULL, 0},
|
||||
{NULL, 0},
|
||||
{0}
|
||||
/* console_id */ 0,
|
||||
/* core_supports */ true,
|
||||
/* core */ {NULL, 0},
|
||||
/* unofficial */ {NULL, 0},
|
||||
/* leaderboards */ NULL,
|
||||
/* lboard_count */ 0,
|
||||
/* token */ {0},
|
||||
{
|
||||
/* meminfo[0] */ {NULL, 0, 0},
|
||||
/* meminfo[1] */ {NULL, 0, 0},
|
||||
/* meminfo[2] */ {NULL, 0, 0},
|
||||
/* meminfo[3] */ {NULL, 0, 0}
|
||||
}
|
||||
};
|
||||
|
||||
bool cheevos_loaded = false;
|
||||
int cheats_are_enabled = 0;
|
||||
int cheats_were_enabled = 0;
|
||||
bool cheevos_loaded = false;
|
||||
int cheats_are_enabled = 0;
|
||||
int cheats_were_enabled = 0;
|
||||
|
||||
/*****************************************************************************
|
||||
Supporting functions.
|
||||
@@ -405,6 +449,16 @@ static void cheevos_add_uint(char** aux, size_t* left, unsigned v)
|
||||
cheevos_add_string(aux, left, buffer);
|
||||
}
|
||||
|
||||
static void cheevos_add_int(char** aux, size_t* left, int v)
|
||||
{
|
||||
char buffer[32];
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%d", v);
|
||||
buffer[sizeof(buffer) - 1] = 0;
|
||||
|
||||
cheevos_add_string(aux, left, buffer);
|
||||
}
|
||||
|
||||
static void cheevos_log_var(const cheevos_var_t* var)
|
||||
{
|
||||
RARCH_LOG("CHEEVOS size: %s\n",
|
||||
@@ -608,6 +662,43 @@ static void cheevos_post_log_cheevo(const cheevo_t* cheevo)
|
||||
cheevos_build_memaddr(&cheevo->condition, memaddr, sizeof(memaddr));
|
||||
RARCH_LOG("CHEEVOS memaddr (computed): %s\n", memaddr);
|
||||
}
|
||||
|
||||
static void cheevos_log_lboard(const cheevos_leaderboard_t* lb)
|
||||
{
|
||||
char mem[256];
|
||||
char* aux;
|
||||
size_t left;
|
||||
unsigned i;
|
||||
|
||||
RARCH_LOG("CHEEVOS leaderboard %p\n", lb);
|
||||
RARCH_LOG("CHEEVOS id: %u\n", lb->id);
|
||||
RARCH_LOG("CHEEVOS title: %s\n", lb->title);
|
||||
RARCH_LOG("CHEEVOS desc: %s\n", lb->description);
|
||||
|
||||
cheevos_build_memaddr(&lb->start, mem, sizeof(mem));
|
||||
RARCH_LOG("CHEEVOS start: %s\n", mem);
|
||||
|
||||
cheevos_build_memaddr(&lb->cancel, mem, sizeof(mem));
|
||||
RARCH_LOG("CHEEVOS cancel: %s\n", mem);
|
||||
|
||||
cheevos_build_memaddr(&lb->submit, mem, sizeof(mem));
|
||||
RARCH_LOG("CHEEVOS submit: %s\n", mem);
|
||||
|
||||
left = sizeof(mem);
|
||||
aux = mem;
|
||||
|
||||
for (i = 0; i < lb->value.count; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
cheevos_add_char(&aux, &left, '_');
|
||||
|
||||
cheevos_add_var(&lb->value.terms[i].var, &aux, &left);
|
||||
cheevos_add_char(&aux, &left, '*');
|
||||
cheevos_add_int(&aux, &left, lb->value.terms[i].multiplier);
|
||||
}
|
||||
|
||||
RARCH_LOG("CHEEVOS value: %s\n", mem);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t cheevos_djb2(const char* str, size_t length)
|
||||
@@ -633,11 +724,19 @@ static int cheevos_http_get(const char **result, size_t *size,
|
||||
int ret = net_http_get(result, size, url, timeout);
|
||||
#endif
|
||||
|
||||
if (ret == NET_HTTP_GET_OK)
|
||||
{
|
||||
if (*result != NULL)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
RARCH_ERR("CHEEVOS error during HTTP GET: ok.\n");
|
||||
return NET_HTTP_GET_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case NET_HTTP_GET_OK:
|
||||
return ret;
|
||||
|
||||
case NET_HTTP_GET_MALFORMED_URL:
|
||||
msg = "malformed url";
|
||||
break;
|
||||
@@ -651,11 +750,11 @@ static int cheevos_http_get(const char **result, size_t *size,
|
||||
break;
|
||||
|
||||
default:
|
||||
msg = "?";
|
||||
msg = "unknown error";
|
||||
break;
|
||||
}
|
||||
|
||||
RARCH_ERR("CHEEVOS error getting %s: %s.\n", url, msg);
|
||||
RARCH_ERR("CHEEVOS error during HTTP GET: %s.\n", msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -756,6 +855,7 @@ static int cheevos_count__json_end_array(void *userdata)
|
||||
{
|
||||
cheevos_countud_t* ud = (cheevos_countud_t*)userdata;
|
||||
ud->in_cheevos = 0;
|
||||
ud->in_lboards = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -767,6 +867,8 @@ static int cheevos_count__json_key(void *userdata,
|
||||
|
||||
if (ud->field_hash == CHEEVOS_JSON_KEY_ACHIEVEMENTS)
|
||||
ud->in_cheevos = 1;
|
||||
else if (ud->field_hash == CHEEVOS_JSON_KEY_LEADERBOARDS)
|
||||
ud->in_lboards = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -785,12 +887,15 @@ static int cheevos_count__json_number(void *userdata,
|
||||
else if (flags == 5)
|
||||
ud->unofficial_count++; /* Unofficial achievements */
|
||||
}
|
||||
else if (ud->in_lboards && ud->field_hash == CHEEVOS_JSON_KEY_ID)
|
||||
ud->lboard_count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cheevos_count_cheevos(const char *json,
|
||||
unsigned *core_count, unsigned *unofficial_count)
|
||||
unsigned *core_count, unsigned *unofficial_count,
|
||||
unsigned *lboard_count)
|
||||
{
|
||||
static const jsonsax_handlers_t handlers =
|
||||
{
|
||||
@@ -813,11 +918,13 @@ static int cheevos_count_cheevos(const char *json,
|
||||
ud.in_cheevos = 0;
|
||||
ud.core_count = 0;
|
||||
ud.unofficial_count = 0;
|
||||
ud.lboard_count = 0;
|
||||
|
||||
res = jsonsax_parse(json, &handlers, (void*)&ud);
|
||||
|
||||
*core_count = ud.core_count;
|
||||
*unofficial_count = ud.unofficial_count;
|
||||
*lboard_count = ud.lboard_count;
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -872,8 +979,8 @@ static unsigned cheevos_read_hits(const char **memaddr)
|
||||
|
||||
if (*str == '(' || *str == '.')
|
||||
{
|
||||
num_hits = strtol(str + 1, &end, 10);
|
||||
str = end + 1;
|
||||
num_hits = (unsigned)strtol(str + 1, &end, 10);
|
||||
str = end + 1;
|
||||
}
|
||||
|
||||
*memaddr = str;
|
||||
@@ -1002,8 +1109,8 @@ void cheevos_parse_guest_addr(cheevos_var_t *var, unsigned value)
|
||||
{
|
||||
if (((desc->core.start ^ var->value) & desc->core.select) == 0)
|
||||
{
|
||||
var->bank_id = desc - system->mmaps.descriptors;
|
||||
var->value = cheevos_reduce(
|
||||
var->bank_id = (int)(desc - system->mmaps.descriptors);
|
||||
var->value = (unsigned)cheevos_reduce(
|
||||
(var->value - desc->core.start) & desc->disconnect_mask,
|
||||
desc->core.disconnect);
|
||||
|
||||
@@ -1061,7 +1168,12 @@ static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr)
|
||||
if (toupper(*str) == 'H')
|
||||
str++;
|
||||
else
|
||||
{
|
||||
if (toupper(*str) == 'V')
|
||||
str++;
|
||||
|
||||
base = 10;
|
||||
}
|
||||
}
|
||||
|
||||
if (var->type != CHEEVOS_VAR_TYPE_VALUE_COMP)
|
||||
@@ -1072,7 +1184,7 @@ static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr)
|
||||
str++;
|
||||
}
|
||||
|
||||
var->value = strtol(str, &end, base);
|
||||
var->value = (unsigned)strtol(str, &end, base);
|
||||
*memaddr = end;
|
||||
|
||||
switch (var->type)
|
||||
@@ -1256,6 +1368,117 @@ static int cheevos_parse_condition(cheevos_condition_t *condition, const char* m
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CHEEVOS_ENABLE_LBOARDS
|
||||
static void cheevos_free_condition(cheevos_condition_t* condition)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (condition->condsets)
|
||||
{
|
||||
for (i = 0; i < condition->count; i++)
|
||||
{
|
||||
free((void*)condition->condsets[i].conds);
|
||||
}
|
||||
|
||||
free((void*)condition->condsets);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
Parse the Mem field of leaderboards.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef CHEEVOS_ENABLE_LBOARDS
|
||||
static int cheevos_parse_expression(cheevos_expr_t *expr, const char* mem)
|
||||
{
|
||||
const char* aux;
|
||||
char* end;
|
||||
unsigned i;
|
||||
expr->count = 1;
|
||||
|
||||
for (aux = mem; *aux != '"'; aux++)
|
||||
{
|
||||
expr->count += *aux == '_';
|
||||
}
|
||||
|
||||
expr->terms = (cheevos_term_t*)calloc(expr->count, sizeof(cheevos_term_t));
|
||||
|
||||
if (!expr->terms)
|
||||
return -1;
|
||||
|
||||
for (i = 0, aux = mem; i < expr->count; i++)
|
||||
{
|
||||
cheevos_parse_var(&expr->terms[i].var, &aux);
|
||||
|
||||
if (*aux != '*')
|
||||
{
|
||||
free((void*)expr->terms);
|
||||
return -1;
|
||||
}
|
||||
|
||||
expr->terms[i].multiplier = (int)strtol(aux + 1, &end, 10);
|
||||
aux = end + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CHEEVOS_ENABLE_LBOARDS
|
||||
static int cheevos_parse_mem(cheevos_leaderboard_t *lb, const char* mem)
|
||||
{
|
||||
lb->start.condsets = NULL;
|
||||
lb->cancel.condsets = NULL;
|
||||
lb->submit.condsets = NULL;
|
||||
lb->value.terms = NULL;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (*mem == 'S' && mem[1] == 'T' && mem[2] == 'A' && mem[3] == ':')
|
||||
{
|
||||
if (cheevos_parse_condition(&lb->start, mem + 4))
|
||||
goto error;
|
||||
}
|
||||
else if (*mem == 'C' && mem[1] == 'A' && mem[2] == 'N' && mem[3] == ':')
|
||||
{
|
||||
if (cheevos_parse_condition(&lb->cancel, mem + 4))
|
||||
goto error;
|
||||
}
|
||||
else if (*mem == 'S' && mem[1] == 'U' && mem[2] == 'B' && mem[3] == ':')
|
||||
{
|
||||
if (cheevos_parse_condition(&lb->submit, mem + 4))
|
||||
goto error;
|
||||
}
|
||||
else if (*mem == 'V' && mem[1] == 'A' && mem[2] == 'L' && mem[3] == ':')
|
||||
{
|
||||
if (cheevos_parse_expression(&lb->value, mem + 4))
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
goto error;
|
||||
|
||||
for (mem += 4;; mem++)
|
||||
{
|
||||
if (*mem == ':' && mem[1] == ':')
|
||||
{
|
||||
mem += 2;
|
||||
break;
|
||||
}
|
||||
else if (*mem == '"')
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
cheevos_free_condition(&lb->start);
|
||||
cheevos_free_condition(&lb->cancel);
|
||||
cheevos_free_condition(&lb->submit);
|
||||
free((void*)lb->value.terms);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
Load achievements from a JSON string.
|
||||
*****************************************************************************/
|
||||
@@ -1282,12 +1505,12 @@ static int cheevos_new_cheevo(cheevos_readud_t *ud)
|
||||
else
|
||||
cheevo = cheevos_locals.unofficial.cheevos + ud->unofficial_count++;
|
||||
|
||||
cheevo->id = strtol(ud->id.string, NULL, 10);
|
||||
cheevo->id = (unsigned)strtol(ud->id.string, NULL, 10);
|
||||
cheevo->title = cheevos_dupstr(&ud->title);
|
||||
cheevo->description = cheevos_dupstr(&ud->desc);
|
||||
cheevo->author = cheevos_dupstr(&ud->author);
|
||||
cheevo->badge = cheevos_dupstr(&ud->badge);
|
||||
cheevo->points = strtol(ud->points.string, NULL, 10);
|
||||
cheevo->points = (unsigned)strtol(ud->points.string, NULL, 10);
|
||||
cheevo->dirty = 0;
|
||||
cheevo->active = CHEEVOS_ACTIVE_SOFTCORE | CHEEVOS_ACTIVE_HARDCORE;
|
||||
cheevo->last = 1;
|
||||
@@ -1317,11 +1540,40 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CHEEVOS_ENABLE_LBOARDS
|
||||
static int cheevos_new_lboard(cheevos_readud_t *ud)
|
||||
{
|
||||
cheevos_leaderboard_t *lboard = cheevos_locals.leaderboards + ud->lboard_count++;
|
||||
|
||||
lboard->id = strtol(ud->id.string, NULL, 10);
|
||||
lboard->title = cheevos_dupstr(&ud->title);
|
||||
lboard->description = cheevos_dupstr(&ud->desc);
|
||||
|
||||
if (!lboard->title || !lboard->description)
|
||||
goto error;
|
||||
|
||||
if (cheevos_parse_mem(lboard, ud->memaddr.string))
|
||||
goto error;
|
||||
|
||||
#ifdef CHEEVOS_VERBOSE
|
||||
cheevos_log_lboard(lboard);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free((void*)lboard->title);
|
||||
free((void*)lboard->description);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cheevos_read__json_key( void *userdata,
|
||||
const char *name, size_t length)
|
||||
{
|
||||
cheevos_readud_t *ud = (cheevos_readud_t*)userdata;
|
||||
uint32_t hash = cheevos_djb2(name, length);
|
||||
int common = ud->in_cheevos || ud->in_lboards;
|
||||
|
||||
ud->field = NULL;
|
||||
|
||||
@@ -1330,23 +1582,30 @@ static int cheevos_read__json_key( void *userdata,
|
||||
case CHEEVOS_JSON_KEY_ACHIEVEMENTS:
|
||||
ud->in_cheevos = 1;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_LEADERBOARDS:
|
||||
ud->in_lboards = 1;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_CONSOLE_ID:
|
||||
ud->is_console_id = 1;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_ID:
|
||||
if (ud->in_cheevos)
|
||||
if (common)
|
||||
ud->field = &ud->id;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_MEMADDR:
|
||||
if (ud->in_cheevos)
|
||||
ud->field = &ud->memaddr;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_MEM:
|
||||
if (ud->in_lboards)
|
||||
ud->field = &ud->memaddr;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_TITLE:
|
||||
if (ud->in_cheevos)
|
||||
if (common)
|
||||
ud->field = &ud->title;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_DESCRIPTION:
|
||||
if (ud->in_cheevos)
|
||||
if (common)
|
||||
ud->field = &ud->desc;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_POINTS:
|
||||
@@ -1373,6 +1632,10 @@ static int cheevos_read__json_key( void *userdata,
|
||||
if (ud->in_cheevos)
|
||||
ud->field = &ud->flags;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_FORMAT:
|
||||
if (ud->in_lboards)
|
||||
ud->field = &ud->format;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1406,7 +1669,7 @@ static int cheevos_read__json_number(void *userdata,
|
||||
}
|
||||
else if (ud->is_console_id)
|
||||
{
|
||||
cheevos_locals.console_id = strtol(number, NULL, 10);
|
||||
cheevos_locals.console_id = (int)strtol(number, NULL, 10);
|
||||
ud->is_console_id = 0;
|
||||
}
|
||||
|
||||
@@ -1419,6 +1682,10 @@ static int cheevos_read__json_end_object(void *userdata)
|
||||
|
||||
if (ud->in_cheevos)
|
||||
return cheevos_new_cheevo(ud);
|
||||
#ifdef CHEEVOS_ENABLE_LBOARDS
|
||||
else if (ud->in_lboards)
|
||||
return cheevos_new_lboard(ud);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1427,6 +1694,7 @@ static int cheevos_read__json_end_array(void *userdata)
|
||||
{
|
||||
cheevos_readud_t *ud = (cheevos_readud_t*)userdata;
|
||||
ud->in_cheevos = 0;
|
||||
ud->in_lboards = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1448,7 +1716,7 @@ static int cheevos_parse(const char *json)
|
||||
NULL
|
||||
};
|
||||
|
||||
unsigned core_count, unofficial_count;
|
||||
unsigned core_count, unofficial_count, lboard_count;
|
||||
int res;
|
||||
cheevos_readud_t ud;
|
||||
settings_t *settings = config_get_ptr();
|
||||
@@ -1458,7 +1726,8 @@ static int cheevos_parse(const char *json)
|
||||
return 0;
|
||||
|
||||
/* Count the number of achievements in the JSON file. */
|
||||
res = cheevos_count_cheevos(json, &core_count, &unofficial_count);
|
||||
res = cheevos_count_cheevos(json, &core_count, &unofficial_count,
|
||||
&lboard_count);
|
||||
|
||||
if (res != JSONSAX_OK)
|
||||
return -1;
|
||||
@@ -1473,21 +1742,30 @@ static int cheevos_parse(const char *json)
|
||||
calloc(unofficial_count, sizeof(cheevo_t));
|
||||
cheevos_locals.unofficial.count = unofficial_count;
|
||||
|
||||
if (!cheevos_locals.core.cheevos || !cheevos_locals.unofficial.cheevos)
|
||||
cheevos_locals.leaderboards = (cheevos_leaderboard_t*)
|
||||
calloc(lboard_count, sizeof(cheevos_leaderboard_t));
|
||||
cheevos_locals.lboard_count = lboard_count;
|
||||
|
||||
if ( !cheevos_locals.core.cheevos || !cheevos_locals.unofficial.cheevos
|
||||
|| !cheevos_locals.leaderboards)
|
||||
{
|
||||
free((void*)cheevos_locals.core.cheevos);
|
||||
free((void*)cheevos_locals.unofficial.cheevos);
|
||||
cheevos_locals.core.count = cheevos_locals.unofficial.count = 0;
|
||||
free((void*)cheevos_locals.leaderboards);
|
||||
cheevos_locals.core.count = cheevos_locals.unofficial.count =
|
||||
cheevos_locals.lboard_count = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Load the achievements. */
|
||||
ud.in_cheevos = 0;
|
||||
ud.in_lboards = 0;
|
||||
ud.is_console_id = 0;
|
||||
ud.field = NULL;
|
||||
ud.core_count = 0;
|
||||
ud.unofficial_count = 0;
|
||||
ud.lboard_count = 0;
|
||||
|
||||
if (jsonsax_parse(json, &handlers, (void*)&ud) != JSONSAX_OK)
|
||||
goto error;
|
||||
@@ -1535,7 +1813,6 @@ static unsigned cheevos_get_var_value(cheevos_var_t *var)
|
||||
if ( var->type == CHEEVOS_VAR_TYPE_ADDRESS
|
||||
|| var->type == CHEEVOS_VAR_TYPE_DELTA_MEM)
|
||||
{
|
||||
/* TODO Check with Scott if the bank id is needed */
|
||||
const uint8_t *memory = cheevos_get_memory(var);
|
||||
unsigned live_val = 0;
|
||||
|
||||
@@ -1950,6 +2227,162 @@ static void cheevos_test_cheevo_set(const cheevoset_t *set)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CHEEVOS_ENABLE_LBOARDS
|
||||
static int cheevos_test_lboard_condition(const cheevos_condition_t* condition)
|
||||
{
|
||||
int dirty_conds = 0;
|
||||
int reset_conds = 0;
|
||||
int ret_val = 0;
|
||||
int ret_val_sub_cond = condition->count == 1;
|
||||
cheevos_condset_t *condset = condition->condsets;
|
||||
const cheevos_condset_t *end = condset + condition->count;
|
||||
|
||||
if (condset < end)
|
||||
{
|
||||
ret_val = cheevos_test_cond_set(condset, &dirty_conds, &reset_conds, 0);
|
||||
condset++;
|
||||
}
|
||||
|
||||
while (condset < end)
|
||||
{
|
||||
ret_val_sub_cond |= cheevos_test_cond_set(condset, &dirty_conds, &reset_conds, 0);
|
||||
condset++;
|
||||
}
|
||||
|
||||
if (reset_conds)
|
||||
{
|
||||
for (condset = condition->condsets; condset < end; condset++)
|
||||
cheevos_reset_cond_set(condset, 0);
|
||||
}
|
||||
|
||||
return ret_val && ret_val_sub_cond;
|
||||
}
|
||||
|
||||
static int cheevos_expr_value(cheevos_expr_t* expr)
|
||||
{
|
||||
cheevos_term_t* term = expr->terms;
|
||||
unsigned i;
|
||||
int value = 0;
|
||||
|
||||
for (i = expr->count; i != 0; i--, term++)
|
||||
{
|
||||
value += cheevos_get_var_value(&term->var) * term->multiplier;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void cheevos_make_lboard_url(const cheevos_leaderboard_t *lboard,
|
||||
char* url, size_t url_size)
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
char signature[64];
|
||||
MD5_CTX ctx;
|
||||
uint8_t hash[16];
|
||||
|
||||
hash[0] = '\0';
|
||||
|
||||
snprintf(signature, sizeof(signature), "%u%s%u", lboard->id,
|
||||
settings->cheevos.username, lboard->id);
|
||||
|
||||
MD5_Init(&ctx);
|
||||
MD5_Update(&ctx, (void*)signature, strlen(signature));
|
||||
MD5_Final(hash, &ctx);
|
||||
|
||||
snprintf(
|
||||
url, url_size,
|
||||
"http://retroachievements.org/dorequest.php?r=submitlbentry&u=%s&t=%s&i=%u&s=%d"
|
||||
"&v=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
settings->cheevos.username, cheevos_locals.token, lboard->id,
|
||||
lboard->last_value,
|
||||
hash[ 0], hash[ 1], hash[ 2], hash[ 3],
|
||||
hash[ 4], hash[ 5], hash[ 6], hash[ 7],
|
||||
hash[ 8], hash[ 9], hash[10], hash[11],
|
||||
hash[12], hash[13], hash[14], hash[15]
|
||||
);
|
||||
|
||||
url[url_size - 1] = 0;
|
||||
|
||||
#ifdef CHEEVOS_LOG_URLS
|
||||
cheevos_log_url("CHEEVOS url to submit the leaderboard: %s\n", url);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CHEEVOS_ENABLE_LBOARDS
|
||||
static void cheevos_lboard_submit(void *task_data, void *user_data, const char *error)
|
||||
{
|
||||
cheevos_leaderboard_t *lboard = (cheevos_leaderboard_t *)user_data;
|
||||
|
||||
if (error == NULL)
|
||||
{
|
||||
RARCH_LOG("CHEEVOS submitted leaderboard %u.\n", lboard->id);
|
||||
}
|
||||
else
|
||||
RARCH_ERR("CHEEVOS error submitting leaderboard %u\n", lboard->id);
|
||||
#if 0
|
||||
{
|
||||
char url[256];
|
||||
url[0] = '\0';
|
||||
|
||||
RARCH_ERR("CHEEVOS error submitting leaderboard %u, retrying...\n", lboard->id);
|
||||
|
||||
cheevos_make_lboard_url(lboard, url, sizeof(url));
|
||||
task_push_http_transfer(url, true, NULL, cheevos_lboard_submit, lboard);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CHEEVOS_ENABLE_LBOARDS
|
||||
static void cheevos_test_leaderboards(void)
|
||||
{
|
||||
cheevos_leaderboard_t* lboard = cheevos_locals.leaderboards;
|
||||
unsigned i;
|
||||
|
||||
for (i = cheevos_locals.lboard_count; i != 0; i--, lboard++)
|
||||
{
|
||||
if (lboard->active)
|
||||
{
|
||||
int value = cheevos_expr_value(&lboard->value);
|
||||
|
||||
if (value != lboard->last_value)
|
||||
{
|
||||
#ifdef CHEEVOS_VERBOSE
|
||||
RARCH_LOG("CHEEVOS value lboard %s %u\n", lboard->title, value);
|
||||
#endif
|
||||
lboard->last_value = value;
|
||||
}
|
||||
|
||||
if (cheevos_test_lboard_condition(&lboard->submit))
|
||||
{
|
||||
char url[256];
|
||||
|
||||
cheevos_make_lboard_url(lboard, url, sizeof(url));
|
||||
task_push_http_transfer(url, true, NULL, cheevos_lboard_submit, lboard);
|
||||
|
||||
RARCH_LOG("CHEEVOS submit lboard %s\n", lboard->title);
|
||||
}
|
||||
|
||||
if (cheevos_test_lboard_condition(&lboard->cancel))
|
||||
{
|
||||
RARCH_LOG("CHEEVOS cancel lboard %s\n", lboard->title);
|
||||
lboard->active = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cheevos_test_lboard_condition(&lboard->start))
|
||||
{
|
||||
RARCH_LOG("CHEEVOS start lboard %s\n", lboard->title);
|
||||
lboard->active = 1;
|
||||
lboard->last_value = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
Free the loaded achievements.
|
||||
*****************************************************************************/
|
||||
@@ -2065,7 +2498,7 @@ static unsigned cheevos_get_game_id(unsigned char *hash, retro_time_t *timeout)
|
||||
if (!res)
|
||||
{
|
||||
RARCH_LOG("CHEEVOS got game id %s.\n", game_id);
|
||||
return strtoul(game_id, NULL, 10);
|
||||
return (unsigned)strtoul(game_id, NULL, 10);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2698,13 +3131,17 @@ void cheevos_reset_game(void)
|
||||
const cheevo_t *end = cheevo + cheevos_locals.core.count;
|
||||
|
||||
for (; cheevo < end; cheevo++)
|
||||
{
|
||||
cheevo->last = 1;
|
||||
}
|
||||
|
||||
cheevo = cheevos_locals.unofficial.cheevos;
|
||||
end = cheevo + cheevos_locals.unofficial.count;
|
||||
|
||||
for (; cheevo < end; cheevo++)
|
||||
{
|
||||
cheevo->last = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void cheevos_populate_menu(void *data, bool hardcore)
|
||||
@@ -2814,15 +3251,23 @@ void cheevos_populate_menu(void *data, bool hardcore)
|
||||
|
||||
bool cheevos_get_description(cheevos_ctx_desc_t *desc)
|
||||
{
|
||||
cheevo_t *cheevos = cheevos_locals.core.cheevos;
|
||||
|
||||
if (desc->idx >= cheevos_locals.core.count)
|
||||
if (cheevos_loaded)
|
||||
{
|
||||
cheevos = cheevos_locals.unofficial.cheevos;
|
||||
desc->idx -= cheevos_locals.unofficial.count;
|
||||
}
|
||||
cheevo_t *cheevos = cheevos_locals.core.cheevos;
|
||||
|
||||
strlcpy(desc->s, cheevos[desc->idx].description, desc->len);
|
||||
if (desc->idx >= cheevos_locals.core.count)
|
||||
{
|
||||
cheevos = cheevos_locals.unofficial.cheevos;
|
||||
desc->idx -= cheevos_locals.unofficial.count;
|
||||
}
|
||||
|
||||
strlcpy(desc->s, cheevos[desc->idx].description, desc->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
*desc->s = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2842,7 +3287,7 @@ bool cheevos_unload(void)
|
||||
cheevos_free_cheevo_set(&cheevos_locals.core);
|
||||
cheevos_free_cheevo_set(&cheevos_locals.unofficial);
|
||||
|
||||
cheevos_loaded = false;
|
||||
cheevos_loaded = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2881,7 +3326,7 @@ void cheevos_test(void)
|
||||
if (settings->cheevos.test_unofficial)
|
||||
cheevos_test_cheevo_set(&cheevos_locals.unofficial);
|
||||
|
||||
#if 0
|
||||
#ifdef CHEEVOS_ENABLE_LBOARDS
|
||||
cheevos_test_leaderboards();
|
||||
#endif
|
||||
}
|
||||
@@ -43,7 +43,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHEEVOS
|
||||
#include "cheevos.h"
|
||||
#include "cheevos/cheevos.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
@@ -1315,7 +1315,7 @@ static void command_event_set_savestate_auto_index(void)
|
||||
while ((end > dir_elem) && isdigit((int)end[-1]))
|
||||
end--;
|
||||
|
||||
idx = strtoul(end, NULL, 0);
|
||||
idx = (unsigned)strtoul(end, NULL, 0);
|
||||
if (idx > max_idx)
|
||||
max_idx = idx;
|
||||
}
|
||||
@@ -1350,15 +1350,6 @@ static bool event_init_content(void)
|
||||
|
||||
content_get_status(&contentless, &is_inited);
|
||||
|
||||
if (contentless)
|
||||
{
|
||||
#ifdef HAVE_NETWORKING
|
||||
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
|
||||
RARCH_ERR("%s\n", msg_hash_to_str(MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
command_event_set_savestate_auto_index();
|
||||
|
||||
if (event_load_save_files())
|
||||
@@ -1630,7 +1621,10 @@ static void command_event_save_current_config(enum override_type type)
|
||||
switch (type)
|
||||
{
|
||||
case OVERRIDE_NONE:
|
||||
if (!path_is_empty(RARCH_PATH_CONFIG))
|
||||
if (path_is_empty(RARCH_PATH_CONFIG))
|
||||
strlcpy(msg, "Config directory not set, cannot save configuration.",
|
||||
sizeof(msg));
|
||||
else
|
||||
command_event_save_config(path_get(RARCH_PATH_CONFIG), msg, sizeof(msg));
|
||||
break;
|
||||
case OVERRIDE_GAME:
|
||||
@@ -1697,11 +1691,12 @@ static void command_event_undo_load_state(char *s, size_t len)
|
||||
msg_hash_to_str(MSG_UNDID_LOAD_STATE), len);
|
||||
}
|
||||
|
||||
static void command_event_main_state(unsigned cmd)
|
||||
static bool command_event_main_state(unsigned cmd)
|
||||
{
|
||||
retro_ctx_size_info_t info;
|
||||
char path[PATH_MAX_LENGTH];
|
||||
char msg[128];
|
||||
bool ret = false;
|
||||
global_t *global = global_get_ptr();
|
||||
bool push_msg = true;
|
||||
|
||||
@@ -1729,11 +1724,13 @@ static void command_event_main_state(unsigned cmd)
|
||||
{
|
||||
case CMD_EVENT_SAVE_STATE:
|
||||
content_save_state(path, true, false);
|
||||
ret = true;
|
||||
push_msg = false;
|
||||
break;
|
||||
case CMD_EVENT_LOAD_STATE:
|
||||
if (content_load_state(path, false, false))
|
||||
{
|
||||
ret = true;
|
||||
#ifdef HAVE_NETWORKING
|
||||
netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL);
|
||||
#endif
|
||||
@@ -1742,9 +1739,11 @@ static void command_event_main_state(unsigned cmd)
|
||||
break;
|
||||
case CMD_EVENT_UNDO_LOAD_STATE:
|
||||
command_event_undo_load_state(msg, sizeof(msg));
|
||||
ret = true;
|
||||
break;
|
||||
case CMD_EVENT_UNDO_SAVE_STATE:
|
||||
command_event_undo_save_state(msg, sizeof(msg));
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1755,6 +1754,8 @@ static void command_event_main_state(unsigned cmd)
|
||||
if (push_msg)
|
||||
runloop_msg_queue_push(msg, 2, 180, true);
|
||||
RARCH_LOG("%s\n", msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void handle_quit_event(void)
|
||||
@@ -1895,15 +1896,13 @@ bool command_event(enum event_command cmd, void *data)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
command_event_main_state(cmd);
|
||||
return command_event_main_state(cmd);
|
||||
}
|
||||
break;
|
||||
case CMD_EVENT_UNDO_LOAD_STATE:
|
||||
command_event_main_state(cmd);
|
||||
break;
|
||||
return command_event_main_state(cmd);
|
||||
case CMD_EVENT_UNDO_SAVE_STATE:
|
||||
command_event_main_state(cmd);
|
||||
break;
|
||||
return command_event_main_state(cmd);
|
||||
case CMD_EVENT_RESIZE_WINDOWED_SCALE:
|
||||
return command_event_resize_windowed_scale();
|
||||
case CMD_EVENT_MENU_TOGGLE:
|
||||
@@ -1927,6 +1926,9 @@ bool command_event(enum event_command cmd, void *data)
|
||||
core_reset();
|
||||
#ifdef HAVE_CHEEVOS
|
||||
cheevos_reset_game();
|
||||
#endif
|
||||
#if HAVE_NETWORKING
|
||||
netplay_driver_ctl(RARCH_NETPLAY_CTL_RESET, NULL);
|
||||
#endif
|
||||
break;
|
||||
case CMD_EVENT_SAVE_STATE:
|
||||
@@ -1939,10 +1941,8 @@ bool command_event(enum event_command cmd, void *data)
|
||||
|
||||
if (settings->savestate_auto_index)
|
||||
settings->state_slot++;
|
||||
|
||||
command_event_main_state(cmd);
|
||||
}
|
||||
break;
|
||||
return command_event_main_state(cmd);
|
||||
case CMD_EVENT_SAVE_STATE_DECREMENT:
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
@@ -1974,12 +1974,7 @@ bool command_event(enum event_command cmd, void *data)
|
||||
command_event(CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, NULL);
|
||||
|
||||
if (is_inited)
|
||||
if (!task_push_content_load_default(
|
||||
NULL, NULL,
|
||||
&content_info,
|
||||
CORE_TYPE_DUMMY,
|
||||
CONTENT_MODE_LOAD_NOTHING_WITH_DUMMY_CORE,
|
||||
NULL, NULL))
|
||||
if (!task_push_start_dummy_core(&content_info))
|
||||
return false;
|
||||
#ifdef HAVE_DYNAMIC
|
||||
#ifdef HAVE_MENU
|
||||
@@ -2051,7 +2046,7 @@ bool command_event(enum event_command cmd, void *data)
|
||||
#endif
|
||||
{
|
||||
if (settings->rewind_enable)
|
||||
state_manager_event_init(settings->rewind_buffer_size);
|
||||
state_manager_event_init((unsigned)settings->rewind_buffer_size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -2507,9 +2502,12 @@ bool command_event(enum event_command cmd, void *data)
|
||||
if (!init_netplay_deferred(
|
||||
hostname->elems[0].data, atoi(hostname->elems[1].data)))
|
||||
{
|
||||
string_list_free(hostname);
|
||||
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
string_list_free(hostname);
|
||||
}
|
||||
break;
|
||||
case CMD_EVENT_NETPLAY_FLIP_PLAYERS:
|
||||
|
||||
@@ -623,6 +623,9 @@ static bool xmb_show_images = true;
|
||||
static bool xmb_show_music = true;
|
||||
static bool xmb_show_video = true;
|
||||
#endif
|
||||
#ifdef HAVE_NETWORKING
|
||||
static bool xmb_show_netplay = true;
|
||||
#endif
|
||||
static bool xmb_show_history = true;
|
||||
#ifdef HAVE_LIBRETRODB
|
||||
static bool xmb_show_add = true;
|
||||
@@ -652,7 +655,7 @@ static const uint32_t menu_title_color = 0xff64ff64;
|
||||
static bool default_block_config_read = false;
|
||||
#endif
|
||||
|
||||
static bool default_game_specific_options = false;
|
||||
static bool default_game_specific_options = true;
|
||||
static bool default_auto_overrides_enable = true;
|
||||
static bool default_auto_remaps_enable = true;
|
||||
static bool default_auto_shaders_enable = true;
|
||||
@@ -815,6 +818,18 @@ static const bool pause_nonactive = true;
|
||||
* It is measured in seconds. A value of 0 disables autosave. */
|
||||
static const unsigned autosave_interval = 0;
|
||||
|
||||
/* Publicly announce netplay */
|
||||
static const bool netplay_public_announce = true;
|
||||
|
||||
/* Start netplay in spectator mode */
|
||||
static const bool netplay_start_as_spectator = false;
|
||||
|
||||
/* Allow connections in slave mode */
|
||||
static const bool netplay_allow_slaves = true;
|
||||
|
||||
/* Require connections only in slave mode */
|
||||
static const bool netplay_require_slaves = false;
|
||||
|
||||
/* Netplay without savestates/rewind */
|
||||
static const bool netplay_stateless_mode = false;
|
||||
|
||||
@@ -828,6 +843,8 @@ static const unsigned netplay_delay_frames = 16;
|
||||
|
||||
static const int netplay_check_frames = 30;
|
||||
|
||||
static const bool netplay_use_mitm_server = false;
|
||||
|
||||
/* On save state load, block SRAM from being overwritten.
|
||||
* This could potentially lead to buggy games. */
|
||||
static const bool block_sram_overwrite = false;
|
||||
|
||||
@@ -728,8 +728,13 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
|
||||
SETTING_BOOL("all_users_control_menu", &settings->input.all_users_control_menu, true, all_users_control_menu, false);
|
||||
SETTING_BOOL("menu_swap_ok_cancel_buttons", &settings->input.menu_swap_ok_cancel_buttons, true, menu_swap_ok_cancel_buttons, false);
|
||||
#ifdef HAVE_NETWORKING
|
||||
SETTING_BOOL("netplay_stateless_mode", &settings->netplay.stateless_mode, false, netplay_stateless_mode, false);
|
||||
SETTING_BOOL("netplay_public_announce", &settings->netplay.public_announce, true, netplay_public_announce, false);
|
||||
SETTING_BOOL("netplay_start_as_spectator", &settings->netplay.start_as_spectator, false, netplay_start_as_spectator, false);
|
||||
SETTING_BOOL("netplay_allow_slaves", &settings->netplay.allow_slaves, true, netplay_allow_slaves, false);
|
||||
SETTING_BOOL("netplay_require_slaves", &settings->netplay.require_slaves, true, netplay_require_slaves, false);
|
||||
SETTING_BOOL("netplay_stateless_mode", &settings->netplay.stateless_mode, true, netplay_stateless_mode, false);
|
||||
SETTING_BOOL("netplay_client_swap_input", &settings->netplay.swap_input, true, netplay_client_swap_input, false);
|
||||
SETTING_BOOL("netplay_use_mitm_server", &settings->netplay.use_mitm_server, true, netplay_use_mitm_server, false);
|
||||
#endif
|
||||
SETTING_BOOL("input_descriptor_label_show", &settings->input.input_descriptor_label_show, true, input_descriptor_label_show, false);
|
||||
SETTING_BOOL("input_descriptor_hide_unbound", &settings->input.input_descriptor_hide_unbound, true, input_descriptor_hide_unbound, false);
|
||||
@@ -808,6 +813,9 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
|
||||
#ifdef HAVE_FFMPEG
|
||||
SETTING_BOOL("xmb_show_music", &settings->menu.xmb.show_music, true, xmb_show_music, false);
|
||||
SETTING_BOOL("xmb_show_video", &settings->menu.xmb.show_video, true, xmb_show_video, false);
|
||||
#endif
|
||||
#ifdef HAVE_NETWORKING
|
||||
SETTING_BOOL("xmb_show_netplay", &settings->menu.xmb.show_netplay, true, xmb_show_netplay, false);
|
||||
#endif
|
||||
SETTING_BOOL("xmb_show_history", &settings->menu.xmb.show_history, true, xmb_show_history, false);
|
||||
#ifdef HAVE_LIBRETRODB
|
||||
@@ -1157,9 +1165,9 @@ static void config_set_defaults(void)
|
||||
settings->input.autoconf_binds[i][j].joykey = NO_BTN;
|
||||
settings->input.autoconf_binds[i][j].joyaxis = AXIS_NONE;
|
||||
}
|
||||
|
||||
settings->input.autoconfigured[i] = 0;
|
||||
}
|
||||
memset(settings->input.autoconfigured, 0,
|
||||
sizeof(settings->input.autoconfigured));
|
||||
|
||||
/* Verify that binds are in proper order. */
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
@@ -1328,9 +1336,16 @@ static void config_set_defaults(void)
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
if (!string_is_empty(g_defaults.dir.menu_config))
|
||||
{
|
||||
strlcpy(settings->directory.menu_config,
|
||||
g_defaults.dir.menu_config,
|
||||
sizeof(settings->directory.menu_config));
|
||||
#if TARGET_OS_IPHONE
|
||||
path_set(RARCH_PATH_CONFIG,
|
||||
settings->directory.menu_config);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!string_is_empty(g_defaults.dir.menu_content))
|
||||
strlcpy(settings->directory.menu_content,
|
||||
g_defaults.dir.menu_content,
|
||||
@@ -1671,7 +1686,7 @@ static bool check_shader_compatibility(enum file_path_enum enum_idx)
|
||||
}
|
||||
|
||||
if (string_is_equal("gl", settings->video.driver) ||
|
||||
string_is_equal("d3d9", settings->video.driver))
|
||||
string_is_equal("d3d", settings->video.driver))
|
||||
{
|
||||
if (enum_idx == FILE_PATH_SLANGP_EXTENSION)
|
||||
return false;
|
||||
@@ -2662,7 +2677,7 @@ static void save_keybind_hat(config_file_t *conf, const char *key,
|
||||
const struct retro_keybind *bind)
|
||||
{
|
||||
char config[16];
|
||||
unsigned hat = GET_HAT(bind->joykey);
|
||||
unsigned hat = (unsigned)GET_HAT(bind->joykey);
|
||||
const char *dir = NULL;
|
||||
|
||||
config[0] = '\0';
|
||||
@@ -3377,12 +3392,7 @@ bool config_replace(bool config_save_on_exit, char *path)
|
||||
/* Load core in new config. */
|
||||
path_clear(RARCH_PATH_CORE);
|
||||
|
||||
if (!task_push_content_load_default(
|
||||
NULL, NULL,
|
||||
&content_info,
|
||||
CORE_TYPE_DUMMY,
|
||||
CONTENT_MODE_LOAD_NOTHING_WITH_DUMMY_CORE,
|
||||
NULL, NULL))
|
||||
if (!task_push_start_dummy_core(&content_info))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -198,6 +198,7 @@ typedef struct settings
|
||||
bool show_images;
|
||||
bool show_music;
|
||||
bool show_video;
|
||||
bool show_netplay;
|
||||
bool show_history;
|
||||
bool show_add;
|
||||
} xmb;
|
||||
@@ -403,8 +404,12 @@ typedef struct settings
|
||||
#ifdef HAVE_NETWORKING
|
||||
struct
|
||||
{
|
||||
bool public_announce;
|
||||
char server[255];
|
||||
unsigned port;
|
||||
bool start_as_spectator;
|
||||
bool allow_slaves;
|
||||
bool require_slaves;
|
||||
bool stateless_mode;
|
||||
int check_frames;
|
||||
unsigned input_latency_frames_min;
|
||||
@@ -413,6 +418,7 @@ typedef struct settings
|
||||
bool nat_traversal;
|
||||
char password[128];
|
||||
char spectate_password[128];
|
||||
bool use_mitm_server;
|
||||
} netplay;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ static void core_info_list_resolve_all_extensions(
|
||||
(strlen(core_info_list->list[i].supported_extensions) + 2);
|
||||
}
|
||||
|
||||
all_ext_len += strlen("7z|") + strlen("zip|");
|
||||
|
||||
if (all_ext_len)
|
||||
all_ext = (char*)calloc(1, all_ext_len);
|
||||
|
||||
@@ -76,6 +78,12 @@ static void core_info_list_resolve_all_extensions(
|
||||
core_info_list->list[i].supported_extensions, all_ext_len);
|
||||
strlcat(core_info_list->all_ext, "|", all_ext_len);
|
||||
}
|
||||
#ifdef HAVE_7ZIP
|
||||
strlcat(core_info_list->all_ext, "7z|", all_ext_len);
|
||||
#endif
|
||||
#ifdef HAVE_ZLIB
|
||||
strlcat(core_info_list->all_ext, "zip|", all_ext_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void core_info_list_resolve_all_firmware(
|
||||
@@ -820,61 +828,65 @@ bool core_info_unsupported_content_path(const char *path)
|
||||
|
||||
bool core_info_database_supports_content_path(const char *database_path, const char *path)
|
||||
{
|
||||
size_t i;
|
||||
char *database = NULL;
|
||||
const char *delim = NULL;
|
||||
const char *archive_path = NULL;
|
||||
const char *new_path = NULL;
|
||||
const char *new_path = path_basename(database_path);
|
||||
|
||||
if (!core_info_curr_list)
|
||||
if (string_is_empty(new_path))
|
||||
return false;
|
||||
|
||||
new_path = path_basename(database_path);
|
||||
database = strdup(new_path);
|
||||
|
||||
if (!string_is_empty(new_path))
|
||||
database = strdup(new_path);
|
||||
if (string_is_empty(database))
|
||||
return false;
|
||||
|
||||
path_remove_extension(database);
|
||||
|
||||
delim = path_get_archive_delim(path);
|
||||
|
||||
if (delim)
|
||||
archive_path = delim - 1;
|
||||
|
||||
/* if the path contains a compressed file and the core supports archives,
|
||||
* we don't want to look at this file */
|
||||
if (archive_path)
|
||||
if (core_info_curr_list)
|
||||
{
|
||||
size_t i;
|
||||
const char *delim = path_get_archive_delim(path);
|
||||
|
||||
if (delim)
|
||||
{
|
||||
const char *archive_path = delim - 1;
|
||||
|
||||
/* if the path contains a compressed file and the core supports archives,
|
||||
* we don't want to look at this file */
|
||||
if (archive_path)
|
||||
{
|
||||
for (i = 0; i < core_info_curr_list->count; i++)
|
||||
{
|
||||
const core_info_t *info = &core_info_curr_list->list[i];
|
||||
|
||||
if (!string_list_find_elem(info->databases_list, database))
|
||||
continue;
|
||||
|
||||
if ( !string_list_find_elem(info->supported_extensions_list, "zip")
|
||||
&& !string_list_find_elem(info->supported_extensions_list, "7z"))
|
||||
continue;
|
||||
|
||||
free(database);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < core_info_curr_list->count; i++)
|
||||
{
|
||||
const core_info_t *info = &core_info_curr_list->list[i];
|
||||
|
||||
if (!string_list_find_elem(info->supported_extensions_list,
|
||||
path_get_extension(path)))
|
||||
continue;
|
||||
|
||||
if (!string_list_find_elem(info->databases_list, database))
|
||||
continue;
|
||||
|
||||
if ( !string_list_find_elem(info->supported_extensions_list, "zip")
|
||||
&& !string_list_find_elem(info->supported_extensions_list, "7z"))
|
||||
continue;
|
||||
|
||||
free(database);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < core_info_curr_list->count; i++)
|
||||
{
|
||||
const core_info_t *info = &core_info_curr_list->list[i];
|
||||
|
||||
if (!string_list_find_elem(info->supported_extensions_list, path_get_extension(path)))
|
||||
continue;
|
||||
|
||||
if (!string_list_find_elem(info->databases_list, database))
|
||||
continue;
|
||||
|
||||
free(database);
|
||||
return true;
|
||||
}
|
||||
|
||||
free(database);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -410,8 +410,8 @@ void IMAGE_CORE_PREFIX(retro_run)(void)
|
||||
}
|
||||
else if (last_image)
|
||||
{
|
||||
image_index = file_list->size - 1;
|
||||
load_image = true;
|
||||
image_index = (int)(file_list->size - 1);
|
||||
load_image = true;
|
||||
}
|
||||
|
||||
if (load_image)
|
||||
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 357 B |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 562 B |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 880 B |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 343 B |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 874 B |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 639 B |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 17 KiB |
@@ -293,52 +293,52 @@ static int database_cursor_iterate(libretrodb_cursor_t *cur,
|
||||
break;
|
||||
case DB_CURSOR_CERO_RATING:
|
||||
if (!string_is_empty(val_string))
|
||||
db_info->cero_rating = strdup(val_string);
|
||||
db_info->cero_rating = strdup(val_string);
|
||||
break;
|
||||
case DB_CURSOR_PEGI_RATING:
|
||||
if (!string_is_empty(val_string))
|
||||
db_info->pegi_rating = strdup(val_string);
|
||||
db_info->pegi_rating = strdup(val_string);
|
||||
break;
|
||||
case DB_CURSOR_ENHANCEMENT_HW:
|
||||
if (!string_is_empty(val_string))
|
||||
db_info->enhancement_hw = strdup(val_string);
|
||||
db_info->enhancement_hw = strdup(val_string);
|
||||
break;
|
||||
case DB_CURSOR_EDGE_MAGAZINE_REVIEW:
|
||||
if (!string_is_empty(val_string))
|
||||
db_info->edge_magazine_review = strdup(val_string);
|
||||
break;
|
||||
case DB_CURSOR_EDGE_MAGAZINE_RATING:
|
||||
db_info->edge_magazine_rating = val->val.uint_;
|
||||
db_info->edge_magazine_rating = (unsigned)val->val.uint_;
|
||||
break;
|
||||
case DB_CURSOR_EDGE_MAGAZINE_ISSUE:
|
||||
db_info->edge_magazine_issue = val->val.uint_;
|
||||
db_info->edge_magazine_issue = (unsigned)val->val.uint_;
|
||||
break;
|
||||
case DB_CURSOR_FAMITSU_MAGAZINE_RATING:
|
||||
db_info->famitsu_magazine_rating = val->val.uint_;
|
||||
db_info->famitsu_magazine_rating = (unsigned)val->val.uint_;
|
||||
break;
|
||||
case DB_CURSOR_TGDB_RATING:
|
||||
db_info->tgdb_rating = val->val.uint_;
|
||||
db_info->tgdb_rating = (unsigned)val->val.uint_;
|
||||
break;
|
||||
case DB_CURSOR_MAX_USERS:
|
||||
db_info->max_users = val->val.uint_;
|
||||
db_info->max_users = (unsigned)val->val.uint_;
|
||||
break;
|
||||
case DB_CURSOR_RELEASEDATE_MONTH:
|
||||
db_info->releasemonth = val->val.uint_;
|
||||
db_info->releasemonth = (unsigned)val->val.uint_;
|
||||
break;
|
||||
case DB_CURSOR_RELEASEDATE_YEAR:
|
||||
db_info->releaseyear = val->val.uint_;
|
||||
db_info->releaseyear = (unsigned)val->val.uint_;
|
||||
break;
|
||||
case DB_CURSOR_RUMBLE_SUPPORTED:
|
||||
db_info->rumble_supported = val->val.uint_;
|
||||
db_info->rumble_supported = (int)val->val.uint_;
|
||||
break;
|
||||
case DB_CURSOR_COOP_SUPPORTED:
|
||||
db_info->coop_supported = val->val.uint_;
|
||||
db_info->coop_supported = (int)val->val.uint_;
|
||||
break;
|
||||
case DB_CURSOR_ANALOG_SUPPORTED:
|
||||
db_info->analog_supported = val->val.uint_;
|
||||
db_info->analog_supported = (int)val->val.uint_;
|
||||
break;
|
||||
case DB_CURSOR_SIZE:
|
||||
db_info->size = val->val.uint_;
|
||||
db_info->size = (unsigned)val->val.uint_;
|
||||
break;
|
||||
case DB_CURSOR_CHECKSUM_CRC32:
|
||||
db_info->crc32 = swap_if_little32(*(uint32_t*)val->val.binary.buff);
|
||||
|
||||
@@ -0,0 +1,684 @@
|
||||
$Id: Changelog.txt,v 1.226 2016/12/16 08:57:19 nanard Exp $
|
||||
miniUPnP client Changelog.
|
||||
|
||||
2016/11/11:
|
||||
check strlen before memcmp in XML parsing portlistingparse.c
|
||||
fix build under SOLARIS and CYGWIN
|
||||
|
||||
2016/10/11:
|
||||
Add python 3 compatibility to IGD test
|
||||
|
||||
VERSION 2.0 : released 2016/04/19
|
||||
|
||||
2016/01/24:
|
||||
change miniwget to return HTTP status code
|
||||
increments API_VERSION to 16
|
||||
|
||||
2016/01/22:
|
||||
Improve UPNPIGD_IsConnected() to check if WAN address is not private.
|
||||
parse HTTP response status line in miniwget.c
|
||||
|
||||
2015/10/26:
|
||||
snprintf() overflow check. check overflow in simpleUPnPcommand2()
|
||||
|
||||
2015/10/25:
|
||||
fix compilation with old macs
|
||||
fix compilation with mingw32 (for Appveyor)
|
||||
fix python module for python <= 2.3
|
||||
|
||||
2015/10/08:
|
||||
Change sameport to localport
|
||||
see https://github.com/miniupnp/miniupnp/pull/120
|
||||
increments API_VERSION to 15
|
||||
|
||||
2015/09/15:
|
||||
Fix buffer overflow in igd_desc_parse.c/IGDstartelt()
|
||||
Discovered by Aleksandar Nikolic of Cisco Talos
|
||||
|
||||
2015/08/28:
|
||||
move ssdpDiscoverDevices() to minissdpc.c
|
||||
|
||||
2015/08/27:
|
||||
avoid unix socket leak in getDevicesFromMiniSSDPD()
|
||||
|
||||
2015/08/16:
|
||||
Also accept "Up" as ConnectionStatus value
|
||||
|
||||
2015/07/23:
|
||||
split getDevicesFromMiniSSDPD
|
||||
add ttl argument to upnpDiscover() functions
|
||||
increments API_VERSION to 14
|
||||
|
||||
2015/07/22:
|
||||
Read USN from SSDP messages.
|
||||
|
||||
2015/07/15:
|
||||
Check malloc/calloc
|
||||
|
||||
2015/06/16:
|
||||
update getDevicesFromMiniSSDPD() to process longer minissdpd
|
||||
responses
|
||||
|
||||
2015/05/22:
|
||||
add searchalltypes param to upnpDiscoverDevices()
|
||||
increments API_VERSION to 13
|
||||
|
||||
2015/04/30:
|
||||
upnpc: output version on the terminal
|
||||
|
||||
2015/04/27:
|
||||
_BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE
|
||||
fix CMakeLists.txt COMPILE_DEFINITIONS
|
||||
fix getDevicesFromMiniSSDPD() not setting scope_id
|
||||
improve -r command of upnpc command line tool
|
||||
|
||||
2014/11/17:
|
||||
search all :
|
||||
upnpDiscoverDevices() / upnpDiscoverAll() functions
|
||||
listdevices executable
|
||||
increment API_VERSION to 12
|
||||
validate igd_desc_parse
|
||||
|
||||
2014/11/13:
|
||||
increment API_VERSION to 11
|
||||
|
||||
2014/11/05:
|
||||
simplified function GetUPNPUrls()
|
||||
|
||||
2014/09/11:
|
||||
use remoteHost arg of DeletePortMapping
|
||||
|
||||
2014/09/06:
|
||||
Fix python3 build
|
||||
|
||||
2014/07/01:
|
||||
Fix parsing of IGD2 root descriptions
|
||||
|
||||
2014/06/10:
|
||||
rename LIBSPEC to MINIUPNP_LIBSPEC
|
||||
|
||||
2014/05/15:
|
||||
Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange
|
||||
|
||||
2014/02/05:
|
||||
handle EINPROGRESS after connect()
|
||||
|
||||
2014/02/03:
|
||||
minixml now handle XML comments
|
||||
|
||||
VERSION 1.9 : released 2014/01/31
|
||||
|
||||
2014/01/31:
|
||||
added argument remoteHost to UPNP_GetSpecificPortMappingEntry()
|
||||
increment API_VERSION to 10
|
||||
|
||||
2013/12/09:
|
||||
--help and -h arguments in upnpc.c
|
||||
|
||||
2013/10/07:
|
||||
fixed potential buffer overrun in miniwget.c
|
||||
Modified UPNP_GetValidIGD() to check for ExternalIpAddress
|
||||
|
||||
2013/08/01:
|
||||
define MAXHOSTNAMELEN if not already done
|
||||
|
||||
2013/06/06:
|
||||
update upnpreplyparse to allow larger values (128 chars instead of 64)
|
||||
|
||||
2013/05/14:
|
||||
Update upnpreplyparse to take into account "empty" elements
|
||||
validate upnpreplyparse.c code with "make check"
|
||||
|
||||
2013/05/03:
|
||||
Fix Solaris build thanks to Maciej Małecki
|
||||
|
||||
2013/04/27:
|
||||
Fix testminiwget.sh for BSD
|
||||
|
||||
2013/03/23:
|
||||
Fixed Makefile for *BSD
|
||||
|
||||
2013/03/11:
|
||||
Update Makefile to use JNAerator version 0.11
|
||||
|
||||
2013/02/11:
|
||||
Fix testminiwget.sh for use with dash
|
||||
Use $(DESTDIR) in Makefile
|
||||
|
||||
VERSION 1.8 : released 2013/02/06
|
||||
|
||||
2012/10/16:
|
||||
fix testminiwget with no IPv6 support
|
||||
|
||||
2012/09/27:
|
||||
Rename all include guards to not clash with C99
|
||||
(7.1.3 Reserved identifiers).
|
||||
|
||||
2012/08/30:
|
||||
Added -e option to upnpc program (set description for port mappings)
|
||||
|
||||
2012/08/29:
|
||||
Python 3 support (thanks to Christopher Foo)
|
||||
|
||||
2012/08/11:
|
||||
Fix a memory link in UPNP_GetValidIGD()
|
||||
Try to handle scope id in link local IPv6 URL under MS Windows
|
||||
|
||||
2012/07/20:
|
||||
Disable HAS_IP_MREQN on DragonFly BSD
|
||||
|
||||
2012/06/28:
|
||||
GetUPNPUrls() now inserts scope into link-local IPv6 addresses
|
||||
|
||||
2012/06/23:
|
||||
More error return checks in upnpc.c
|
||||
#define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id
|
||||
parseURL() now parses IPv6 addresses scope
|
||||
new parameter for miniwget() : IPv6 address scope
|
||||
increment API_VERSION to 9
|
||||
|
||||
2012/06/20:
|
||||
fixed CMakeLists.txt
|
||||
|
||||
2012/05/29
|
||||
Improvements in testminiwget.sh
|
||||
|
||||
VERSION 1.7 : released 2012/05/24
|
||||
|
||||
2012/05/01:
|
||||
Cleanup settings of CFLAGS in Makefile
|
||||
Fix signed/unsigned integer comparaisons
|
||||
|
||||
2012/04/20:
|
||||
Allow to specify protocol with TCP or UDP for -A option
|
||||
|
||||
2012/04/09:
|
||||
Only try to fetch XML description once in UPNP_GetValidIGD()
|
||||
Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments.
|
||||
|
||||
2012/04/05:
|
||||
minor improvements to minihttptestserver.c
|
||||
|
||||
2012/03/15:
|
||||
upnperrors.c returns valid error string for unrecognized error codes
|
||||
|
||||
2012/03/08:
|
||||
make minihttptestserver listen on loopback interface instead of 0.0.0.0
|
||||
|
||||
2012/01/25:
|
||||
Maven installation thanks to Alexey Kuznetsov
|
||||
|
||||
2012/01/21:
|
||||
Replace WIN32 macro by _WIN32
|
||||
|
||||
2012/01/19:
|
||||
Fixes in java wrappers thanks to Alexey Kuznetsov :
|
||||
https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc
|
||||
Make and install .deb packages (python) thanks to Alexey Kuznetsov :
|
||||
https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc
|
||||
|
||||
2012/01/07:
|
||||
The multicast interface can now be specified by name with IPv4.
|
||||
|
||||
2012/01/02:
|
||||
Install man page
|
||||
|
||||
2011/11/25:
|
||||
added header to Port Mappings list in upnpc.c
|
||||
|
||||
2011/10/09:
|
||||
Makefile : make clean now removes jnaerator generated files.
|
||||
MINIUPNPC_VERSION in miniupnpc.h (updated by make)
|
||||
|
||||
2011/09/12:
|
||||
added rootdescURL to UPNPUrls structure.
|
||||
|
||||
VERSION 1.6 : released 2011/07/25
|
||||
|
||||
2011/07/25:
|
||||
Update doc for version 1.6 release
|
||||
|
||||
2011/06/18:
|
||||
Fix for windows in miniwget.c
|
||||
|
||||
2011/06/04:
|
||||
display remote host in port mapping listing
|
||||
|
||||
2011/06/03:
|
||||
Fix in make install : there were missing headers
|
||||
|
||||
2011/05/26:
|
||||
Fix the socket leak in miniwget thanks to Richard Marsh.
|
||||
Permit to add leaseduration in -a command. Display lease duration.
|
||||
|
||||
2011/05/15:
|
||||
Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6
|
||||
|
||||
2011/05/09:
|
||||
add a test in testminiwget.sh.
|
||||
more error checking in miniwget.c
|
||||
|
||||
2011/05/06:
|
||||
Adding some tool to test and validate miniwget.c
|
||||
simplified and debugged miniwget.c
|
||||
|
||||
2011/04/11:
|
||||
moving ReceiveData() to a receivedata.c file.
|
||||
parsing presentation url
|
||||
adding IGD v2 WANIPv6FirewallControl commands
|
||||
|
||||
2011/04/10:
|
||||
update of miniupnpcmodule.c
|
||||
comments in miniwget.c, update in testminiwget
|
||||
Adding errors codes from IGD v2
|
||||
new functions in upnpc.c for IGD v2
|
||||
|
||||
2011/04/09:
|
||||
Support for litteral ip v6 address in miniwget
|
||||
|
||||
2011/04/08:
|
||||
Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
|
||||
Updating APIVERSION
|
||||
Supporting IPV6 in upnpDiscover()
|
||||
Adding a -6 option to upnpc command line tool
|
||||
|
||||
2011/03/18:
|
||||
miniwget/parseURL() : return an error when url param is null.
|
||||
fixing GetListOfPortMappings()
|
||||
|
||||
2011/03/14:
|
||||
upnpDiscover() now reporting an error code.
|
||||
improvements in comments.
|
||||
|
||||
2011/03/11:
|
||||
adding miniupnpcstrings.h.cmake and CMakeLists.txt files.
|
||||
|
||||
2011/02/15:
|
||||
Implementation of GetListOfPortMappings()
|
||||
|
||||
2011/02/07:
|
||||
updates to minixml to support character data starting with spaces
|
||||
minixml now support CDATA
|
||||
upnpreplyparse treats <NewPortListing> specificaly
|
||||
change in simpleUPnPcommand to return the buffer (simplification)
|
||||
|
||||
2011/02/06:
|
||||
Added leaseDuration argument to AddPortMapping()
|
||||
Starting to implement GetListOfPortMappings()
|
||||
|
||||
2011/01/11:
|
||||
updating wingenminiupnpcstrings.c
|
||||
|
||||
2011/01/04:
|
||||
improving updateminiupnpcstrings.sh
|
||||
|
||||
VERSION 1.5 : released 2011/01/01
|
||||
|
||||
2010/12/21:
|
||||
use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo
|
||||
|
||||
2010/12/11:
|
||||
Improvements on getHTTPResponse() code.
|
||||
|
||||
2010/12/09:
|
||||
new code for miniwget that handle Chunked transfer encoding
|
||||
using getHTTPResponse() in SOAP call code
|
||||
Adding MANIFEST.in for 'python setup.py bdist_rpm'
|
||||
|
||||
2010/11/25:
|
||||
changes to minissdpc.c to compile under Win32.
|
||||
see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729
|
||||
|
||||
2010/09/17:
|
||||
Various improvement to Makefile from Michał Górny
|
||||
|
||||
2010/08/05:
|
||||
Adding the script "external-ip.sh" from Reuben Hawkins
|
||||
|
||||
2010/06/09:
|
||||
update to python module to match modification made on 2010/04/05
|
||||
update to Java test code to match modification made on 2010/04/05
|
||||
all UPNP_* function now return an error if the SOAP request failed
|
||||
at HTTP level.
|
||||
|
||||
2010/04/17:
|
||||
Using GetBestRoute() under win32 in order to find the
|
||||
right interface to use.
|
||||
|
||||
2010/04/12:
|
||||
Retrying with HTTP/1.1 if HTTP/1.0 failed. see
|
||||
http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703
|
||||
|
||||
2010/04/07:
|
||||
avoid returning duplicates in upnpDiscover()
|
||||
|
||||
2010/04/05:
|
||||
Create a connecthostport.h/.c with connecthostport() function
|
||||
and use it in miniwget and miniupnpc.
|
||||
Use getnameinfo() instead of inet_ntop or inet_ntoa
|
||||
Work to make miniupnpc IPV6 compatible...
|
||||
Add java test code.
|
||||
Big changes in order to support device having both WANIPConnection
|
||||
and WANPPPConnection.
|
||||
|
||||
2010/04/04:
|
||||
Use getaddrinfo() instead of gethostbyname() in miniwget.
|
||||
|
||||
2010/01/06:
|
||||
#define _DARWIN_C_SOURCE for Mac OS X
|
||||
|
||||
2009/12/19:
|
||||
Improve MinGW32 build
|
||||
|
||||
2009/12/11:
|
||||
adding a MSVC9 project to build the static library and executable
|
||||
|
||||
2009/12/10:
|
||||
Fixing some compilation stuff for Windows/MinGW
|
||||
|
||||
2009/12/07:
|
||||
adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS
|
||||
some fixes for Windows when using virtual ethernet adapters (it is the
|
||||
case with VMWare installed).
|
||||
|
||||
2009/12/04:
|
||||
some fixes for AmigaOS compilation
|
||||
Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked
|
||||
transfer encoding)
|
||||
|
||||
2009/12/03:
|
||||
updating printIDG and testigddescparse.c for debug.
|
||||
modifications to compile under AmigaOS
|
||||
adding a testminiwget program
|
||||
Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked
|
||||
transfer encoding
|
||||
|
||||
2009/11/26:
|
||||
fixing updateminiupnpcstrings.sh to take into account
|
||||
which command that does not return an error code.
|
||||
|
||||
VERSION 1.4 : released 2009/10/30
|
||||
|
||||
2009/10/16:
|
||||
using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module.
|
||||
|
||||
2009/10/10:
|
||||
Some fixes for compilation under Solaris
|
||||
compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464
|
||||
|
||||
2009/09/21:
|
||||
fixing the code to ignore EINTR during connect() calls.
|
||||
|
||||
2009/08/07:
|
||||
Set socket timeout for connect()
|
||||
Some cleanup in miniwget.c
|
||||
|
||||
2009/08/04:
|
||||
remove multiple redirections with -d in upnpc.c
|
||||
Print textual error code in upnpc.c
|
||||
Ignore EINTR during the connect() and poll() calls.
|
||||
|
||||
2009/07/29:
|
||||
fix in updateminiupnpcstrings.sh if OS name contains "/"
|
||||
Sending a correct value for MX: field in SSDP request
|
||||
|
||||
2009/07/20:
|
||||
Change the Makefile to compile under Mac OS X
|
||||
Fixed a stackoverflow in getDevicesFromMiniSSDPD()
|
||||
|
||||
2009/07/09:
|
||||
Compile under Haiku
|
||||
generate miniupnpcstrings.h.in from miniupnpcstrings.h
|
||||
|
||||
2009/06/04:
|
||||
patching to compile under CygWin and cross compile for minGW
|
||||
|
||||
VERSION 1.3 :
|
||||
|
||||
2009/04/17:
|
||||
updating python module
|
||||
Use strtoull() when using C99
|
||||
|
||||
2009/02/28:
|
||||
Fixed miniwget.c for compiling under sun
|
||||
|
||||
2008/12/18:
|
||||
cleanup in Makefile (thanks to Paul de Weerd)
|
||||
minissdpc.c : win32 compatibility
|
||||
miniupnpc.c : changed xmlns prefix from 'm' to 'u'
|
||||
Removed NDEBUG (using DEBUG)
|
||||
|
||||
2008/10/14:
|
||||
Added the ExternalHost argument to DeletePortMapping()
|
||||
|
||||
2008/10/11:
|
||||
Added the ExternalHost argument to AddPortMapping()
|
||||
Put a correct User-Agent: header in HTTP requests.
|
||||
|
||||
VERSION 1.2 :
|
||||
|
||||
2008/10/07:
|
||||
Update docs
|
||||
|
||||
2008/09/25:
|
||||
Integrated sameport patch from Dario Meloni : Added a "sameport"
|
||||
argument to upnpDiscover().
|
||||
|
||||
2008/07/18:
|
||||
small modif to make Clang happy :)
|
||||
|
||||
2008/07/17:
|
||||
#define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV...
|
||||
|
||||
2008/07/14:
|
||||
include declspec.h in installation (to /usr/include/miniupnpc)
|
||||
|
||||
VERSION 1.1 :
|
||||
|
||||
2008/07/04:
|
||||
standard options for install/ln instead of gnu-specific stuff.
|
||||
|
||||
2008/07/03:
|
||||
now builds a .dll and .lib with win32. (mingw32)
|
||||
|
||||
2008/04/28:
|
||||
make install now install the binary of the upnpc tool
|
||||
|
||||
2008/04/27:
|
||||
added testupnpigd.py
|
||||
added error strings for miniupnpc "internal" errors
|
||||
improved python module error/exception reporting.
|
||||
|
||||
2008/04/23:
|
||||
Completely rewrite igd_desc_parse.c in order to be compatible with
|
||||
Linksys WAG200G
|
||||
Added testigddescparse
|
||||
updated python module
|
||||
|
||||
VERSION 1.0 :
|
||||
|
||||
2008/02/21:
|
||||
put some #ifdef DEBUG around DisplayNameValueList()
|
||||
|
||||
2008/02/18:
|
||||
Improved error reporting in upnpcommands.c
|
||||
UPNP_GetStatusInfo() returns LastConnectionError
|
||||
|
||||
2008/02/16:
|
||||
better error handling in minisoap.c
|
||||
improving display of "valid IGD found" in upnpc.c
|
||||
|
||||
2008/02/03:
|
||||
Fixing UPNP_GetValidIGD()
|
||||
improved make install :)
|
||||
|
||||
2007/12/22:
|
||||
Adding upnperrors.c/h to provide a strupnperror() function
|
||||
used to translate UPnP error codes to string.
|
||||
|
||||
2007/12/19:
|
||||
Fixing getDevicesFromMiniSSDPD()
|
||||
improved error reporting of UPnP functions
|
||||
|
||||
2007/12/18:
|
||||
It is now possible to specify a different location for MiniSSDPd socket.
|
||||
working with MiniSSDPd is now more efficient.
|
||||
python module improved.
|
||||
|
||||
2007/12/16:
|
||||
improving error reporting
|
||||
|
||||
2007/12/13:
|
||||
Try to improve compatibility by using HTTP/1.0 instead of 1.1 and
|
||||
XML a bit different for SOAP.
|
||||
|
||||
2007/11/25:
|
||||
fixed select() call for linux
|
||||
|
||||
2007/11/15:
|
||||
Added -fPIC to CFLAG for better shared library code.
|
||||
|
||||
2007/11/02:
|
||||
Fixed a potential socket leak in miniwget2()
|
||||
|
||||
2007/10/16:
|
||||
added a parameter to upnpDiscover() in order to allow the use of another
|
||||
interface than the default multicast interface.
|
||||
|
||||
2007/10/12:
|
||||
Fixed the creation of symbolic link in Makefile
|
||||
|
||||
2007/10/08:
|
||||
Added man page
|
||||
|
||||
2007/10/02:
|
||||
fixed memory bug in GetUPNPUrls()
|
||||
|
||||
2007/10/01:
|
||||
fixes in the Makefile
|
||||
Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly.
|
||||
Added SONAME in the shared library to please debian :)
|
||||
fixed MS Windows compilation (minissdpd is not available under MS Windows).
|
||||
|
||||
2007/09/25:
|
||||
small change to Makefile to be able to install in a different location
|
||||
(default is /usr)
|
||||
|
||||
2007/09/24:
|
||||
now compiling both shared and static library
|
||||
|
||||
2007/09/19:
|
||||
Cosmetic changes on upnpc.c
|
||||
|
||||
2007/09/02:
|
||||
adapting to new miniSSDPd (release version ?)
|
||||
|
||||
2007/08/31:
|
||||
Usage of miniSSDPd to skip discovery process.
|
||||
|
||||
2007/08/27:
|
||||
fixed python module to allow compilation with Python older than Python 2.4
|
||||
|
||||
2007/06/12:
|
||||
Added a python module.
|
||||
|
||||
2007/05/19:
|
||||
Fixed compilation under MinGW
|
||||
|
||||
2007/05/15:
|
||||
fixed a memory leak in AddPortMapping()
|
||||
Added testupnpreplyparse executable to check the parsing of
|
||||
upnp soap messages
|
||||
minixml now ignore namespace prefixes.
|
||||
|
||||
2007/04/26:
|
||||
upnpc now displays external ip address with -s or -l
|
||||
|
||||
2007/04/11:
|
||||
changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210"
|
||||
|
||||
2007/03/19:
|
||||
cleanup in miniwget.c
|
||||
|
||||
2007/03/01:
|
||||
Small typo fix...
|
||||
|
||||
2007/01/30:
|
||||
Now parsing the HTTP header from SOAP responses in order to
|
||||
get content-length value.
|
||||
|
||||
2007/01/29:
|
||||
Fixed the Soap Query to speedup the HTTP request.
|
||||
added some Win32 DLL stuff...
|
||||
|
||||
2007/01/27:
|
||||
Fixed some WIN32 compatibility issues
|
||||
|
||||
2006/12/14:
|
||||
Added UPNPIGD_IsConnected() function in miniupnp.c/.h
|
||||
Added UPNP_GetValidIGD() in miniupnp.c/.h
|
||||
cleaned upnpc.c main(). now using UPNP_GetValidIGD()
|
||||
|
||||
2006/12/07:
|
||||
Version 1.0-RC1 released
|
||||
|
||||
2006/12/03:
|
||||
Minor changes to compile under SunOS/Solaris
|
||||
|
||||
2006/11/30:
|
||||
made a minixml parser validator program
|
||||
updated minixml to handle attributes correctly
|
||||
|
||||
2006/11/22:
|
||||
Added a -r option to the upnpc sample thanks to Alexander Hubmann.
|
||||
|
||||
2006/11/19:
|
||||
Cleanup code to make it more ANSI C compliant
|
||||
|
||||
2006/11/10:
|
||||
detect and display local lan address.
|
||||
|
||||
2006/11/04:
|
||||
Packets and Bytes Sent/Received are now unsigned int.
|
||||
|
||||
2006/11/01:
|
||||
Bug fix thanks to Giuseppe D'Angelo
|
||||
|
||||
2006/10/31:
|
||||
C++ compatibility for .h files.
|
||||
Added a way to get ip Address on the LAN used to reach the IGD.
|
||||
|
||||
2006/10/25:
|
||||
Added M-SEARCH to the services in the discovery process.
|
||||
|
||||
2006/10/22:
|
||||
updated the Makefile to use makedepend, added a "make install"
|
||||
update Makefile
|
||||
|
||||
2006/10/20:
|
||||
fixing the description url parsing thanks to patch sent by
|
||||
Wayne Dawe.
|
||||
Fixed/translated some comments.
|
||||
Implemented a better discover process, first looking
|
||||
for IGD then for root devices (as some devices only reply to
|
||||
M-SEARCH for root devices).
|
||||
|
||||
2006/09/02:
|
||||
added freeUPNPDevlist() function.
|
||||
|
||||
2006/08/04:
|
||||
More command line arguments checking
|
||||
|
||||
2006/08/01:
|
||||
Added the .bat file to compile under Win32 with minGW32
|
||||
|
||||
2006/07/31:
|
||||
Fixed the rootdesc parser (igd_desc_parse.c)
|
||||
|
||||
2006/07/20:
|
||||
parseMSEARCHReply() is now returning the ST: line as well
|
||||
starting changes to detect several UPnP devices on the network
|
||||
|
||||
2006/07/19:
|
||||
using GetCommonLinkProperties to get down/upload bitrate
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
MiniUPnPc
|
||||
Copyright (c) 2005-2016, Thomas BERNARD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
include README
|
||||
include miniupnpcmodule.c
|
||||
include setup.py
|
||||
include *.h
|
||||
include libminiupnpc.a
|
||||
@@ -0,0 +1,274 @@
|
||||
# $Id: Makefile,v 1.134 2016/10/07 09:04:36 nanard Exp $
|
||||
# MiniUPnP Project
|
||||
# http://miniupnp.free.fr/
|
||||
# http://miniupnp.tuxfamily.org/
|
||||
# https://github.com/miniupnp/miniupnp
|
||||
# (c) 2005-2016 Thomas Bernard
|
||||
# to install use :
|
||||
# $ make DESTDIR=/tmp/dummylocation install
|
||||
# or
|
||||
# $ INSTALLPREFIX=/usr/local make install
|
||||
# or
|
||||
# $ make install (default INSTALLPREFIX is /usr)
|
||||
OS = $(shell uname -s)
|
||||
VERSION = $(shell cat VERSION)
|
||||
|
||||
ifeq ($(OS), Darwin)
|
||||
JARSUFFIX=mac
|
||||
LIBTOOL ?= $(shell which libtool)
|
||||
endif
|
||||
ifeq ($(OS), Linux)
|
||||
JARSUFFIX=linux
|
||||
endif
|
||||
ifneq (,$(findstring NT-5.1,$(OS)))
|
||||
JARSUFFIX=win32
|
||||
endif
|
||||
|
||||
HAVE_IPV6 ?= yes
|
||||
export HAVE_IPV6
|
||||
|
||||
CC ?= gcc
|
||||
#AR = gar
|
||||
#CFLAGS = -O -g -DDEBUG
|
||||
CFLAGS ?= -O
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -W -Wstrict-prototypes
|
||||
CFLAGS += -fno-common
|
||||
CFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
CFLAGS += -DMINIUPNPC_GET_SRC_ADDR
|
||||
CFLAGS += -D_BSD_SOURCE
|
||||
CFLAGS += -D_DEFAULT_SOURCE
|
||||
ifeq ($(OS), NetBSD)
|
||||
CFLAGS += -D_NETBSD_SOURCE
|
||||
endif
|
||||
ifneq ($(OS), FreeBSD)
|
||||
ifneq ($(OS), Darwin)
|
||||
#CFLAGS += -D_POSIX_C_SOURCE=200112L
|
||||
CFLAGS += -D_XOPEN_SOURCE=600
|
||||
endif
|
||||
endif
|
||||
#CFLAGS += -ansi
|
||||
# -DNO_GETADDRINFO
|
||||
INSTALL = install
|
||||
SH = /bin/sh
|
||||
|
||||
ifeq (SunOS, $(OS))
|
||||
LDLIBS=-lsocket -lnsl -lresolv
|
||||
CFLAGS += -D__EXTENSIONS__
|
||||
CFLAGS += -std=c99
|
||||
endif
|
||||
|
||||
# APIVERSION is used to build SONAME
|
||||
APIVERSION = 16
|
||||
|
||||
SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \
|
||||
upnpcommands.c upnpreplyparse.c \
|
||||
minixmlvalid.c minissdpc.c \
|
||||
upnperrors.c \
|
||||
connecthostport.c portlistingparse.c receivedata.c \
|
||||
upnpdev.c miniupnpcmodule.c
|
||||
|
||||
LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \
|
||||
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
|
||||
connecthostport.o portlistingparse.o receivedata.o upnpdev.o
|
||||
|
||||
ifneq ($(OS), AmigaOS)
|
||||
ifeq (,$(findstring CYGWIN,$(OS)))
|
||||
CFLAGS := -fPIC $(CFLAGS)
|
||||
endif
|
||||
LIBOBJS := $(LIBOBJS) minissdpc.o
|
||||
endif
|
||||
|
||||
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||
|
||||
# HEADERS to install
|
||||
HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \
|
||||
upnpreplyparse.h upnperrors.h miniupnpctypes.h \
|
||||
portlistingparse.h \
|
||||
upnpdev.h \
|
||||
miniupnpc_declspec.h
|
||||
|
||||
# library names
|
||||
LIBRARY = libminiupnpc.a
|
||||
ifeq ($(OS), Darwin)
|
||||
SHAREDLIBRARY = libminiupnpc.dylib
|
||||
SONAME = $(basename $(SHAREDLIBRARY)).$(APIVERSION).dylib
|
||||
CFLAGS := -D_DARWIN_C_SOURCE $(CFLAGS)
|
||||
else
|
||||
ifeq ($(JARSUFFIX), win32)
|
||||
SHAREDLIBRARY = miniupnpc.dll
|
||||
else
|
||||
# Linux/BSD/etc.
|
||||
SHAREDLIBRARY = libminiupnpc.so
|
||||
SONAME = $(SHAREDLIBRARY).$(APIVERSION)
|
||||
endif
|
||||
endif
|
||||
|
||||
EXECUTABLES = upnpc-static
|
||||
|
||||
ifneq ($(OS), AmigaOS)
|
||||
EXECUTABLES := $(EXECUTABLES) upnpc-shared
|
||||
endif
|
||||
|
||||
LIBDIR ?= lib
|
||||
# install directories
|
||||
ifeq ($(strip $(PREFIX)),)
|
||||
INSTALLPREFIX ?= /usr
|
||||
else
|
||||
INSTALLPREFIX ?= $(PREFIX)
|
||||
endif
|
||||
INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc
|
||||
INSTALLDIRLIB = $(INSTALLPREFIX)/$(LIBDIR)
|
||||
INSTALLDIRBIN = $(INSTALLPREFIX)/bin
|
||||
INSTALLDIRMAN = $(INSTALLPREFIX)/share/man
|
||||
|
||||
FILESTOINSTALL = $(LIBRARY) $(EXECUTABLES)
|
||||
ifneq ($(OS), AmigaOS)
|
||||
FILESTOINSTALL := $(FILESTOINSTALL) $(SHAREDLIBRARY)
|
||||
endif
|
||||
|
||||
|
||||
.PHONY: install clean depend all check test everything \
|
||||
updateversion
|
||||
# validateminixml validateminiwget
|
||||
|
||||
all: $(LIBRARY) $(EXECUTABLES)
|
||||
|
||||
test: check
|
||||
|
||||
check: validateminixml validateminiwget validateupnpreplyparse \
|
||||
validateportlistingparse validateigddescparse
|
||||
|
||||
everything: all
|
||||
|
||||
validateminixml: minixmlvalid
|
||||
@echo "minixml validation test"
|
||||
./minixmlvalid
|
||||
touch $@
|
||||
|
||||
validateminiwget: testminiwget minihttptestserver testminiwget.sh
|
||||
@echo "miniwget validation test"
|
||||
./testminiwget.sh
|
||||
touch $@
|
||||
|
||||
validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh
|
||||
@echo "upnpreplyparse validation test"
|
||||
./testupnpreplyparse.sh
|
||||
touch $@
|
||||
|
||||
validateportlistingparse: testportlistingparse
|
||||
@echo "portlistingparse validation test"
|
||||
./testportlistingparse
|
||||
touch $@
|
||||
|
||||
validateigddescparse: testigddescparse
|
||||
@echo "igd desc parse validation test"
|
||||
./testigddescparse testdesc/new_LiveBox_desc.xml testdesc/new_LiveBox_desc.values
|
||||
./testigddescparse testdesc/linksys_WAG200G_desc.xml testdesc/linksys_WAG200G_desc.values
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
$(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h
|
||||
|
||||
distclean: clean
|
||||
|
||||
updateversion: miniupnpc.h
|
||||
cp miniupnpc.h miniupnpc.h.bak
|
||||
sed 's/\(.*MINIUPNPC_API_VERSION\s\+\)[0-9]\+/\1$(APIVERSION)/' < miniupnpc.h.bak > miniupnpc.h
|
||||
|
||||
install: updateversion $(FILESTOINSTALL)
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC)
|
||||
$(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC)
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB)
|
||||
$(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB)
|
||||
ifneq ($(OS), AmigaOS)
|
||||
$(INSTALL) -m 644 $(SHAREDLIBRARY) $(DESTDIR)$(INSTALLDIRLIB)/$(SONAME)
|
||||
ln -fs $(SONAME) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY)
|
||||
endif
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN)
|
||||
ifeq ($(OS), AmigaOS)
|
||||
$(INSTALL) -m 755 upnpc-static $(DESTDIR)$(INSTALLDIRBIN)/upnpc
|
||||
else
|
||||
$(INSTALL) -m 755 upnpc-shared $(DESTDIR)$(INSTALLDIRBIN)/upnpc
|
||||
endif
|
||||
$(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
|
||||
ifneq ($(OS), AmigaOS)
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRMAN)/man3
|
||||
$(INSTALL) -m 644 man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
|
||||
ifeq ($(OS), Linux)
|
||||
gzip -f $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
|
||||
endif
|
||||
endif
|
||||
|
||||
install-static: updateversion $(FILESTOINSTALL)
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC)
|
||||
$(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC)
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB)
|
||||
$(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB)
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN)
|
||||
$(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
|
||||
|
||||
cleaninstall:
|
||||
$(RM) -r $(DESTDIR)$(INSTALLDIRINC)
|
||||
$(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(LIBRARY)
|
||||
$(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY)
|
||||
|
||||
depend:
|
||||
makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null
|
||||
|
||||
$(LIBRARY): $(LIBOBJS)
|
||||
ifeq ($(OS), Darwin)
|
||||
$(LIBTOOL) -static -o $@ $?
|
||||
else
|
||||
$(AR) crs $@ $?
|
||||
endif
|
||||
|
||||
$(SHAREDLIBRARY): $(LIBOBJS)
|
||||
ifeq ($(OS), Darwin)
|
||||
# $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(SONAME) -o $@ $^
|
||||
$(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(INSTALLDIRLIB)/$(SONAME) -o $@ $^
|
||||
else
|
||||
$(CC) -shared $(LDFLAGS) -Wl,-soname,$(SONAME) -o $@ $^
|
||||
endif
|
||||
|
||||
upnpc-static: $(LIBRARY)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS)
|
||||
|
||||
upnpc-shared: $(SHAREDLIBRARY)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS)
|
||||
|
||||
minixmlvalid: minixml.o minixmlvalid.o
|
||||
|
||||
miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION
|
||||
$(SH) updateminiupnpcstrings.sh
|
||||
|
||||
# DO NOT DELETE THIS LINE -- make depend depends on it.
|
||||
|
||||
igd_desc_parse.o: igd_desc_parse.h
|
||||
miniupnpc.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h upnpdev.h
|
||||
miniupnpc.o: minissdpc.h miniwget.h minisoap.h minixml.h upnpcommands.h
|
||||
miniupnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h
|
||||
miniupnpc.o: connecthostport.h
|
||||
minixml.o: minixml.h
|
||||
minisoap.o: minisoap.h miniupnpcstrings.h
|
||||
miniwget.o: miniupnpcstrings.h miniwget.h miniupnpc_declspec.h
|
||||
miniwget.o: connecthostport.h receivedata.h
|
||||
upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h
|
||||
upnpcommands.o: miniupnpc_declspec.h miniupnpctypes.h miniupnpc.h
|
||||
upnpcommands.o: igd_desc_parse.h upnpdev.h
|
||||
upnpreplyparse.o: upnpreplyparse.h minixml.h
|
||||
minixmlvalid.o: minixml.h
|
||||
minissdpc.o: minissdpc.h miniupnpc_declspec.h upnpdev.h miniupnpc.h
|
||||
minissdpc.o: igd_desc_parse.h receivedata.h codelength.h
|
||||
upnperrors.o: upnperrors.h miniupnpc_declspec.h upnpcommands.h
|
||||
upnperrors.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h
|
||||
upnperrors.o: miniupnpc.h igd_desc_parse.h upnpdev.h
|
||||
connecthostport.o: connecthostport.h
|
||||
portlistingparse.o: portlistingparse.h miniupnpc_declspec.h miniupnpctypes.h
|
||||
portlistingparse.o: minixml.h
|
||||
receivedata.o: receivedata.h
|
||||
upnpdev.o: upnpdev.h miniupnpc_declspec.h
|
||||
testportlistingparse.o: miniupnpctypes.h
|
||||
miniupnpcmodule.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h
|
||||
miniupnpcmodule.o: upnpdev.h upnpcommands.h upnpreplyparse.h
|
||||
miniupnpcmodule.o: portlistingparse.h miniupnpctypes.h upnperrors.h
|
||||
@@ -0,0 +1,64 @@
|
||||
Project: miniupnp
|
||||
Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
github: https://github.com/miniupnp/miniupnp
|
||||
freecode: http://freecode.com/projects/miniupnp
|
||||
Author: Thomas Bernard
|
||||
Copyright (c) 2005-2016 Thomas Bernard
|
||||
This software is subject to the conditions detailed in the
|
||||
LICENSE file provided within this distribution.
|
||||
|
||||
|
||||
* miniUPnP Client - miniUPnPc *
|
||||
|
||||
To compile, simply run 'gmake' (could be 'make' on your system).
|
||||
Under win32, to compile with MinGW, type "mingw32make.bat".
|
||||
MS Visual C solution and project files are supplied in the msvc/ subdirectory.
|
||||
|
||||
The compilation is known to work under linux, FreeBSD,
|
||||
OpenBSD, MacOS X, AmigaOS and cygwin.
|
||||
The official AmigaOS4.1 SDK was used for AmigaOS4 and GeekGadgets for AmigaOS3.
|
||||
upx (http://upx.sourceforge.net) is used to compress the win32 .exe files.
|
||||
|
||||
To install the library and headers on the system use :
|
||||
> su
|
||||
> make install
|
||||
> exit
|
||||
|
||||
alternatively, to install into a specific location, use :
|
||||
> INSTALLPREFIX=/usr/local make install
|
||||
|
||||
upnpc.c is a sample client using the libminiupnpc.
|
||||
To use the libminiupnpc in your application, link it with
|
||||
libminiupnpc.a (or .so) and use the following functions found in miniupnpc.h,
|
||||
upnpcommands.h and miniwget.h :
|
||||
- upnpDiscover()
|
||||
- UPNP_GetValidIGD()
|
||||
- miniwget()
|
||||
- parserootdesc()
|
||||
- GetUPNPUrls()
|
||||
- UPNP_* (calling UPNP methods)
|
||||
|
||||
Note : use #include <miniupnpc/miniupnpc.h> etc... for the includes
|
||||
and -lminiupnpc for the link
|
||||
|
||||
Discovery process is speeded up when MiniSSDPd is running on the machine.
|
||||
|
||||
|
||||
* Python module *
|
||||
|
||||
you can build a python module with 'make pythonmodule'
|
||||
and install it with 'make installpythonmodule'.
|
||||
setup.py (and setupmingw32.py) are included in the distribution.
|
||||
|
||||
|
||||
Feel free to contact me if you have any problem :
|
||||
e-mail : [email protected]
|
||||
|
||||
If you are using libminiupnpc in your application, please
|
||||
send me an email !
|
||||
|
||||
For any question, you can use the web forum :
|
||||
http://miniupnp.tuxfamily.org/forum/
|
||||
|
||||
Bugs should be reported on github :
|
||||
https://github.com/miniupnp/miniupnp/issues
|
||||
@@ -0,0 +1 @@
|
||||
2.0
|
||||
@@ -0,0 +1,172 @@
|
||||
$Id: apiversions.txt,v 1.9 2016/01/24 17:24:36 nanard Exp $
|
||||
|
||||
Differences in API between miniUPnPc versions
|
||||
|
||||
API version 16
|
||||
added "status_code" argument to getHTTPResponse(), miniwget() and miniwget_getaddr()
|
||||
updated macro :
|
||||
#define MINIUPNPC_API_VERSION 16
|
||||
|
||||
API version 15
|
||||
changed "sameport" argument of upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice()
|
||||
to "localport". When 0 or 1, behaviour is not changed, but it can take
|
||||
any other value between 2 and 65535
|
||||
Existing programs should be compatible
|
||||
updated macro :
|
||||
#define MINIUPNPC_API_VERSION 15
|
||||
|
||||
API version 14
|
||||
miniupnpc.h
|
||||
add ttl argument to upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice()
|
||||
upnpDiscoverDevices()
|
||||
getDevicesFromMiniSSDPD() :
|
||||
connectToMiniSSDPD() / disconnectFromMiniSSDPD()
|
||||
requestDevicesFromMiniSSDPD() / receiveDevicesFromMiniSSDPD()
|
||||
updated macro :
|
||||
#define MINIUPNPC_API_VERSION 14
|
||||
|
||||
API version 13
|
||||
miniupnpc.h:
|
||||
add searchalltype param to upnpDiscoverDevices() function
|
||||
updated macro :
|
||||
#define MINIUPNPC_API_VERSION 13
|
||||
|
||||
API version 12
|
||||
miniupnpc.h :
|
||||
add upnpDiscoverAll() / upnpDiscoverDevice() / upnpDiscoverDevices()
|
||||
functions
|
||||
updated macros :
|
||||
#define MINIUPNPC_API_VERSION 12
|
||||
|
||||
API version 11
|
||||
|
||||
upnpreplyparse.h / portlistingparse.h :
|
||||
removed usage of sys/queue.h / bsdqueue.h
|
||||
|
||||
miniupnpc.h:
|
||||
updated macros :
|
||||
#define MINIUPNPC_API_VERSION 11
|
||||
|
||||
====================== miniUPnPc version 1.9 ======================
|
||||
API version 10
|
||||
|
||||
upnpcommands.h:
|
||||
added argument remoteHost to UPNP_GetSpecificPortMappingEntry()
|
||||
|
||||
miniupnpc.h:
|
||||
updated macros :
|
||||
#define MINIUPNPC_VERSION "1.9"
|
||||
#define MINIUPNPC_API_VERSION 10
|
||||
|
||||
====================== miniUPnPc version 1.8 ======================
|
||||
API version 9
|
||||
|
||||
miniupnpc.h:
|
||||
updated macros :
|
||||
#define MINIUPNPC_VERSION "1.8"
|
||||
#define MINIUPNPC_API_VERSION 9
|
||||
added "unsigned int scope_id;" to struct UPNPDev
|
||||
added scope_id argument to GetUPNPUrls()
|
||||
|
||||
|
||||
|
||||
====================== miniUPnPc version 1.7 ======================
|
||||
API version 8
|
||||
|
||||
miniupnpc.h :
|
||||
add new macros :
|
||||
#define MINIUPNPC_VERSION "1.7"
|
||||
#define MINIUPNPC_API_VERSION 8
|
||||
add rootdescURL to struct UPNPUrls
|
||||
|
||||
|
||||
|
||||
====================== miniUPnPc version 1.6 ======================
|
||||
API version 8
|
||||
|
||||
Adding support for IPv6.
|
||||
igd_desc_parse.h :
|
||||
struct IGDdatas_service :
|
||||
add char presentationurl[MINIUPNPC_URL_MAXSIZE];
|
||||
struct IGDdatas :
|
||||
add struct IGDdatas_service IPv6FC;
|
||||
miniupnpc.h :
|
||||
new macros :
|
||||
#define UPNPDISCOVER_SUCCESS (0)
|
||||
#define UPNPDISCOVER_UNKNOWN_ERROR (-1)
|
||||
#define UPNPDISCOVER_SOCKET_ERROR (-101)
|
||||
#define UPNPDISCOVER_MEMORY_ERROR (-102)
|
||||
simpleUPnPcommand() prototype changed (but is normaly not used by API users)
|
||||
add arguments ipv6 and error to upnpDiscover() :
|
||||
struct UPNPDev *
|
||||
upnpDiscover(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int sameport,
|
||||
int ipv6,
|
||||
int * error);
|
||||
add controlURL_6FC member to struct UPNPUrls :
|
||||
struct UPNPUrls {
|
||||
char * controlURL;
|
||||
char * ipcondescURL;
|
||||
char * controlURL_CIF;
|
||||
char * controlURL_6FC;
|
||||
};
|
||||
|
||||
upnpcommands.h :
|
||||
add leaseDuration argument to UPNP_AddPortMapping()
|
||||
add desc, enabled and leaseDuration arguments to UPNP_GetSpecificPortMappingEntry()
|
||||
add UPNP_GetListOfPortMappings() function (IGDv2)
|
||||
add IGDv2 IPv6 related functions :
|
||||
UPNP_GetFirewallStatus()
|
||||
UPNP_GetOutboundPinholeTimeout()
|
||||
UPNP_AddPinhole()
|
||||
UPNP_UpdatePinhole()
|
||||
UPNP_DeletePinhole()
|
||||
UPNP_CheckPinholeWorking()
|
||||
UPNP_GetPinholePackets()
|
||||
|
||||
|
||||
|
||||
====================== miniUPnPc version 1.5 ======================
|
||||
API version 5
|
||||
|
||||
new function :
|
||||
int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
|
||||
new macro in upnpcommands.h :
|
||||
#define UPNPCOMMAND_HTTP_ERROR
|
||||
|
||||
====================== miniUPnPc version 1.4 ======================
|
||||
Same API as version 1.3
|
||||
|
||||
====================== miniUPnPc version 1.3 ======================
|
||||
API version 4
|
||||
|
||||
Use UNSIGNED_INTEGER type for
|
||||
UPNP_GetTotalBytesSent(), UPNP_GetTotalBytesReceived(),
|
||||
UPNP_GetTotalPacketsSent(), UPNP_GetTotalPacketsReceived()
|
||||
Add remoteHost argument to UPNP_AddPortMapping() and UPNP_DeletePortMapping()
|
||||
|
||||
====================== miniUPnPc version 1.2 ======================
|
||||
API version 3
|
||||
|
||||
added sameport argument to upnpDiscover()
|
||||
struct UPNPDev *
|
||||
upnpDiscover(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int sameport);
|
||||
|
||||
====================== miniUPnPc Version 1.1 ======================
|
||||
Same API as 1.0
|
||||
|
||||
|
||||
====================== miniUPnPc Version 1.0 ======================
|
||||
API version 2
|
||||
|
||||
|
||||
struct UPNPDev {
|
||||
struct UPNPDev * pNext;
|
||||
char * descURL;
|
||||
char * st;
|
||||
char buffer[2];
|
||||
};
|
||||
struct UPNPDev * upnpDiscover(int delay, const char * multicastif,
|
||||
const char * minissdpdsock);
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENCE file. */
|
||||
#ifndef CODELENGTH_H_INCLUDED
|
||||
#define CODELENGTH_H_INCLUDED
|
||||
|
||||
/* Encode length by using 7bit per Byte :
|
||||
* Most significant bit of each byte specifies that the
|
||||
* following byte is part of the code */
|
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char *
|
||||
*/
|
||||
#define DECODELENGTH(n, p) n = 0; \
|
||||
do { n = (n << 7) | (*p & 0x7f); } \
|
||||
while((*(p++)&0x80) && (n<(1<<25)));
|
||||
|
||||
/* n : unsigned
|
||||
* READ : function/macro to read one byte (unsigned char)
|
||||
*/
|
||||
#define DECODELENGTH_READ(n, READ) \
|
||||
n = 0; \
|
||||
do { \
|
||||
unsigned char c; \
|
||||
READ(c); \
|
||||
n = (n << 7) | (c & 0x07f); \
|
||||
if(!(c&0x80)) break; \
|
||||
} while(n<(1<<25));
|
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char *
|
||||
* p_limit : unsigned char *
|
||||
*/
|
||||
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
|
||||
n = 0; \
|
||||
do { \
|
||||
if((p) >= (p_limit)) break; \
|
||||
n = (n << 7) | (*(p) & 0x7f); \
|
||||
} while((*((p)++)&0x80) && (n<(1<<25)));
|
||||
|
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char *
|
||||
*/
|
||||
#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
|
||||
if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
|
||||
if(n>=16384) *(p++) = (n >> 14) | 0x80; \
|
||||
if(n>=128) *(p++) = (n >> 7) | 0x80; \
|
||||
*(p++) = n & 0x7f;
|
||||
|
||||
#endif /* CODELENGTH_H_INCLUDED */
|
||||
@@ -0,0 +1,264 @@
|
||||
/* $Id: connecthostport.c,v 1.15 2015/10/09 16:26:19 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2010-2016 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
/* use getaddrinfo() or gethostbyname()
|
||||
* uncomment the following line in order to use gethostbyname() */
|
||||
#ifdef NO_GETADDRINFO
|
||||
#define USE_GETHOSTBYNAME
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#define snprintf _snprintf
|
||||
#define herror
|
||||
#define socklen_t int
|
||||
#else /* #ifdef _WIN32 */
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
#include <sys/time.h>
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
#include <sys/param.h>
|
||||
#include <sys/select.h>
|
||||
#include <errno.h>
|
||||
#define closesocket close
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
|
||||
* during the connect() call */
|
||||
#define MINIUPNPC_IGNORE_EINTR
|
||||
#ifndef USE_GETHOSTBYNAME
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#endif /* #ifndef USE_GETHOSTBYNAME */
|
||||
#endif /* #else _WIN32 */
|
||||
|
||||
/* definition of PRINT_SOCKET_ERROR */
|
||||
#ifdef _WIN32
|
||||
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
|
||||
#else
|
||||
#define PRINT_SOCKET_ERROR(x) perror(x)
|
||||
#endif
|
||||
|
||||
#if defined(__amigaos__) || defined(__amigaos4__)
|
||||
#define herror(A) printf("%s\n", A)
|
||||
#endif
|
||||
|
||||
#include "connecthostport.h"
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
/* connecthostport()
|
||||
* return a socket connected (TCP) to the host and port
|
||||
* or -1 in case of error */
|
||||
int connecthostport(const char * host, unsigned short port,
|
||||
unsigned int scope_id)
|
||||
{
|
||||
int s, n;
|
||||
#ifdef USE_GETHOSTBYNAME
|
||||
struct sockaddr_in dest;
|
||||
struct hostent *hp;
|
||||
#else /* #ifdef USE_GETHOSTBYNAME */
|
||||
char tmp_host[MAXHOSTNAMELEN+1];
|
||||
char port_str[8];
|
||||
struct addrinfo *ai, *p;
|
||||
struct addrinfo hints;
|
||||
#endif /* #ifdef USE_GETHOSTBYNAME */
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
struct timeval timeout;
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
|
||||
#ifdef USE_GETHOSTBYNAME
|
||||
hp = gethostbyname(host);
|
||||
if(hp == NULL)
|
||||
{
|
||||
herror(host);
|
||||
return -1;
|
||||
}
|
||||
memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr));
|
||||
memset(dest.sin_zero, 0, sizeof(dest.sin_zero));
|
||||
s = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if(s < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("socket");
|
||||
return -1;
|
||||
}
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
/* setting a 3 seconds timeout for the connect() call */
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt SO_RCVTIMEO");
|
||||
}
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt SO_SNDTIMEO");
|
||||
}
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_port = htons(port);
|
||||
n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
|
||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||
/* EINTR The system call was interrupted by a signal that was caught
|
||||
* EINPROGRESS The socket is nonblocking and the connection cannot
|
||||
* be completed immediately. */
|
||||
while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
|
||||
{
|
||||
socklen_t len;
|
||||
fd_set wset;
|
||||
int err;
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(s, &wset);
|
||||
if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
|
||||
continue;
|
||||
/*len = 0;*/
|
||||
/*n = getpeername(s, NULL, &len);*/
|
||||
len = sizeof(err);
|
||||
if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
|
||||
PRINT_SOCKET_ERROR("getsockopt");
|
||||
closesocket(s);
|
||||
return -1;
|
||||
}
|
||||
if(err != 0) {
|
||||
errno = err;
|
||||
n = -1;
|
||||
}
|
||||
}
|
||||
#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
|
||||
if(n<0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("connect");
|
||||
closesocket(s);
|
||||
return -1;
|
||||
}
|
||||
#else /* #ifdef USE_GETHOSTBYNAME */
|
||||
/* use getaddrinfo() instead of gethostbyname() */
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
/* hints.ai_flags = AI_ADDRCONFIG; */
|
||||
#ifdef AI_NUMERICSERV
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
#endif
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
|
||||
/* hints.ai_protocol = IPPROTO_TCP; */
|
||||
snprintf(port_str, sizeof(port_str), "%hu", port);
|
||||
if(host[0] == '[')
|
||||
{
|
||||
/* literal ip v6 address */
|
||||
int i, j;
|
||||
for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++)
|
||||
{
|
||||
tmp_host[i] = host[j];
|
||||
if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */
|
||||
j+=2; /* skip "25" */
|
||||
}
|
||||
tmp_host[i] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(tmp_host, host, MAXHOSTNAMELEN);
|
||||
}
|
||||
tmp_host[MAXHOSTNAMELEN] = '\0';
|
||||
n = getaddrinfo(tmp_host, port_str, &hints, &ai);
|
||||
if(n != 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
fprintf(stderr, "getaddrinfo() error : %d\n", n);
|
||||
#else
|
||||
fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
s = -1;
|
||||
for(p = ai; p; p = p->ai_next)
|
||||
{
|
||||
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||
if(s < 0)
|
||||
continue;
|
||||
if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) {
|
||||
struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr;
|
||||
addr6->sin6_scope_id = scope_id;
|
||||
}
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
/* setting a 3 seconds timeout for the connect() call */
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt");
|
||||
}
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt");
|
||||
}
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
n = connect(s, p->ai_addr, p->ai_addrlen);
|
||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||
/* EINTR The system call was interrupted by a signal that was caught
|
||||
* EINPROGRESS The socket is nonblocking and the connection cannot
|
||||
* be completed immediately. */
|
||||
while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
|
||||
{
|
||||
socklen_t len;
|
||||
fd_set wset;
|
||||
int err;
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(s, &wset);
|
||||
if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
|
||||
continue;
|
||||
/*len = 0;*/
|
||||
/*n = getpeername(s, NULL, &len);*/
|
||||
len = sizeof(err);
|
||||
if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
|
||||
PRINT_SOCKET_ERROR("getsockopt");
|
||||
closesocket(s);
|
||||
freeaddrinfo(ai);
|
||||
return -1;
|
||||
}
|
||||
if(err != 0) {
|
||||
errno = err;
|
||||
n = -1;
|
||||
}
|
||||
}
|
||||
#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
|
||||
if(n < 0)
|
||||
{
|
||||
closesocket(s);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
if(s < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("socket");
|
||||
return -1;
|
||||
}
|
||||
if(n < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("connect");
|
||||
return -1;
|
||||
}
|
||||
#endif /* #ifdef USE_GETHOSTBYNAME */
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/* $Id: connecthostport.h,v 1.2 2012/06/23 22:32:33 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2010-2012 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef CONNECTHOSTPORT_H_INCLUDED
|
||||
#define CONNECTHOSTPORT_H_INCLUDED
|
||||
|
||||
/* connecthostport()
|
||||
* return a socket connected (TCP) to the host and port
|
||||
* or -1 in case of error */
|
||||
int connecthostport(const char * host, unsigned short port,
|
||||
unsigned int scope_id);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include "igd_desc_parse.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Start element handler :
|
||||
* update nesting level counter and copy element name */
|
||||
void IGDstartelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
if(l >= MINIUPNPC_URL_MAXSIZE)
|
||||
l = MINIUPNPC_URL_MAXSIZE-1;
|
||||
memcpy(datas->cureltname, name, l);
|
||||
datas->cureltname[l] = '\0';
|
||||
datas->level++;
|
||||
if( (l==7) && !memcmp(name, "service", l) ) {
|
||||
datas->tmp.controlurl[0] = '\0';
|
||||
datas->tmp.eventsuburl[0] = '\0';
|
||||
datas->tmp.scpdurl[0] = '\0';
|
||||
datas->tmp.servicetype[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
|
||||
|
||||
/* End element handler :
|
||||
* update nesting level counter and update parser state if
|
||||
* service element is parsed */
|
||||
void IGDendelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
datas->level--;
|
||||
/*printf("endelt %2d %.*s\n", datas->level, l, name);*/
|
||||
if( (l==7) && !memcmp(name, "service", l) )
|
||||
{
|
||||
if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) {
|
||||
memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) {
|
||||
memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:")
|
||||
|| COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:") ) {
|
||||
if(datas->first.servicetype[0] == '\0') {
|
||||
memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else {
|
||||
memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Data handler :
|
||||
* copy data depending on the current element name and state */
|
||||
void IGDdata(void * d, const char * data, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
char * dstmember = 0;
|
||||
/*printf("%2d %s : %.*s\n",
|
||||
datas->level, datas->cureltname, l, data); */
|
||||
if( !strcmp(datas->cureltname, "URLBase") )
|
||||
dstmember = datas->urlbase;
|
||||
else if( !strcmp(datas->cureltname, "presentationURL") )
|
||||
dstmember = datas->presentationurl;
|
||||
else if( !strcmp(datas->cureltname, "serviceType") )
|
||||
dstmember = datas->tmp.servicetype;
|
||||
else if( !strcmp(datas->cureltname, "controlURL") )
|
||||
dstmember = datas->tmp.controlurl;
|
||||
else if( !strcmp(datas->cureltname, "eventSubURL") )
|
||||
dstmember = datas->tmp.eventsuburl;
|
||||
else if( !strcmp(datas->cureltname, "SCPDURL") )
|
||||
dstmember = datas->tmp.scpdurl;
|
||||
/* else if( !strcmp(datas->cureltname, "deviceType") )
|
||||
dstmember = datas->devicetype_tmp;*/
|
||||
if(dstmember)
|
||||
{
|
||||
if(l>=MINIUPNPC_URL_MAXSIZE)
|
||||
l = MINIUPNPC_URL_MAXSIZE-1;
|
||||
memcpy(dstmember, data, l);
|
||||
dstmember[l] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void printIGD(struct IGDdatas * d)
|
||||
{
|
||||
printf("urlbase = '%s'\n", d->urlbase);
|
||||
printf("WAN Device (Common interface config) :\n");
|
||||
/*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/
|
||||
printf(" serviceType = '%s'\n", d->CIF.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->CIF.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->CIF.scpdurl);
|
||||
printf("primary WAN Connection Device (IP or PPP Connection):\n");
|
||||
/*printf(" deviceType = '%s'\n", d->first.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->first.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->first.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->first.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->first.scpdurl);
|
||||
printf("secondary WAN Connection Device (IP or PPP Connection):\n");
|
||||
/*printf(" deviceType = '%s'\n", d->second.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->second.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->second.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->second.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->second.scpdurl);
|
||||
printf("WAN IPv6 Firewall Control :\n");
|
||||
/*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->IPv6FC.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->IPv6FC.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef IGD_DESC_PARSE_H_INCLUDED
|
||||
#define IGD_DESC_PARSE_H_INCLUDED
|
||||
|
||||
/* Structure to store the result of the parsing of UPnP
|
||||
* descriptions of Internet Gateway Devices */
|
||||
#define MINIUPNPC_URL_MAXSIZE (128)
|
||||
struct IGDdatas_service {
|
||||
char controlurl[MINIUPNPC_URL_MAXSIZE];
|
||||
char eventsuburl[MINIUPNPC_URL_MAXSIZE];
|
||||
char scpdurl[MINIUPNPC_URL_MAXSIZE];
|
||||
char servicetype[MINIUPNPC_URL_MAXSIZE];
|
||||
/*char devicetype[MINIUPNPC_URL_MAXSIZE];*/
|
||||
};
|
||||
|
||||
struct IGDdatas {
|
||||
char cureltname[MINIUPNPC_URL_MAXSIZE];
|
||||
char urlbase[MINIUPNPC_URL_MAXSIZE];
|
||||
char presentationurl[MINIUPNPC_URL_MAXSIZE];
|
||||
int level;
|
||||
/*int state;*/
|
||||
/* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
|
||||
struct IGDdatas_service CIF;
|
||||
/* "urn:schemas-upnp-org:service:WANIPConnection:1"
|
||||
* "urn:schemas-upnp-org:service:WANPPPConnection:1" */
|
||||
struct IGDdatas_service first;
|
||||
/* if both WANIPConnection and WANPPPConnection are present */
|
||||
struct IGDdatas_service second;
|
||||
/* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */
|
||||
struct IGDdatas_service IPv6FC;
|
||||
/* tmp */
|
||||
struct IGDdatas_service tmp;
|
||||
};
|
||||
|
||||
void IGDstartelt(void *, const char *, int);
|
||||
void IGDendelt(void *, const char *, int);
|
||||
void IGDdata(void *, const char *, int);
|
||||
#ifdef DEBUG
|
||||
void printIGD(struct IGDdatas *);
|
||||
#endif /* DEBUG */
|
||||
|
||||
#endif /* IGD_DESC_PARSE_H_INCLUDED */
|
||||
@@ -0,0 +1,123 @@
|
||||
/* $Id: minisoap.c,v 1.23 2014/11/04 22:31:55 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
*
|
||||
* Minimal SOAP implementation for UPnP protocol.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <winsock2.h>
|
||||
#define snprintf _snprintf
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include "minisoap.h"
|
||||
#include "miniupnpcstrings.h"
|
||||
|
||||
/* only for malloc */
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
|
||||
#else
|
||||
#define PRINT_SOCKET_ERROR(x) perror(x)
|
||||
#endif
|
||||
|
||||
/* httpWrite sends the headers and the body to the socket
|
||||
* and returns the number of bytes sent */
|
||||
static int
|
||||
httpWrite(int fd, const char * body, int bodysize,
|
||||
const char * headers, int headerssize)
|
||||
{
|
||||
int n = 0;
|
||||
/*n = write(fd, headers, headerssize);*/
|
||||
/*if(bodysize>0)
|
||||
n += write(fd, body, bodysize);*/
|
||||
/* Note : my old linksys router only took into account
|
||||
* soap request that are sent into only one packet */
|
||||
char * p;
|
||||
/* TODO: AVOID MALLOC, we could use writev() for that */
|
||||
p = (char*)malloc(headerssize+bodysize);
|
||||
if(!p)
|
||||
return -1;
|
||||
memcpy(p, headers, headerssize);
|
||||
memcpy(p+headerssize, body, bodysize);
|
||||
/*n = write(fd, p, headerssize+bodysize);*/
|
||||
n = (int)send(fd, p, headerssize+bodysize, 0);
|
||||
if(n<0) {
|
||||
PRINT_SOCKET_ERROR("send");
|
||||
}
|
||||
/* disable send on the socket */
|
||||
/* draytek routers dont seems to like that... */
|
||||
#if 0
|
||||
#ifdef _WIN32
|
||||
if(shutdown(fd, SD_SEND)<0) {
|
||||
#else
|
||||
if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/
|
||||
#endif
|
||||
PRINT_SOCKET_ERROR("shutdown");
|
||||
}
|
||||
#endif
|
||||
free(p);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* self explanatory */
|
||||
int soapPostSubmit(int fd,
|
||||
const char * url,
|
||||
const char * host,
|
||||
unsigned short port,
|
||||
const char * action,
|
||||
const char * body,
|
||||
const char * httpversion)
|
||||
{
|
||||
int bodysize;
|
||||
char headerbuf[512];
|
||||
int headerssize;
|
||||
char portstr[8];
|
||||
bodysize = (int)strlen(body);
|
||||
/* We are not using keep-alive HTTP connections.
|
||||
* HTTP/1.1 needs the header Connection: close to do that.
|
||||
* This is the default with HTTP/1.0
|
||||
* Using HTTP/1.1 means we need to support chunked transfer-encoding :
|
||||
* When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked
|
||||
* transfer encoding. */
|
||||
/* Connection: Close is normally there only in HTTP/1.1 but who knows */
|
||||
portstr[0] = '\0';
|
||||
if(port != 80)
|
||||
snprintf(portstr, sizeof(portstr), ":%hu", port);
|
||||
headerssize = snprintf(headerbuf, sizeof(headerbuf),
|
||||
"POST %s HTTP/%s\r\n"
|
||||
"Host: %s%s\r\n"
|
||||
"User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"Content-Type: text/xml\r\n"
|
||||
"SOAPAction: \"%s\"\r\n"
|
||||
"Connection: Close\r\n"
|
||||
"Cache-Control: no-cache\r\n" /* ??? */
|
||||
"Pragma: no-cache\r\n"
|
||||
"\r\n",
|
||||
url, httpversion, host, portstr, bodysize, action);
|
||||
if ((unsigned int)headerssize >= sizeof(headerbuf))
|
||||
return -1;
|
||||
#ifdef DEBUG
|
||||
/*printf("SOAP request : headersize=%d bodysize=%d\n",
|
||||
headerssize, bodysize);
|
||||
*/
|
||||
printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n",
|
||||
url, httpversion, host, portstr);
|
||||
printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize);
|
||||
printf("Headers :\n%s", headerbuf);
|
||||
printf("Body :\n%s\n", body);
|
||||
#endif
|
||||
return httpWrite(fd, body, bodysize, headerbuf, headerssize);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/* $Id: minisoap.h,v 1.4 2010/04/12 20:39:41 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
#ifndef MINISOAP_H_INCLUDED
|
||||
#define MINISOAP_H_INCLUDED
|
||||
|
||||
/*int httpWrite(int, const char *, int, const char *);*/
|
||||
int soapPostSubmit(int, const char *, const char *, unsigned short,
|
||||
const char *, const char *, const char *);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,878 @@
|
||||
/* $Id: minissdpc.c,v 1.32 2016/10/07 09:04:36 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2017 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENCE file. */
|
||||
/*#include <syslog.h>*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#if defined (__NetBSD__)
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <winsock.h>
|
||||
#define snprintf _snprintf
|
||||
#if !defined(_MSC_VER)
|
||||
#include <stdint.h>
|
||||
#else /* !defined(_MSC_VER) */
|
||||
typedef unsigned short uint16_t;
|
||||
#endif /* !defined(_MSC_VER) */
|
||||
#ifndef strncasecmp
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
#define strncasecmp _memicmp
|
||||
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||
#define strncasecmp memicmp
|
||||
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||
#endif /* #ifndef strncasecmp */
|
||||
#endif /* _WIN32 */
|
||||
#if defined(__amigaos__) || defined(__amigaos4__)
|
||||
#include <sys/socket.h>
|
||||
#endif /* defined(__amigaos__) || defined(__amigaos4__) */
|
||||
#if defined(__amigaos__)
|
||||
#define uint16_t unsigned short
|
||||
#endif /* defined(__amigaos__) */
|
||||
/* Hack */
|
||||
#define UNIX_PATH_LEN 108
|
||||
struct sockaddr_un {
|
||||
uint16_t sun_family;
|
||||
char sun_path[UNIX_PATH_LEN];
|
||||
};
|
||||
#else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#define closesocket close
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
|
||||
#else
|
||||
#define PRINT_SOCKET_ERROR(x) perror(x)
|
||||
#endif
|
||||
|
||||
#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__)
|
||||
#define HAS_IP_MREQN
|
||||
#endif
|
||||
|
||||
#if !defined(HAS_IP_MREQN) && !defined(_WIN32)
|
||||
#include <sys/ioctl.h>
|
||||
#if defined(__sun)
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN)
|
||||
/* Several versions of glibc don't define this structure,
|
||||
* define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */
|
||||
struct ip_mreqn
|
||||
{
|
||||
struct in_addr imr_multiaddr; /* IP multicast address of group */
|
||||
struct in_addr imr_address; /* local IP address of interface */
|
||||
int imr_ifindex; /* Interface index */
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(__amigaos__) || defined(__amigaos4__)
|
||||
/* Amiga OS specific stuff */
|
||||
#define TIMEVAL struct timeval
|
||||
#endif
|
||||
|
||||
#include "minissdpc.h"
|
||||
#include "miniupnpc.h"
|
||||
#include "receivedata.h"
|
||||
|
||||
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
|
||||
|
||||
#include "codelength.h"
|
||||
|
||||
struct UPNPDev *
|
||||
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error)
|
||||
{
|
||||
struct UPNPDev * devlist = NULL;
|
||||
int s;
|
||||
int res;
|
||||
|
||||
s = connectToMiniSSDPD(socketpath);
|
||||
if (s < 0) {
|
||||
if (error)
|
||||
*error = s;
|
||||
return NULL;
|
||||
}
|
||||
res = requestDevicesFromMiniSSDPD(s, devtype);
|
||||
if (res < 0) {
|
||||
if (error)
|
||||
*error = res;
|
||||
} else {
|
||||
devlist = receiveDevicesFromMiniSSDPD(s, error);
|
||||
}
|
||||
disconnectFromMiniSSDPD(s);
|
||||
return devlist;
|
||||
}
|
||||
|
||||
/* macros used to read from unix socket */
|
||||
#define READ_BYTE_BUFFER(c) \
|
||||
if((int)bufferindex >= n) { \
|
||||
n = read(s, buffer, sizeof(buffer)); \
|
||||
if(n<=0) break; \
|
||||
bufferindex = 0; \
|
||||
} \
|
||||
c = buffer[bufferindex++];
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
#define READ_COPY_BUFFER(dst, len) \
|
||||
for(l = len, p = (unsigned char *)dst; l > 0; ) { \
|
||||
unsigned int lcopy; \
|
||||
if((int)bufferindex >= n) { \
|
||||
n = read(s, buffer, sizeof(buffer)); \
|
||||
if(n<=0) break; \
|
||||
bufferindex = 0; \
|
||||
} \
|
||||
lcopy = MIN(l, (n - bufferindex)); \
|
||||
memcpy(p, buffer + bufferindex, lcopy); \
|
||||
l -= lcopy; \
|
||||
p += lcopy; \
|
||||
bufferindex += lcopy; \
|
||||
}
|
||||
|
||||
#define READ_DISCARD_BUFFER(len) \
|
||||
for(l = len; l > 0; ) { \
|
||||
unsigned int lcopy; \
|
||||
if(bufferindex >= n) { \
|
||||
n = read(s, buffer, sizeof(buffer)); \
|
||||
if(n<=0) break; \
|
||||
bufferindex = 0; \
|
||||
} \
|
||||
lcopy = MIN(l, (n - bufferindex)); \
|
||||
l -= lcopy; \
|
||||
bufferindex += lcopy; \
|
||||
}
|
||||
|
||||
int
|
||||
connectToMiniSSDPD(const char * socketpath)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_un addr;
|
||||
#if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun)
|
||||
struct timeval timeout;
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
|
||||
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if(s < 0)
|
||||
{
|
||||
/*syslog(LOG_ERR, "socket(unix): %m");*/
|
||||
perror("socket(unix)");
|
||||
return MINISSDPC_SOCKET_ERROR;
|
||||
}
|
||||
#if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun)
|
||||
/* setting a 3 seconds timeout */
|
||||
/* not supported for AF_UNIX sockets under Solaris */
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
perror("setsockopt SO_RCVTIMEO unix");
|
||||
}
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
perror("setsockopt SO_SNDTIMEO unix");
|
||||
}
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
if(!socketpath)
|
||||
socketpath = "/var/run/minissdpd.sock";
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
|
||||
/* TODO : check if we need to handle the EINTR */
|
||||
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0)
|
||||
{
|
||||
/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
|
||||
close(s);
|
||||
return MINISSDPC_SOCKET_ERROR;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
disconnectFromMiniSSDPD(int s)
|
||||
{
|
||||
if (close(s) < 0)
|
||||
return MINISSDPC_SOCKET_ERROR;
|
||||
return MINISSDPC_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
requestDevicesFromMiniSSDPD(int s, const char * devtype)
|
||||
{
|
||||
unsigned char buffer[256];
|
||||
unsigned char * p;
|
||||
unsigned int l;
|
||||
unsigned stsize = (unsigned)strlen(devtype);
|
||||
if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8))
|
||||
{
|
||||
buffer[0] = 3; /* request type 3 : everything */
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[0] = 1; /* request type 1 : request devices/services by type */
|
||||
}
|
||||
p = buffer + 1;
|
||||
l = stsize; CODELENGTH(l, p);
|
||||
if(p + stsize > buffer + sizeof(buffer))
|
||||
{
|
||||
/* devtype is too long ! */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n",
|
||||
stsize, (unsigned)sizeof(buffer));
|
||||
#endif /* DEBUG */
|
||||
return MINISSDPC_INVALID_INPUT;
|
||||
}
|
||||
memcpy(p, devtype, stsize);
|
||||
p += stsize;
|
||||
if(write(s, buffer, p - buffer) < 0)
|
||||
{
|
||||
/*syslog(LOG_ERR, "write(): %m");*/
|
||||
perror("minissdpc.c: write()");
|
||||
return MINISSDPC_SOCKET_ERROR;
|
||||
}
|
||||
return MINISSDPC_SUCCESS;
|
||||
}
|
||||
|
||||
struct UPNPDev *
|
||||
receiveDevicesFromMiniSSDPD(int s, int * error)
|
||||
{
|
||||
struct UPNPDev * tmp;
|
||||
struct UPNPDev * devlist = NULL;
|
||||
unsigned char buffer[256];
|
||||
ssize_t n;
|
||||
unsigned char * p;
|
||||
unsigned char * url;
|
||||
unsigned char * st;
|
||||
unsigned int bufferindex;
|
||||
unsigned int i, ndev;
|
||||
unsigned int urlsize, stsize, usnsize, l;
|
||||
|
||||
n = read(s, buffer, sizeof(buffer));
|
||||
if(n<=0)
|
||||
{
|
||||
perror("minissdpc.c: read()");
|
||||
if (error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
ndev = buffer[0];
|
||||
bufferindex = 1;
|
||||
for(i = 0; i < ndev; i++)
|
||||
{
|
||||
DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER);
|
||||
if(n<=0) {
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
return devlist;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf(" urlsize=%u", urlsize);
|
||||
#endif /* DEBUG */
|
||||
url = (unsigned char*)malloc(urlsize);
|
||||
if(url == NULL)
|
||||
{
|
||||
if (error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
return devlist;
|
||||
}
|
||||
READ_COPY_BUFFER(url, urlsize);
|
||||
if(n<=0)
|
||||
{
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
goto free_url_and_return;
|
||||
}
|
||||
DECODELENGTH_READ(stsize, READ_BYTE_BUFFER);
|
||||
if(n<=0)
|
||||
{
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
goto free_url_and_return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf(" stsize=%u", stsize);
|
||||
#endif /* DEBUG */
|
||||
st = (unsigned char*)malloc(stsize);
|
||||
if (st == NULL) {
|
||||
if (error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
goto free_url_and_return;
|
||||
}
|
||||
READ_COPY_BUFFER(st, stsize);
|
||||
if(n<=0) {
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
goto free_url_and_st_and_return;
|
||||
}
|
||||
DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER);
|
||||
if(n<=0) {
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
goto free_url_and_st_and_return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf(" usnsize=%u\n", usnsize);
|
||||
#endif /* DEBUG */
|
||||
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
|
||||
if(tmp == NULL) {
|
||||
if (error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
goto free_url_and_st_and_return;
|
||||
}
|
||||
tmp->pNext = devlist;
|
||||
tmp->descURL = tmp->buffer;
|
||||
tmp->st = tmp->buffer + 1 + urlsize;
|
||||
memcpy(tmp->buffer, url, urlsize);
|
||||
tmp->buffer[urlsize] = '\0';
|
||||
memcpy(tmp->st, st, stsize);
|
||||
tmp->buffer[urlsize+1+stsize] = '\0';
|
||||
free(url);
|
||||
free(st);
|
||||
url = NULL;
|
||||
st = NULL;
|
||||
tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize;
|
||||
READ_COPY_BUFFER(tmp->usn, usnsize);
|
||||
if(n<=0) {
|
||||
if (error)
|
||||
*error = MINISSDPC_INVALID_SERVER_REPLY;
|
||||
goto free_tmp_and_return;
|
||||
}
|
||||
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
|
||||
tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */
|
||||
devlist = tmp;
|
||||
}
|
||||
if (error)
|
||||
*error = MINISSDPC_SUCCESS;
|
||||
return devlist;
|
||||
|
||||
free_url_and_st_and_return:
|
||||
free(st);
|
||||
free_url_and_return:
|
||||
free(url);
|
||||
return devlist;
|
||||
|
||||
free_tmp_and_return:
|
||||
free(tmp);
|
||||
return devlist;
|
||||
}
|
||||
|
||||
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
|
||||
|
||||
/* parseMSEARCHReply()
|
||||
* the last 4 arguments are filled during the parsing :
|
||||
* - location/locationsize : "location:" field of the SSDP reply packet
|
||||
* - st/stsize : "st:" field of the SSDP reply packet.
|
||||
* The strings are NOT null terminated */
|
||||
static void
|
||||
parseMSEARCHReply(const char * reply, int size,
|
||||
const char * * location, int * locationsize,
|
||||
const char * * st, int * stsize,
|
||||
const char * * usn, int * usnsize)
|
||||
{
|
||||
int a, b, i;
|
||||
i = 0;
|
||||
a = i; /* start of the line */
|
||||
b = 0; /* end of the "header" (position of the colon) */
|
||||
while(i<size)
|
||||
{
|
||||
switch(reply[i])
|
||||
{
|
||||
case ':':
|
||||
if(b==0)
|
||||
{
|
||||
b = i; /* end of the "header" */
|
||||
/*for(j=a; j<b; j++)
|
||||
{
|
||||
putchar(reply[j]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case '\x0a':
|
||||
case '\x0d':
|
||||
if(b!=0)
|
||||
{
|
||||
/*for(j=b+1; j<i; j++)
|
||||
{
|
||||
putchar(reply[j]);
|
||||
}
|
||||
putchar('\n');*/
|
||||
/* skip the colon and white spaces */
|
||||
do { b++; } while(reply[b]==' ');
|
||||
if(0==strncasecmp(reply+a, "location", 8))
|
||||
{
|
||||
*location = reply+b;
|
||||
*locationsize = i-b;
|
||||
}
|
||||
else if(0==strncasecmp(reply+a, "st", 2))
|
||||
{
|
||||
*st = reply+b;
|
||||
*stsize = i-b;
|
||||
}
|
||||
else if(0==strncasecmp(reply+a, "usn", 3))
|
||||
{
|
||||
*usn = reply+b;
|
||||
*usnsize = i-b;
|
||||
}
|
||||
b = 0;
|
||||
}
|
||||
a = i+1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* port upnp discover : SSDP protocol */
|
||||
#define SSDP_PORT 1900
|
||||
#define XSTR(s) MINISSDPC_STR(s)
|
||||
#define MINISSDPC_STR(s) #s
|
||||
#define UPNP_MCAST_ADDR "239.255.255.250"
|
||||
/* for IPv6 */
|
||||
#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
|
||||
#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
|
||||
|
||||
/* direct discovery if minissdpd responses are not sufficient */
|
||||
/* ssdpDiscoverDevices() :
|
||||
* return a chained list of all devices found or NULL if
|
||||
* no devices was found.
|
||||
* It is up to the caller to free the chained list
|
||||
* delay is in millisecond (poll).
|
||||
* UDA v1.1 says :
|
||||
* The TTL for the IP packet SHOULD default to 2 and
|
||||
* SHOULD be configurable. */
|
||||
struct UPNPDev *
|
||||
ssdpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error,
|
||||
int searchalltypes)
|
||||
{
|
||||
struct UPNPDev * tmp;
|
||||
struct UPNPDev * devlist = 0;
|
||||
unsigned int scope_id = 0;
|
||||
int opt = 1;
|
||||
static const char MSearchMsgFmt[] =
|
||||
"M-SEARCH * HTTP/1.1\r\n"
|
||||
"HOST: %s:" XSTR(SSDP_PORT) "\r\n"
|
||||
"ST: %s\r\n"
|
||||
"MAN: \"ssdp:discover\"\r\n"
|
||||
"MX: %u\r\n"
|
||||
"\r\n";
|
||||
int deviceIndex;
|
||||
char bufr[1536]; /* reception and emission buffer */
|
||||
int sudp;
|
||||
int n;
|
||||
struct sockaddr_storage sockudp_r;
|
||||
unsigned int mx;
|
||||
#ifdef NO_GETADDRINFO
|
||||
struct sockaddr_storage sockudp_w;
|
||||
#else
|
||||
int rv;
|
||||
struct addrinfo hints, *servinfo, *p;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
MIB_IPFORWARDROW ip_forward;
|
||||
unsigned long _ttl = (unsigned long)ttl;
|
||||
#endif
|
||||
int linklocal = 1;
|
||||
|
||||
if(error)
|
||||
*error = MINISSDPC_UNKNOWN_ERROR;
|
||||
|
||||
if(localport==UPNP_LOCAL_PORT_SAME)
|
||||
localport = SSDP_PORT;
|
||||
|
||||
#ifdef _WIN32
|
||||
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
#else
|
||||
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
|
||||
#endif
|
||||
if(sudp < 0)
|
||||
{
|
||||
if(error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
PRINT_SOCKET_ERROR("socket");
|
||||
return NULL;
|
||||
}
|
||||
/* reception */
|
||||
memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
|
||||
if(ipv6) {
|
||||
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
|
||||
p->sin6_family = AF_INET6;
|
||||
if(localport > 0 && localport < 65536)
|
||||
p->sin6_port = htons((unsigned short)localport);
|
||||
p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
|
||||
} else {
|
||||
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
|
||||
p->sin_family = AF_INET;
|
||||
if(localport > 0 && localport < 65536)
|
||||
p->sin_port = htons((unsigned short)localport);
|
||||
p->sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
/* This code could help us to use the right Network interface for
|
||||
* SSDP multicast traffic */
|
||||
/* Get IP associated with the index given in the ip_forward struct
|
||||
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
|
||||
if(!ipv6
|
||||
&& (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
|
||||
DWORD dwRetVal = 0;
|
||||
PMIB_IPADDRTABLE pIPAddrTable;
|
||||
DWORD dwSize = 0;
|
||||
#ifdef DEBUG
|
||||
IN_ADDR IPAddr;
|
||||
#endif
|
||||
int i;
|
||||
#ifdef DEBUG
|
||||
printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
|
||||
#endif
|
||||
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
|
||||
if(pIPAddrTable) {
|
||||
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
|
||||
free(pIPAddrTable);
|
||||
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
|
||||
}
|
||||
}
|
||||
if(pIPAddrTable) {
|
||||
dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
|
||||
if (dwRetVal == NO_ERROR) {
|
||||
#ifdef DEBUG
|
||||
printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
|
||||
#endif
|
||||
for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
|
||||
#ifdef DEBUG
|
||||
printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
|
||||
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
|
||||
printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
|
||||
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
|
||||
printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
|
||||
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
|
||||
printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
|
||||
printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
|
||||
printf("\tType and State[%d]:", i);
|
||||
printf("\n");
|
||||
#endif
|
||||
if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
|
||||
/* Set the address of this interface to be used */
|
||||
struct in_addr mc_if;
|
||||
memset(&mc_if, 0, sizeof(mc_if));
|
||||
mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
|
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
|
||||
PRINT_SOCKET_ERROR("setsockopt");
|
||||
}
|
||||
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
|
||||
#ifndef DEBUG
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
free(pIPAddrTable);
|
||||
pIPAddrTable = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef _WIN32
|
||||
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
|
||||
#else
|
||||
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
|
||||
#endif
|
||||
{
|
||||
if(error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0)
|
||||
#else /* _WIN32 */
|
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
|
||||
#endif /* _WIN32 */
|
||||
{
|
||||
/* not a fatal error */
|
||||
PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)");
|
||||
}
|
||||
|
||||
if(multicastif)
|
||||
{
|
||||
if(ipv6) {
|
||||
#if !defined(_WIN32)
|
||||
/* according to MSDN, if_nametoindex() is supported since
|
||||
* MS Windows Vista and MS Windows Server 2008.
|
||||
* http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
|
||||
unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
|
||||
if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt IPV6_MULTICAST_IF");
|
||||
}
|
||||
#else
|
||||
#ifdef DEBUG
|
||||
printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
struct in_addr mc_if;
|
||||
mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
|
||||
if(mc_if.s_addr != INADDR_NONE)
|
||||
{
|
||||
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
|
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
|
||||
}
|
||||
} else {
|
||||
#ifdef HAS_IP_MREQN
|
||||
/* was not an ip address, try with an interface name */
|
||||
struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
|
||||
memset(&reqn, 0, sizeof(struct ip_mreqn));
|
||||
reqn.imr_ifindex = if_nametoindex(multicastif);
|
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
|
||||
}
|
||||
#elif !defined(_WIN32)
|
||||
struct ifreq ifr;
|
||||
int ifrlen = sizeof(ifr);
|
||||
strncpy(ifr.ifr_name, multicastif, IFNAMSIZ);
|
||||
ifr.ifr_name[IFNAMSIZ-1] = '\0';
|
||||
if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)");
|
||||
}
|
||||
mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
|
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
|
||||
}
|
||||
#else /* _WIN32 */
|
||||
#ifdef DEBUG
|
||||
printf("Setting of multicast interface not supported with interface name.\n");
|
||||
#endif
|
||||
#endif /* #ifdef HAS_IP_MREQN / !defined(_WIN32) */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Before sending the packed, we first "bind" in order to be able
|
||||
* to receive the response */
|
||||
if (bind(sudp, (const struct sockaddr *)&sockudp_r,
|
||||
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
|
||||
{
|
||||
if(error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
PRINT_SOCKET_ERROR("bind");
|
||||
closesocket(sudp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(error)
|
||||
*error = MINISSDPC_SUCCESS;
|
||||
/* Calculating maximum response time in seconds */
|
||||
mx = ((unsigned int)delay) / 1000u;
|
||||
if(mx == 0) {
|
||||
mx = 1;
|
||||
delay = 1000;
|
||||
}
|
||||
/* receiving SSDP response packet */
|
||||
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
|
||||
/* sending the SSDP M-SEARCH packet */
|
||||
n = snprintf(bufr, sizeof(bufr),
|
||||
MSearchMsgFmt,
|
||||
ipv6 ?
|
||||
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
|
||||
: UPNP_MCAST_ADDR,
|
||||
deviceTypes[deviceIndex], mx);
|
||||
if ((unsigned int)n >= sizeof(bufr)) {
|
||||
if(error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
goto error;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
/*printf("Sending %s", bufr);*/
|
||||
printf("Sending M-SEARCH request to %s with ST: %s\n",
|
||||
ipv6 ?
|
||||
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
|
||||
: UPNP_MCAST_ADDR,
|
||||
deviceTypes[deviceIndex]);
|
||||
#endif
|
||||
#ifdef NO_GETADDRINFO
|
||||
/* the following code is not using getaddrinfo */
|
||||
/* emission */
|
||||
memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
|
||||
if(ipv6) {
|
||||
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
|
||||
p->sin6_family = AF_INET6;
|
||||
p->sin6_port = htons(SSDP_PORT);
|
||||
inet_pton(AF_INET6,
|
||||
linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
|
||||
&(p->sin6_addr));
|
||||
} else {
|
||||
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
|
||||
p->sin_family = AF_INET;
|
||||
p->sin_port = htons(SSDP_PORT);
|
||||
p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
|
||||
}
|
||||
n = sendto(sudp, bufr, n, 0, &sockudp_w,
|
||||
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
|
||||
if (n < 0) {
|
||||
if(error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
PRINT_SOCKET_ERROR("sendto");
|
||||
break;
|
||||
}
|
||||
#else /* #ifdef NO_GETADDRINFO */
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
/*hints.ai_flags = */
|
||||
if ((rv = getaddrinfo(ipv6
|
||||
? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
|
||||
: UPNP_MCAST_ADDR,
|
||||
XSTR(SSDP_PORT), &hints, &servinfo)) != 0) {
|
||||
if(error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
#ifdef _WIN32
|
||||
fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
|
||||
#else
|
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
for(p = servinfo; p; p = p->ai_next) {
|
||||
n = (int)sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
|
||||
if (n < 0) {
|
||||
#ifdef DEBUG
|
||||
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
|
||||
if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
|
||||
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
|
||||
fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
|
||||
}
|
||||
#endif
|
||||
PRINT_SOCKET_ERROR("sendto");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(servinfo);
|
||||
if(n < 0) {
|
||||
if(error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
break;
|
||||
}
|
||||
#endif /* #ifdef NO_GETADDRINFO */
|
||||
/* Waiting for SSDP REPLY packet to M-SEARCH
|
||||
* if searchalltypes is set, enter the loop only
|
||||
* when the last deviceType is reached */
|
||||
if(!searchalltypes || !deviceTypes[deviceIndex + 1]) do {
|
||||
n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
|
||||
if (n < 0) {
|
||||
/* error */
|
||||
if(error)
|
||||
*error = MINISSDPC_SOCKET_ERROR;
|
||||
goto error;
|
||||
} else if (n == 0) {
|
||||
/* no data or Time Out */
|
||||
#ifdef DEBUG
|
||||
printf("NODATA or TIMEOUT\n");
|
||||
#endif /* DEBUG */
|
||||
if (devlist && !searchalltypes) {
|
||||
/* found some devices, stop now*/
|
||||
if(error)
|
||||
*error = MINISSDPC_SUCCESS;
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
const char * descURL=NULL;
|
||||
int urlsize=0;
|
||||
const char * st=NULL;
|
||||
int stsize=0;
|
||||
const char * usn=NULL;
|
||||
int usnsize=0;
|
||||
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
|
||||
if(st&&descURL) {
|
||||
#ifdef DEBUG
|
||||
printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
|
||||
stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
|
||||
#endif /* DEBUG */
|
||||
for(tmp=devlist; tmp; tmp = tmp->pNext) {
|
||||
if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
|
||||
tmp->descURL[urlsize] == '\0' &&
|
||||
memcmp(tmp->st, st, stsize) == 0 &&
|
||||
tmp->st[stsize] == '\0' &&
|
||||
(usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) &&
|
||||
tmp->usn[usnsize] == '\0')
|
||||
break;
|
||||
}
|
||||
/* at the exit of the loop above, tmp is null if
|
||||
* no duplicate device was found */
|
||||
if(tmp)
|
||||
continue;
|
||||
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
|
||||
if(!tmp) {
|
||||
/* memory allocation error */
|
||||
if(error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
goto error;
|
||||
}
|
||||
tmp->pNext = devlist;
|
||||
tmp->descURL = tmp->buffer;
|
||||
tmp->st = tmp->buffer + 1 + urlsize;
|
||||
tmp->usn = tmp->st + 1 + stsize;
|
||||
memcpy(tmp->buffer, descURL, urlsize);
|
||||
tmp->buffer[urlsize] = '\0';
|
||||
memcpy(tmp->st, st, stsize);
|
||||
tmp->buffer[urlsize+1+stsize] = '\0';
|
||||
if(usn != NULL)
|
||||
memcpy(tmp->usn, usn, usnsize);
|
||||
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
|
||||
tmp->scope_id = scope_id;
|
||||
devlist = tmp;
|
||||
}
|
||||
}
|
||||
} while(n > 0);
|
||||
if(ipv6) {
|
||||
/* switch linklocal flag */
|
||||
if(linklocal) {
|
||||
linklocal = 0;
|
||||
--deviceIndex;
|
||||
} else {
|
||||
linklocal = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
error:
|
||||
closesocket(sudp);
|
||||
return devlist;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/* $Id: minissdpc.h,v 1.6 2015/09/18 12:45:16 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef MINISSDPC_H_INCLUDED
|
||||
#define MINISSDPC_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_declspec.h"
|
||||
#include "upnpdev.h"
|
||||
|
||||
/* error codes : */
|
||||
#define MINISSDPC_SUCCESS (0)
|
||||
#define MINISSDPC_UNKNOWN_ERROR (-1)
|
||||
#define MINISSDPC_SOCKET_ERROR (-101)
|
||||
#define MINISSDPC_MEMORY_ERROR (-102)
|
||||
#define MINISSDPC_INVALID_INPUT (-103)
|
||||
#define MINISSDPC_INVALID_SERVER_REPLY (-104)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
connectToMiniSSDPD(const char * socketpath);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
disconnectFromMiniSSDPD(int fd);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
requestDevicesFromMiniSSDPD(int fd, const char * devtype);
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
receiveDevicesFromMiniSSDPD(int fd, int * error);
|
||||
|
||||
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
ssdpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error,
|
||||
int searchalltypes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,722 @@
|
||||
/* $Id: miniupnpc.c,v 1.148 2016/01/24 17:24:36 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2016 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENSE file. */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
/* Win32 Specific includes and defines */
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#include <iphlpapi.h>
|
||||
#define snprintf _snprintf
|
||||
#define strdup _strdup
|
||||
#ifndef strncasecmp
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
#define strncasecmp _memicmp
|
||||
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||
#define strncasecmp memicmp
|
||||
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||
#endif /* #ifndef strncasecmp */
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#else /* #ifdef _WIN32 */
|
||||
/* Standard POSIX includes */
|
||||
#include <unistd.h>
|
||||
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||
/* Amiga OS 3 specific stuff */
|
||||
#define socklen_t int
|
||||
#else
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#if !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#include <strings.h>
|
||||
#include <errno.h>
|
||||
#define closesocket close
|
||||
#endif /* #else _WIN32 */
|
||||
#ifdef __GNU__
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
|
||||
#include "miniupnpc.h"
|
||||
#include "minissdpc.h"
|
||||
#include "miniwget.h"
|
||||
#include "minisoap.h"
|
||||
#include "minixml.h"
|
||||
#include "upnpcommands.h"
|
||||
#include "connecthostport.h"
|
||||
|
||||
/* compare the begining of a string with a constant string */
|
||||
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
#define SOAPPREFIX "s"
|
||||
#define SERVICEPREFIX "u"
|
||||
#define SERVICEPREFIX2 'u'
|
||||
|
||||
/* check if an ip address is a private (LAN) address
|
||||
* see https://tools.ietf.org/html/rfc1918 */
|
||||
static int is_rfc1918addr(const char * addr)
|
||||
{
|
||||
/* 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) */
|
||||
if(COMPARE(addr, "192.168."))
|
||||
return 1;
|
||||
/* 10.0.0.0 - 10.255.255.255 (10/8 prefix) */
|
||||
if(COMPARE(addr, "10."))
|
||||
return 1;
|
||||
/* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */
|
||||
if(COMPARE(addr, "172.")) {
|
||||
int i = atoi(addr + 4);
|
||||
if((16 <= i) && (i <= 31))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* root description parsing */
|
||||
MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
/* xmlparser object */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = data;
|
||||
parser.starteltfunc = IGDstartelt;
|
||||
parser.endeltfunc = IGDendelt;
|
||||
parser.datafunc = IGDdata;
|
||||
parser.attfunc = 0;
|
||||
parsexml(&parser);
|
||||
#ifdef DEBUG
|
||||
printIGD(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* simpleUPnPcommand2 :
|
||||
* not so simple !
|
||||
* return values :
|
||||
* pointer - OK
|
||||
* NULL - error */
|
||||
char * simpleUPnPcommand2(int s, const char * url, const char * service,
|
||||
const char * action, struct UPNParg * args,
|
||||
int * bufsize, const char * httpversion)
|
||||
{
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
unsigned short port = 0;
|
||||
char * path;
|
||||
char soapact[128];
|
||||
char soapbody[2048];
|
||||
int soapbodylen;
|
||||
char * buf;
|
||||
int n;
|
||||
int status_code;
|
||||
|
||||
*bufsize = 0;
|
||||
snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
|
||||
if(args==NULL)
|
||||
{
|
||||
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
||||
"<?xml version=\"1.0\"?>\r\n"
|
||||
"<" SOAPPREFIX ":Envelope "
|
||||
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||
"<" SOAPPREFIX ":Body>"
|
||||
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
|
||||
"</" SERVICEPREFIX ":%s>"
|
||||
"</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
|
||||
"\r\n", action, service, action);
|
||||
if ((unsigned int)soapbodylen >= sizeof(soapbody))
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
char * p;
|
||||
const char * pe, * pv;
|
||||
const char * const pend = soapbody + sizeof(soapbody);
|
||||
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
||||
"<?xml version=\"1.0\"?>\r\n"
|
||||
"<" SOAPPREFIX ":Envelope "
|
||||
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||
"<" SOAPPREFIX ":Body>"
|
||||
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">",
|
||||
action, service);
|
||||
if ((unsigned int)soapbodylen >= sizeof(soapbody))
|
||||
return NULL;
|
||||
p = soapbody + soapbodylen;
|
||||
while(args->elt)
|
||||
{
|
||||
if(p >= pend) /* check for space to write next byte */
|
||||
return NULL;
|
||||
*(p++) = '<';
|
||||
|
||||
pe = args->elt;
|
||||
while(p < pend && *pe)
|
||||
*(p++) = *(pe++);
|
||||
|
||||
if(p >= pend) /* check for space to write next byte */
|
||||
return NULL;
|
||||
*(p++) = '>';
|
||||
|
||||
if((pv = args->val))
|
||||
{
|
||||
while(p < pend && *pv)
|
||||
*(p++) = *(pv++);
|
||||
}
|
||||
|
||||
if((p+2) > pend) /* check for space to write next 2 bytes */
|
||||
return NULL;
|
||||
*(p++) = '<';
|
||||
*(p++) = '/';
|
||||
|
||||
pe = args->elt;
|
||||
while(p < pend && *pe)
|
||||
*(p++) = *(pe++);
|
||||
|
||||
if(p >= pend) /* check for space to write next byte */
|
||||
return NULL;
|
||||
*(p++) = '>';
|
||||
|
||||
args++;
|
||||
}
|
||||
if((p+4) > pend) /* check for space to write next 4 bytes */
|
||||
return NULL;
|
||||
*(p++) = '<';
|
||||
*(p++) = '/';
|
||||
*(p++) = SERVICEPREFIX2;
|
||||
*(p++) = ':';
|
||||
|
||||
pe = action;
|
||||
while(p < pend && *pe)
|
||||
*(p++) = *(pe++);
|
||||
|
||||
strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
|
||||
pend - p);
|
||||
if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */
|
||||
return NULL;
|
||||
}
|
||||
if(!parseURL(url, hostname, &port, &path, NULL)) return NULL;
|
||||
if(s < 0) {
|
||||
s = connecthostport(hostname, port, 0);
|
||||
if(s < 0) {
|
||||
/* failed to connect */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion);
|
||||
if(n<=0) {
|
||||
#ifdef DEBUG
|
||||
printf("Error sending SOAP request\n");
|
||||
#endif
|
||||
closesocket(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = (char*)getHTTPResponse(s, bufsize, &status_code);
|
||||
#ifdef DEBUG
|
||||
if(*bufsize > 0 && buf)
|
||||
{
|
||||
printf("HTTP %d SOAP Response :\n%.*s\n", status_code, *bufsize, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("HTTP %d, empty SOAP response. size=%d\n", status_code, *bufsize);
|
||||
}
|
||||
#endif
|
||||
closesocket(s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* simpleUPnPcommand :
|
||||
* not so simple !
|
||||
* return values :
|
||||
* pointer - OK
|
||||
* NULL - error */
|
||||
char * simpleUPnPcommand(int s, const char * url, const char * service,
|
||||
const char * action, struct UPNParg * args,
|
||||
int * bufsize)
|
||||
{
|
||||
char * buf;
|
||||
|
||||
#if 1
|
||||
buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1");
|
||||
#else
|
||||
buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0");
|
||||
if (!buf || *bufsize == 0)
|
||||
{
|
||||
#if DEBUG
|
||||
printf("Error or no result from SOAP request; retrying with HTTP/1.1\n");
|
||||
#endif
|
||||
buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1");
|
||||
}
|
||||
#endif
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* upnpDiscoverDevices() :
|
||||
* return a chained list of all devices found or NULL if
|
||||
* no devices was found.
|
||||
* It is up to the caller to free the chained list
|
||||
* delay is in millisecond (poll).
|
||||
* UDA v1.1 says :
|
||||
* The TTL for the IP packet SHOULD default to 2 and
|
||||
* SHOULD be configurable. */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error,
|
||||
int searchalltypes)
|
||||
{
|
||||
struct UPNPDev * tmp;
|
||||
struct UPNPDev * devlist = 0;
|
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
int deviceIndex;
|
||||
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
|
||||
if(error)
|
||||
*error = UPNPDISCOVER_UNKNOWN_ERROR;
|
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
/* first try to get infos from minissdpd ! */
|
||||
if(!minissdpdsock)
|
||||
minissdpdsock = "/var/run/minissdpd.sock";
|
||||
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
|
||||
struct UPNPDev * minissdpd_devlist;
|
||||
int only_rootdevice = 1;
|
||||
minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
|
||||
minissdpdsock, 0);
|
||||
if(minissdpd_devlist) {
|
||||
#ifdef DEBUG
|
||||
printf("returned by MiniSSDPD: %s\t%s\n",
|
||||
minissdpd_devlist->st, minissdpd_devlist->descURL);
|
||||
#endif /* DEBUG */
|
||||
if(!strstr(minissdpd_devlist->st, "rootdevice"))
|
||||
only_rootdevice = 0;
|
||||
for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) {
|
||||
#ifdef DEBUG
|
||||
printf("returned by MiniSSDPD: %s\t%s\n",
|
||||
tmp->pNext->st, tmp->pNext->descURL);
|
||||
#endif /* DEBUG */
|
||||
if(!strstr(tmp->st, "rootdevice"))
|
||||
only_rootdevice = 0;
|
||||
}
|
||||
tmp->pNext = devlist;
|
||||
devlist = minissdpd_devlist;
|
||||
if(!searchalltypes && !only_rootdevice)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) {
|
||||
/* We return what we have found if it was not only a rootdevice */
|
||||
if(!strstr(tmp->st, "rootdevice")) {
|
||||
if(error)
|
||||
*error = UPNPDISCOVER_SUCCESS;
|
||||
return devlist;
|
||||
}
|
||||
}
|
||||
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
|
||||
/* direct discovery if minissdpd responses are not sufficient */
|
||||
{
|
||||
struct UPNPDev * discovered_devlist;
|
||||
discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport,
|
||||
ipv6, ttl, error, searchalltypes);
|
||||
if(devlist == NULL)
|
||||
devlist = discovered_devlist;
|
||||
else {
|
||||
for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext);
|
||||
tmp->pNext = discovered_devlist;
|
||||
}
|
||||
}
|
||||
return devlist;
|
||||
}
|
||||
|
||||
/* upnpDiscover() Discover IGD device */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscover(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error)
|
||||
{
|
||||
static const char * const deviceList[] = {
|
||||
#if 0
|
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:2",
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:2",
|
||||
#endif
|
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:1",
|
||||
"upnp:rootdevice",
|
||||
/*"ssdp:all",*/
|
||||
0
|
||||
};
|
||||
return upnpDiscoverDevices(deviceList,
|
||||
delay, multicastif, minissdpdsock, localport,
|
||||
ipv6, ttl, error, 0);
|
||||
}
|
||||
|
||||
/* upnpDiscoverAll() Discover all UPnP devices */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverAll(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error)
|
||||
{
|
||||
static const char * const deviceList[] = {
|
||||
/*"upnp:rootdevice",*/
|
||||
"ssdp:all",
|
||||
0
|
||||
};
|
||||
return upnpDiscoverDevices(deviceList,
|
||||
delay, multicastif, minissdpdsock, localport,
|
||||
ipv6, ttl, error, 0);
|
||||
}
|
||||
|
||||
/* upnpDiscoverDevice() Discover a specific device */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error)
|
||||
{
|
||||
const char * const deviceList[] = {
|
||||
device,
|
||||
0
|
||||
};
|
||||
return upnpDiscoverDevices(deviceList,
|
||||
delay, multicastif, minissdpdsock, localport,
|
||||
ipv6, ttl, error, 0);
|
||||
}
|
||||
|
||||
static char *
|
||||
build_absolute_url(const char * baseurl, const char * descURL,
|
||||
const char * url, unsigned int scope_id)
|
||||
{
|
||||
int l, n;
|
||||
char * s;
|
||||
const char * base;
|
||||
char * p;
|
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32)
|
||||
char ifname[IF_NAMESIZE];
|
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
char scope_str[8];
|
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
|
||||
if( (url[0] == 'h')
|
||||
&&(url[1] == 't')
|
||||
&&(url[2] == 't')
|
||||
&&(url[3] == 'p')
|
||||
&&(url[4] == ':')
|
||||
&&(url[5] == '/')
|
||||
&&(url[6] == '/'))
|
||||
return strdup(url);
|
||||
base = (baseurl[0] == '\0') ? descURL : baseurl;
|
||||
n = (int)strlen(base);
|
||||
if(n > 7) {
|
||||
p = (char*)strchr(base + 7, '/');
|
||||
if(p)
|
||||
n = (int)(p - base);
|
||||
}
|
||||
l = (int)(n + strlen(url) + 1);
|
||||
if(url[0] != '/')
|
||||
l++;
|
||||
if(scope_id != 0) {
|
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32)
|
||||
if(if_indextoname(scope_id, ifname)) {
|
||||
l += 3 + strlen(ifname); /* 3 == strlen(%25) */
|
||||
}
|
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
/* under windows, scope is numerical */
|
||||
l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
|
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
}
|
||||
s = (char*)malloc(l);
|
||||
if(s == NULL) return NULL;
|
||||
memcpy(s, base, n);
|
||||
if(scope_id != 0) {
|
||||
s[n] = '\0';
|
||||
if(0 == memcmp(s, "http://[fe80:", 13)) {
|
||||
/* this is a linklocal IPv6 address */
|
||||
p = strchr(s, ']');
|
||||
if(p) {
|
||||
/* insert %25<scope> into URL */
|
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32)
|
||||
memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
|
||||
memcpy(p, "%25", 3);
|
||||
memcpy(p + 3, ifname, strlen(ifname));
|
||||
n += 3 + strlen(ifname);
|
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
|
||||
memcpy(p, "%25", 3);
|
||||
memcpy(p + 3, scope_str, strlen(scope_str));
|
||||
n += 3 + strlen(scope_str);
|
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
}
|
||||
}
|
||||
}
|
||||
if(url[0] != '/')
|
||||
s[n++] = '/';
|
||||
memcpy(s + n, url, l - n);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Prepare the Urls for usage...
|
||||
*/
|
||||
MINIUPNP_LIBSPEC void
|
||||
GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||
const char * descURL, unsigned int scope_id)
|
||||
{
|
||||
/* strdup descURL */
|
||||
urls->rootdescURL = strdup(descURL);
|
||||
|
||||
/* get description of WANIPConnection */
|
||||
urls->ipcondescURL = build_absolute_url(data->urlbase, descURL,
|
||||
data->first.scpdurl, scope_id);
|
||||
urls->controlURL = build_absolute_url(data->urlbase, descURL,
|
||||
data->first.controlurl, scope_id);
|
||||
urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL,
|
||||
data->CIF.controlurl, scope_id);
|
||||
urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL,
|
||||
data->IPv6FC.controlurl, scope_id);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL);
|
||||
printf("urls->controlURL='%s'\n", urls->controlURL);
|
||||
printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF);
|
||||
printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC);
|
||||
#endif
|
||||
}
|
||||
|
||||
MINIUPNP_LIBSPEC void
|
||||
FreeUPNPUrls(struct UPNPUrls * urls)
|
||||
{
|
||||
if(!urls)
|
||||
return;
|
||||
free(urls->controlURL);
|
||||
urls->controlURL = 0;
|
||||
free(urls->ipcondescURL);
|
||||
urls->ipcondescURL = 0;
|
||||
free(urls->controlURL_CIF);
|
||||
urls->controlURL_CIF = 0;
|
||||
free(urls->controlURL_6FC);
|
||||
urls->controlURL_6FC = 0;
|
||||
free(urls->rootdescURL);
|
||||
urls->rootdescURL = 0;
|
||||
}
|
||||
|
||||
int
|
||||
UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
|
||||
{
|
||||
char status[64];
|
||||
unsigned int uptime;
|
||||
status[0] = '\0';
|
||||
UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
|
||||
status, &uptime, NULL);
|
||||
if(0 == strcmp("Connected", status))
|
||||
return 1;
|
||||
else if(0 == strcmp("Up", status)) /* Also accept "Up" */
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* UPNP_GetValidIGD() :
|
||||
* return values :
|
||||
* -1 = Internal error
|
||||
* 0 = NO IGD found
|
||||
* 1 = A valid connected IGD has been found
|
||||
* 2 = A valid IGD has been found but it reported as
|
||||
* not connected
|
||||
* 3 = an UPnP device has been found but was not recognized as an IGD
|
||||
*
|
||||
* In any positive non zero return case, the urls and data structures
|
||||
* passed as parameters are set. Dont forget to call FreeUPNPUrls(urls) to
|
||||
* free allocated memory.
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
char * lanaddr, int lanaddrlen)
|
||||
{
|
||||
struct xml_desc {
|
||||
char * xml;
|
||||
int size;
|
||||
int is_igd;
|
||||
} * desc = NULL;
|
||||
struct UPNPDev * dev;
|
||||
int ndev = 0;
|
||||
int i;
|
||||
int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
|
||||
int n_igd = 0;
|
||||
char extIpAddr[16];
|
||||
char myLanAddr[40];
|
||||
int status_code = -1;
|
||||
|
||||
if(!devlist)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Empty devlist\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/* counting total number of devices in the list */
|
||||
for(dev = devlist; dev; dev = dev->pNext)
|
||||
ndev++;
|
||||
if(ndev > 0)
|
||||
{
|
||||
desc = (struct xml_desc*)calloc(ndev, sizeof(struct xml_desc));
|
||||
if(!desc)
|
||||
return -1; /* memory allocation error */
|
||||
}
|
||||
/* Step 1 : downloading descriptions and testing type */
|
||||
for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
|
||||
{
|
||||
/* we should choose an internet gateway device.
|
||||
* with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
|
||||
desc[i].xml = (char*)miniwget_getaddr(dev->descURL, &(desc[i].size),
|
||||
myLanAddr, sizeof(myLanAddr),
|
||||
dev->scope_id, &status_code);
|
||||
#ifdef DEBUG
|
||||
if(!desc[i].xml)
|
||||
{
|
||||
printf("error getting XML description %s\n", dev->descURL);
|
||||
}
|
||||
#endif
|
||||
if(desc[i].xml)
|
||||
{
|
||||
memset(data, 0, sizeof(struct IGDdatas));
|
||||
memset(urls, 0, sizeof(struct UPNPUrls));
|
||||
parserootdesc(desc[i].xml, desc[i].size, data);
|
||||
if(COMPARE(data->CIF.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))
|
||||
{
|
||||
desc[i].is_igd = 1;
|
||||
n_igd++;
|
||||
if(lanaddr)
|
||||
strncpy(lanaddr, myLanAddr, lanaddrlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* iterate the list to find a device depending on state */
|
||||
for(state = 1; state <= 3; state++)
|
||||
{
|
||||
for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
|
||||
{
|
||||
if(desc[i].xml)
|
||||
{
|
||||
memset(data, 0, sizeof(struct IGDdatas));
|
||||
memset(urls, 0, sizeof(struct UPNPUrls));
|
||||
parserootdesc(desc[i].xml, desc[i].size, data);
|
||||
if(desc[i].is_igd || state >= 3 )
|
||||
{
|
||||
int is_connected;
|
||||
|
||||
GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
|
||||
|
||||
/* in state 2 and 3 we dont test if device is connected ! */
|
||||
if(state >= 2)
|
||||
goto free_and_return;
|
||||
is_connected = UPNPIGD_IsConnected(urls, data);
|
||||
#ifdef DEBUG
|
||||
printf("UPNPIGD_IsConnected(%s) = %d\n",
|
||||
urls->controlURL, is_connected);
|
||||
#endif
|
||||
/* checks that status is connected AND there is a external IP address assigned */
|
||||
if(is_connected &&
|
||||
(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) {
|
||||
if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0')
|
||||
&& (0 != strcmp(extIpAddr, "0.0.0.0")))
|
||||
goto free_and_return;
|
||||
}
|
||||
FreeUPNPUrls(urls);
|
||||
if(data->second.servicetype[0] != '\0') {
|
||||
#ifdef DEBUG
|
||||
printf("We tried %s, now we try %s !\n",
|
||||
data->first.servicetype, data->second.servicetype);
|
||||
#endif
|
||||
/* swaping WANPPPConnection and WANIPConnection ! */
|
||||
memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service));
|
||||
memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service));
|
||||
memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service));
|
||||
GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
|
||||
is_connected = UPNPIGD_IsConnected(urls, data);
|
||||
#ifdef DEBUG
|
||||
printf("UPNPIGD_IsConnected(%s) = %d\n",
|
||||
urls->controlURL, is_connected);
|
||||
#endif
|
||||
if(is_connected &&
|
||||
(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) {
|
||||
if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0')
|
||||
&& (0 != strcmp(extIpAddr, "0.0.0.0")))
|
||||
goto free_and_return;
|
||||
}
|
||||
FreeUPNPUrls(urls);
|
||||
}
|
||||
}
|
||||
memset(data, 0, sizeof(struct IGDdatas));
|
||||
}
|
||||
}
|
||||
}
|
||||
state = 0;
|
||||
free_and_return:
|
||||
if(desc) {
|
||||
for(i = 0; i < ndev; i++) {
|
||||
if(desc[i].xml) {
|
||||
free(desc[i].xml);
|
||||
}
|
||||
}
|
||||
free(desc);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/* UPNP_GetIGDFromUrl()
|
||||
* Used when skipping the discovery process.
|
||||
* return value :
|
||||
* 0 - Not ok
|
||||
* 1 - OK */
|
||||
int
|
||||
UPNP_GetIGDFromUrl(const char * rootdescurl,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
char * lanaddr, int lanaddrlen)
|
||||
{
|
||||
char * descXML;
|
||||
int descXMLsize = 0;
|
||||
|
||||
descXML = (char*)miniwget_getaddr(rootdescurl, &descXMLsize,
|
||||
lanaddr, lanaddrlen, 0, NULL);
|
||||
if(descXML) {
|
||||
memset(data, 0, sizeof(struct IGDdatas));
|
||||
memset(urls, 0, sizeof(struct UPNPUrls));
|
||||
parserootdesc(descXML, descXMLsize, data);
|
||||
free(descXML);
|
||||
descXML = NULL;
|
||||
GetUPNPUrls(urls, data, rootdescurl, 0);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
LIBRARY
|
||||
; miniupnpc library
|
||||
miniupnpc
|
||||
|
||||
EXPORTS
|
||||
; miniupnpc
|
||||
upnpDiscover
|
||||
freeUPNPDevlist
|
||||
parserootdesc
|
||||
UPNP_GetValidIGD
|
||||
UPNP_GetIGDFromUrl
|
||||
GetUPNPUrls
|
||||
FreeUPNPUrls
|
||||
; miniwget
|
||||
miniwget
|
||||
miniwget_getaddr
|
||||
; upnpcommands
|
||||
UPNP_GetTotalBytesSent
|
||||
UPNP_GetTotalBytesReceived
|
||||
UPNP_GetTotalPacketsSent
|
||||
UPNP_GetTotalPacketsReceived
|
||||
UPNP_GetStatusInfo
|
||||
UPNP_GetConnectionTypeInfo
|
||||
UPNP_GetExternalIPAddress
|
||||
UPNP_GetLinkLayerMaxBitRates
|
||||
UPNP_AddPortMapping
|
||||
UPNP_AddAnyPortMapping
|
||||
UPNP_DeletePortMapping
|
||||
UPNP_DeletePortMappingRange
|
||||
UPNP_GetPortMappingNumberOfEntries
|
||||
UPNP_GetSpecificPortMappingEntry
|
||||
UPNP_GetGenericPortMappingEntry
|
||||
UPNP_GetListOfPortMappings
|
||||
UPNP_AddPinhole
|
||||
UPNP_CheckPinholeWorking
|
||||
UPNP_UpdatePinhole
|
||||
UPNP_GetPinholePackets
|
||||
UPNP_DeletePinhole
|
||||
UPNP_GetFirewallStatus
|
||||
UPNP_GetOutboundPinholeTimeout
|
||||
; upnperrors
|
||||
strupnperror
|
||||
; portlistingparse
|
||||
ParsePortListing
|
||||
FreePortListing
|
||||
@@ -0,0 +1,152 @@
|
||||
/* $Id: miniupnpc.h,v 1.50 2016/04/19 21:06:21 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2016 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef MINIUPNPC_H_INCLUDED
|
||||
#define MINIUPNPC_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_declspec.h"
|
||||
#include "igd_desc_parse.h"
|
||||
#include "upnpdev.h"
|
||||
|
||||
/* error codes : */
|
||||
#define UPNPDISCOVER_SUCCESS (0)
|
||||
#define UPNPDISCOVER_UNKNOWN_ERROR (-1)
|
||||
#define UPNPDISCOVER_SOCKET_ERROR (-101)
|
||||
#define UPNPDISCOVER_MEMORY_ERROR (-102)
|
||||
|
||||
/* versions : */
|
||||
#define MINIUPNPC_VERSION "2.0"
|
||||
#define MINIUPNPC_API_VERSION 16
|
||||
|
||||
/* Source port:
|
||||
Using "1" as an alias for 1900 for backwards compatability
|
||||
(presuming one would have used that for the "sameport" parameter) */
|
||||
#define UPNP_LOCAL_PORT_ANY 0
|
||||
#define UPNP_LOCAL_PORT_SAME 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Structures definitions : */
|
||||
struct UPNParg { const char * elt; const char * val; };
|
||||
|
||||
char *
|
||||
simpleUPnPcommand(int, const char *, const char *,
|
||||
const char *, struct UPNParg *,
|
||||
int *);
|
||||
|
||||
/* upnpDiscover()
|
||||
* discover UPnP devices on the network.
|
||||
* The discovered devices are returned as a chained list.
|
||||
* It is up to the caller to free the list with freeUPNPDevlist().
|
||||
* delay (in millisecond) is the maximum time for waiting any device
|
||||
* response.
|
||||
* If available, device list will be obtained from MiniSSDPd.
|
||||
* Default path for minissdpd socket will be used if minissdpdsock argument
|
||||
* is NULL.
|
||||
* If multicastif is not NULL, it will be used instead of the default
|
||||
* multicast interface for sending SSDP discover packets.
|
||||
* If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent
|
||||
* from the source port 1900 (same as destination port), if set to
|
||||
* UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will
|
||||
* be attempted as the source port.
|
||||
* "searchalltypes" parameter is useful when searching several types,
|
||||
* if 0, the discovery will stop with the first type returning results.
|
||||
* TTL should default to 2. */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscover(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error);
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverAll(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error);
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error);
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error,
|
||||
int searchalltypes);
|
||||
|
||||
/* parserootdesc() :
|
||||
* parse root XML description of a UPnP device and fill the IGDdatas
|
||||
* structure. */
|
||||
MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *);
|
||||
|
||||
/* structure used to get fast access to urls
|
||||
* controlURL: controlURL of the WANIPConnection
|
||||
* ipcondescURL: url of the description of the WANIPConnection
|
||||
* controlURL_CIF: controlURL of the WANCommonInterfaceConfig
|
||||
* controlURL_6FC: controlURL of the WANIPv6FirewallControl
|
||||
*/
|
||||
struct UPNPUrls {
|
||||
char * controlURL;
|
||||
char * ipcondescURL;
|
||||
char * controlURL_CIF;
|
||||
char * controlURL_6FC;
|
||||
char * rootdescURL;
|
||||
};
|
||||
|
||||
/* UPNP_GetValidIGD() :
|
||||
* return values :
|
||||
* 0 = NO IGD found
|
||||
* 1 = A valid connected IGD has been found
|
||||
* 2 = A valid IGD has been found but it reported as
|
||||
* not connected
|
||||
* 3 = an UPnP device has been found but was not recognized as an IGD
|
||||
*
|
||||
* In any non zero return case, the urls and data structures
|
||||
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
|
||||
* free allocated memory.
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
char * lanaddr, int lanaddrlen);
|
||||
|
||||
/* UPNP_GetIGDFromUrl()
|
||||
* Used when skipping the discovery process.
|
||||
* When succeding, urls, data, and lanaddr arguments are set.
|
||||
* return value :
|
||||
* 0 - Not ok
|
||||
* 1 - OK */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetIGDFromUrl(const char * rootdescurl,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
char * lanaddr, int lanaddrlen);
|
||||
|
||||
MINIUPNP_LIBSPEC void
|
||||
GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *,
|
||||
const char *, unsigned int);
|
||||
|
||||
MINIUPNP_LIBSPEC void
|
||||
FreeUPNPUrls(struct UPNPUrls *);
|
||||
|
||||
/* return 0 or 1 */
|
||||
MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED
|
||||
#define MINIUPNPC_DECLSPEC_H_INCLUDED
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
/* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */
|
||||
#define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define MINIUPNP_LIBSPEC
|
||||
#endif
|
||||
|
||||
#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2014 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef MINIUPNPCSTRINGS_H_INCLUDED
|
||||
#define MINIUPNPCSTRINGS_H_INCLUDED
|
||||
|
||||
#define OS_STRING "OS/version"
|
||||
#define MINIUPNPC_VERSION_STRING "version"
|
||||
|
||||
#if 0
|
||||
/* according to "UPnP Device Architecture 1.0" */
|
||||
#define UPNP_VERSION_STRING "UPnP/1.0"
|
||||
#else
|
||||
/* according to "UPnP Device Architecture 1.1" */
|
||||
#define UPNP_VERSION_STRING "UPnP/1.1"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/* $Id: miniupnpctypes.h,v 1.1 2011/02/15 11:10:40 nanard Exp $ */
|
||||
/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2011 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided within this distribution */
|
||||
#ifndef MINIUPNPCTYPES_H_INCLUDED
|
||||
#define MINIUPNPCTYPES_H_INCLUDED
|
||||
|
||||
#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
|
||||
#define UNSIGNED_INTEGER unsigned long long
|
||||
#define STRTOUI strtoull
|
||||
#else
|
||||
#define UNSIGNED_INTEGER unsigned int
|
||||
#define STRTOUI strtoul
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,661 @@
|
||||
/* $Id: miniwget.c,v 1.75 2016/01/24 17:24:36 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2016 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#define snprintf _snprintf
|
||||
#define socklen_t int
|
||||
#ifndef strncasecmp
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
#define strncasecmp _memicmp
|
||||
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||
#define strncasecmp memicmp
|
||||
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||
#endif /* #ifndef strncasecmp */
|
||||
#else /* #ifdef _WIN32 */
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#define socklen_t int
|
||||
#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/select.h>
|
||||
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#define closesocket close
|
||||
#include <strings.h>
|
||||
#endif /* #else _WIN32 */
|
||||
#ifdef __GNU__
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif /* __GNU__ */
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#endif /* MIN */
|
||||
|
||||
|
||||
#include "miniupnpcstrings.h"
|
||||
#include "miniwget.h"
|
||||
#include "connecthostport.h"
|
||||
#include "receivedata.h"
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read a HTTP response from a socket.
|
||||
* Process Content-Length and Transfer-encoding headers.
|
||||
* return a pointer to the content buffer, which length is saved
|
||||
* to the length parameter.
|
||||
*/
|
||||
void *
|
||||
getHTTPResponse(int s, int * size, int * status_code)
|
||||
{
|
||||
char buf[2048];
|
||||
int n;
|
||||
int endofheaders = 0;
|
||||
int chunked = 0;
|
||||
int content_length = -1;
|
||||
unsigned int chunksize = 0;
|
||||
unsigned int bytestocopy = 0;
|
||||
/* buffers : */
|
||||
char * header_buf;
|
||||
unsigned int header_buf_len = 2048;
|
||||
unsigned int header_buf_used = 0;
|
||||
char * content_buf;
|
||||
unsigned int content_buf_len = 2048;
|
||||
unsigned int content_buf_used = 0;
|
||||
char chunksize_buf[32];
|
||||
unsigned int chunksize_buf_index;
|
||||
#ifdef DEBUG
|
||||
char * reason_phrase = NULL;
|
||||
int reason_phrase_len = 0;
|
||||
#endif
|
||||
|
||||
if(status_code) *status_code = -1;
|
||||
header_buf = (char*)malloc(header_buf_len);
|
||||
if(header_buf == NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
|
||||
#endif /* DEBUG */
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
content_buf = (char*)malloc(content_buf_len);
|
||||
if(content_buf == NULL)
|
||||
{
|
||||
free(header_buf);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
|
||||
#endif /* DEBUG */
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
chunksize_buf[0] = '\0';
|
||||
chunksize_buf_index = 0;
|
||||
|
||||
while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0)
|
||||
{
|
||||
if(endofheaders == 0)
|
||||
{
|
||||
int i;
|
||||
int linestart=0;
|
||||
int colon=0;
|
||||
int valuestart=0;
|
||||
if(header_buf_used + n > header_buf_len) {
|
||||
char * tmp = (char*)realloc(header_buf, header_buf_used + n);
|
||||
if(tmp == NULL) {
|
||||
/* memory allocation error */
|
||||
free(header_buf);
|
||||
free(content_buf);
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
header_buf = tmp;
|
||||
header_buf_len = header_buf_used + n;
|
||||
}
|
||||
memcpy(header_buf + header_buf_used, buf, n);
|
||||
header_buf_used += n;
|
||||
/* search for CR LF CR LF (end of headers)
|
||||
* recognize also LF LF */
|
||||
i = 0;
|
||||
while(i < ((int)header_buf_used-1) && (endofheaders == 0)) {
|
||||
if(header_buf[i] == '\r') {
|
||||
i++;
|
||||
if(header_buf[i] == '\n') {
|
||||
i++;
|
||||
if(i < (int)header_buf_used && header_buf[i] == '\r') {
|
||||
i++;
|
||||
if(i < (int)header_buf_used && header_buf[i] == '\n') {
|
||||
endofheaders = i+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(header_buf[i] == '\n') {
|
||||
i++;
|
||||
if(header_buf[i] == '\n') {
|
||||
endofheaders = i+1;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(endofheaders == 0)
|
||||
continue;
|
||||
/* parse header lines */
|
||||
for(i = 0; i < endofheaders - 1; i++) {
|
||||
if(linestart > 0 && colon <= linestart && header_buf[i]==':')
|
||||
{
|
||||
colon = i;
|
||||
while(i < (endofheaders-1)
|
||||
&& (header_buf[i+1] == ' ' || header_buf[i+1] == '\t'))
|
||||
i++;
|
||||
valuestart = i + 1;
|
||||
}
|
||||
/* detecting end of line */
|
||||
else if(header_buf[i]=='\r' || header_buf[i]=='\n')
|
||||
{
|
||||
if(linestart == 0 && status_code)
|
||||
{
|
||||
/* Status line
|
||||
* HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
|
||||
int sp;
|
||||
for(sp = 0; sp < i; sp++)
|
||||
if(header_buf[sp] == ' ')
|
||||
{
|
||||
if(*status_code < 0)
|
||||
*status_code = atoi(header_buf + sp + 1);
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
reason_phrase = header_buf + sp + 1;
|
||||
reason_phrase_len = i - sp - 1;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("HTTP status code = %d, Reason phrase = %.*s\n",
|
||||
*status_code, reason_phrase_len, reason_phrase);
|
||||
#endif
|
||||
}
|
||||
else if(colon > linestart && valuestart > colon)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("header='%.*s', value='%.*s'\n",
|
||||
colon-linestart, header_buf+linestart,
|
||||
i-valuestart, header_buf+valuestart);
|
||||
#endif
|
||||
if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart))
|
||||
{
|
||||
content_length = atoi(header_buf+valuestart);
|
||||
#ifdef DEBUG
|
||||
printf("Content-Length: %d\n", content_length);
|
||||
#endif
|
||||
}
|
||||
else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart)
|
||||
&& 0==strncasecmp(header_buf+valuestart, "chunked", 7))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("chunked transfer-encoding!\n");
|
||||
#endif
|
||||
chunked = 1;
|
||||
}
|
||||
}
|
||||
while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n'))
|
||||
i++;
|
||||
linestart = i;
|
||||
colon = linestart;
|
||||
valuestart = 0;
|
||||
}
|
||||
}
|
||||
/* copy the remaining of the received data back to buf */
|
||||
n = header_buf_used - endofheaders;
|
||||
memcpy(buf, header_buf + endofheaders, n);
|
||||
/* if(headers) */
|
||||
}
|
||||
if(endofheaders)
|
||||
{
|
||||
/* content */
|
||||
if(chunked)
|
||||
{
|
||||
int i = 0;
|
||||
while(i < n)
|
||||
{
|
||||
if(chunksize == 0)
|
||||
{
|
||||
/* reading chunk size */
|
||||
if(chunksize_buf_index == 0) {
|
||||
/* skipping any leading CR LF */
|
||||
if(i<n && buf[i] == '\r') i++;
|
||||
if(i<n && buf[i] == '\n') i++;
|
||||
}
|
||||
while(i<n && isxdigit(buf[i])
|
||||
&& chunksize_buf_index < (sizeof(chunksize_buf)-1))
|
||||
{
|
||||
chunksize_buf[chunksize_buf_index++] = buf[i];
|
||||
chunksize_buf[chunksize_buf_index] = '\0';
|
||||
i++;
|
||||
}
|
||||
while(i<n && buf[i] != '\r' && buf[i] != '\n')
|
||||
i++; /* discarding chunk-extension */
|
||||
if(i<n && buf[i] == '\r') i++;
|
||||
if(i<n && buf[i] == '\n') {
|
||||
unsigned int j;
|
||||
for(j = 0; j < chunksize_buf_index; j++) {
|
||||
if(chunksize_buf[j] >= '0'
|
||||
&& chunksize_buf[j] <= '9')
|
||||
chunksize = (chunksize << 4) + (chunksize_buf[j] - '0');
|
||||
else
|
||||
chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10);
|
||||
}
|
||||
chunksize_buf[0] = '\0';
|
||||
chunksize_buf_index = 0;
|
||||
i++;
|
||||
} else {
|
||||
/* not finished to get chunksize */
|
||||
continue;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("chunksize = %u (%x)\n", chunksize, chunksize);
|
||||
#endif
|
||||
if(chunksize == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("end of HTTP content - %d %d\n", i, n);
|
||||
/*printf("'%.*s'\n", n-i, buf+i);*/
|
||||
#endif
|
||||
goto end_of_stream;
|
||||
}
|
||||
}
|
||||
bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i);
|
||||
if((content_buf_used + bytestocopy) > content_buf_len)
|
||||
{
|
||||
char * tmp;
|
||||
if(content_length >= (int)(content_buf_used + bytestocopy)) {
|
||||
content_buf_len = content_length;
|
||||
} else {
|
||||
content_buf_len = content_buf_used + bytestocopy;
|
||||
}
|
||||
tmp = (char*)realloc(content_buf, content_buf_len);
|
||||
if(tmp == NULL) {
|
||||
/* memory allocation error */
|
||||
free(content_buf);
|
||||
free(header_buf);
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
content_buf = tmp;
|
||||
}
|
||||
memcpy(content_buf + content_buf_used, buf + i, bytestocopy);
|
||||
content_buf_used += bytestocopy;
|
||||
i += bytestocopy;
|
||||
chunksize -= bytestocopy;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not chunked */
|
||||
if(content_length > 0
|
||||
&& (int)(content_buf_used + n) > content_length) {
|
||||
/* skipping additional bytes */
|
||||
n = content_length - content_buf_used;
|
||||
}
|
||||
if(content_buf_used + n > content_buf_len)
|
||||
{
|
||||
char * tmp;
|
||||
if(content_length >= (int)(content_buf_used + n)) {
|
||||
content_buf_len = content_length;
|
||||
} else {
|
||||
content_buf_len = content_buf_used + n;
|
||||
}
|
||||
tmp = (char*)realloc(content_buf, content_buf_len);
|
||||
if(tmp == NULL) {
|
||||
/* memory allocation error */
|
||||
free(content_buf);
|
||||
free(header_buf);
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
content_buf = tmp;
|
||||
}
|
||||
memcpy(content_buf + content_buf_used, buf, n);
|
||||
content_buf_used += n;
|
||||
}
|
||||
}
|
||||
/* use the Content-Length header value if available */
|
||||
if(content_length > 0 && (int)content_buf_used >= content_length)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("End of HTTP content\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
end_of_stream:
|
||||
free(header_buf); header_buf = NULL;
|
||||
*size = content_buf_used;
|
||||
if(content_buf_used == 0)
|
||||
{
|
||||
free(content_buf);
|
||||
content_buf = NULL;
|
||||
}
|
||||
return content_buf;
|
||||
}
|
||||
|
||||
/* miniwget3() :
|
||||
* do all the work.
|
||||
* Return NULL if something failed. */
|
||||
static void *
|
||||
miniwget3(const char * host,
|
||||
unsigned short port, const char * path,
|
||||
int * size, char * addr_str, int addr_str_len,
|
||||
const char * httpversion, unsigned int scope_id,
|
||||
int * status_code)
|
||||
{
|
||||
char buf[2048];
|
||||
int s;
|
||||
int n;
|
||||
int len;
|
||||
int sent;
|
||||
void * content;
|
||||
|
||||
*size = 0;
|
||||
s = connecthostport(host, port, scope_id);
|
||||
if(s < 0)
|
||||
return NULL;
|
||||
|
||||
/* get address for caller ! */
|
||||
if(addr_str)
|
||||
{
|
||||
struct sockaddr_storage saddr;
|
||||
socklen_t saddrlen;
|
||||
|
||||
saddrlen = sizeof(saddr);
|
||||
if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0)
|
||||
{
|
||||
perror("getsockname");
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||
/* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD);
|
||||
* But his function make a string with the port : nn.nn.nn.nn:port */
|
||||
/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr),
|
||||
NULL, addr_str, (DWORD *)&addr_str_len))
|
||||
{
|
||||
printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError());
|
||||
}*/
|
||||
/* the following code is only compatible with ip v4 addresses */
|
||||
strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len);
|
||||
#else
|
||||
#if 0
|
||||
if(saddr.sa_family == AF_INET6) {
|
||||
inet_ntop(AF_INET6,
|
||||
&(((struct sockaddr_in6 *)&saddr)->sin6_addr),
|
||||
addr_str, addr_str_len);
|
||||
} else {
|
||||
inet_ntop(AF_INET,
|
||||
&(((struct sockaddr_in *)&saddr)->sin_addr),
|
||||
addr_str, addr_str_len);
|
||||
}
|
||||
#endif
|
||||
/* getnameinfo return ip v6 address with the scope identifier
|
||||
* such as : 2a01:e35:8b2b:7330::%4281128194 */
|
||||
n = getnameinfo((const struct sockaddr *)&saddr, saddrlen,
|
||||
addr_str, addr_str_len,
|
||||
NULL, 0,
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
if(n != 0) {
|
||||
#ifdef _WIN32
|
||||
fprintf(stderr, "getnameinfo() failed : %d\n", n);
|
||||
#else
|
||||
fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("address miniwget : %s\n", addr_str);
|
||||
#endif
|
||||
}
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"GET %s HTTP/%s\r\n"
|
||||
"Host: %s:%d\r\n"
|
||||
"Connection: Close\r\n"
|
||||
"User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
|
||||
|
||||
"\r\n",
|
||||
path, httpversion, host, port);
|
||||
if ((unsigned int)len >= sizeof(buf))
|
||||
{
|
||||
closesocket(s);
|
||||
return NULL;
|
||||
}
|
||||
sent = 0;
|
||||
/* sending the HTTP request */
|
||||
while(sent < len)
|
||||
{
|
||||
n = (int)send(s, buf+sent, len-sent, 0);
|
||||
if(n < 0)
|
||||
{
|
||||
perror("send");
|
||||
closesocket(s);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
sent += n;
|
||||
}
|
||||
}
|
||||
content = getHTTPResponse(s, size, status_code);
|
||||
closesocket(s);
|
||||
return content;
|
||||
}
|
||||
|
||||
/* miniwget2() :
|
||||
* Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */
|
||||
static void *
|
||||
miniwget2(const char * host,
|
||||
unsigned short port, const char * path,
|
||||
int * size, char * addr_str, int addr_str_len,
|
||||
unsigned int scope_id, int * status_code)
|
||||
{
|
||||
char * respbuffer;
|
||||
|
||||
#if 1
|
||||
respbuffer = (char*)miniwget3(host, port, path, size,
|
||||
addr_str, addr_str_len, "1.1",
|
||||
scope_id, status_code);
|
||||
#else
|
||||
respbuffer = (char*)miniwget3(host, port, path, size,
|
||||
addr_str, addr_str_len, "1.0",
|
||||
scope_id, status_code);
|
||||
if (*size == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Retrying with HTTP/1.1\n");
|
||||
#endif
|
||||
free(respbuffer);
|
||||
respbuffer = miniwget3(host, port, path, size,
|
||||
addr_str, addr_str_len, "1.1",
|
||||
scope_id, status_code);
|
||||
}
|
||||
#endif
|
||||
return respbuffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* parseURL()
|
||||
* arguments :
|
||||
* url : source string not modified
|
||||
* hostname : hostname destination string (size of MAXHOSTNAMELEN+1)
|
||||
* port : port (destination)
|
||||
* path : pointer to the path part of the URL
|
||||
*
|
||||
* Return values :
|
||||
* 0 - Failure
|
||||
* 1 - Success */
|
||||
int
|
||||
parseURL(const char * url,
|
||||
char * hostname, unsigned short * port,
|
||||
char * * path, unsigned int * scope_id)
|
||||
{
|
||||
char * p1, *p2, *p3;
|
||||
if(!url)
|
||||
return 0;
|
||||
p1 = (char*)strstr(url, "://");
|
||||
if(!p1)
|
||||
return 0;
|
||||
p1 += 3;
|
||||
if( (url[0]!='h') || (url[1]!='t')
|
||||
||(url[2]!='t') || (url[3]!='p'))
|
||||
return 0;
|
||||
memset(hostname, 0, MAXHOSTNAMELEN + 1);
|
||||
if(*p1 == '[')
|
||||
{
|
||||
/* IP v6 : http://[2a00:1450:8002::6a]/path/abc */
|
||||
char * scope;
|
||||
scope = strchr(p1, '%');
|
||||
p2 = strchr(p1, ']');
|
||||
if(p2 && scope && scope < p2 && scope_id) {
|
||||
/* parse scope */
|
||||
#ifdef IF_NAMESIZE
|
||||
char tmp[IF_NAMESIZE];
|
||||
int l;
|
||||
scope++;
|
||||
/* "%25" is just '%' in URL encoding */
|
||||
if(scope[0] == '2' && scope[1] == '5')
|
||||
scope += 2; /* skip "25" */
|
||||
l = (int)(p2 - scope);
|
||||
if(l >= IF_NAMESIZE)
|
||||
l = IF_NAMESIZE - 1;
|
||||
memcpy(tmp, scope, l);
|
||||
tmp[l] = '\0';
|
||||
*scope_id = if_nametoindex(tmp);
|
||||
if(*scope_id == 0) {
|
||||
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
|
||||
}
|
||||
#else
|
||||
/* under windows, scope is numerical */
|
||||
char tmp[8];
|
||||
int l;
|
||||
scope++;
|
||||
/* "%25" is just '%' in URL encoding */
|
||||
if(scope[0] == '2' && scope[1] == '5')
|
||||
scope += 2; /* skip "25" */
|
||||
l = p2 - scope;
|
||||
if(l >= sizeof(tmp))
|
||||
l = sizeof(tmp) - 1;
|
||||
memcpy(tmp, scope, l);
|
||||
tmp[l] = '\0';
|
||||
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
|
||||
#endif
|
||||
}
|
||||
p3 = strchr(p1, '/');
|
||||
if(p2 && p3)
|
||||
{
|
||||
p2++;
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||
if(*p2 == ':')
|
||||
{
|
||||
*port = 0;
|
||||
p2++;
|
||||
while( (*p2 >= '0') && (*p2 <= '9'))
|
||||
{
|
||||
*port *= 10;
|
||||
*port += (unsigned short)(*p2 - '0');
|
||||
p2++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*port = 80;
|
||||
}
|
||||
*path = p3;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
p2 = strchr(p1, ':');
|
||||
p3 = strchr(p1, '/');
|
||||
if(!p3)
|
||||
return 0;
|
||||
if(!p2 || (p2>p3))
|
||||
{
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1)));
|
||||
*port = 80;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||
*port = 0;
|
||||
p2++;
|
||||
while( (*p2 >= '0') && (*p2 <= '9'))
|
||||
{
|
||||
*port *= 10;
|
||||
*port += (unsigned short)(*p2 - '0');
|
||||
p2++;
|
||||
}
|
||||
}
|
||||
*path = p3;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *
|
||||
miniwget(const char * url, int * size,
|
||||
unsigned int scope_id, int * status_code)
|
||||
{
|
||||
unsigned short port;
|
||||
char * path;
|
||||
/* protocol://host:port/chemin */
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
*size = 0;
|
||||
if(!parseURL(url, hostname, &port, &path, &scope_id))
|
||||
return NULL;
|
||||
#ifdef DEBUG
|
||||
printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
|
||||
hostname, port, path, scope_id);
|
||||
#endif
|
||||
return miniwget2(hostname, port, path, size, 0, 0, scope_id, status_code);
|
||||
}
|
||||
|
||||
void *
|
||||
miniwget_getaddr(const char * url, int * size,
|
||||
char * addr, int addrlen, unsigned int scope_id,
|
||||
int * status_code)
|
||||
{
|
||||
unsigned short port;
|
||||
char * path;
|
||||
/* protocol://host:port/path */
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
*size = 0;
|
||||
if(addr)
|
||||
addr[0] = '\0';
|
||||
if(!parseURL(url, hostname, &port, &path, &scope_id))
|
||||
return NULL;
|
||||
#ifdef DEBUG
|
||||
printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
|
||||
hostname, port, path, scope_id);
|
||||
#endif
|
||||
return miniwget2(hostname, port, path, size, addr, addrlen, scope_id, status_code);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/* $Id: miniwget.h,v 1.12 2016/01/24 17:24:36 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2016 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef MINIWGET_H_INCLUDED
|
||||
#define MINIWGET_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_declspec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size, int * status_code);
|
||||
|
||||
MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int, int *);
|
||||
|
||||
MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int, int *);
|
||||
|
||||
int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
/* $Id: minixml.c,v 1.10 2012/03/05 19:42:47 nanard Exp $ */
|
||||
/* minixml.c : the minimum size a xml parser can be ! */
|
||||
/* Project : miniupnp
|
||||
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
|
||||
Copyright (c) 2005-2014, Thomas BERNARD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "minixml.h"
|
||||
|
||||
/* parseatt : used to parse the argument list
|
||||
* return 0 (false) in case of success and -1 (true) if the end
|
||||
* of the xmlbuffer is reached. */
|
||||
static int parseatt(struct xmlparser * p)
|
||||
{
|
||||
const char * attname;
|
||||
int attnamelen;
|
||||
const char * attvalue;
|
||||
int attvaluelen;
|
||||
while(p->xml < p->xmlend)
|
||||
{
|
||||
if(*p->xml=='/' || *p->xml=='>')
|
||||
return 0;
|
||||
if( !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
char sep;
|
||||
attname = p->xml;
|
||||
attnamelen = 0;
|
||||
while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
attnamelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(*(p->xml++) != '=')
|
||||
{
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(IS_WHITE_SPACE(*p->xml))
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
sep = *p->xml;
|
||||
if(sep=='\'' || sep=='\"')
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while(*p->xml != sep)
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& *p->xml != '>' && *p->xml != '/')
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*printf("%.*s='%.*s'\n",
|
||||
attnamelen, attname, attvaluelen, attvalue);*/
|
||||
if(p->attfunc)
|
||||
p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen);
|
||||
}
|
||||
p->xml++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* parseelt parse the xml stream and
|
||||
* call the callback functions when needed... */
|
||||
static void parseelt(struct xmlparser * p)
|
||||
{
|
||||
int i;
|
||||
const char * elementname;
|
||||
while(p->xml < (p->xmlend - 1))
|
||||
{
|
||||
if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "<!--", 4)))
|
||||
{
|
||||
p->xml += 3;
|
||||
/* ignore comments */
|
||||
do
|
||||
{
|
||||
p->xml++;
|
||||
if ((p->xml + 3) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
while(memcmp(p->xml, "-->", 3) != 0);
|
||||
p->xml += 3;
|
||||
}
|
||||
else if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& (*p->xml!='>') && (*p->xml!='/')
|
||||
)
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
/* to ignore namespace : */
|
||||
if(*p->xml==':')
|
||||
{
|
||||
i = 0;
|
||||
elementname = ++p->xml;
|
||||
}
|
||||
}
|
||||
if(i>0)
|
||||
{
|
||||
if(p->starteltfunc)
|
||||
p->starteltfunc(p->data, elementname, i);
|
||||
if(parseatt(p))
|
||||
return;
|
||||
if(*p->xml!='/')
|
||||
{
|
||||
const char * data;
|
||||
i = 0; data = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while( IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(memcmp(p->xml, "<![CDATA[", 9) == 0)
|
||||
{
|
||||
/* CDATA handling */
|
||||
p->xml += 9;
|
||||
data = p->xml;
|
||||
i = 0;
|
||||
while(memcmp(p->xml, "]]>", 3) != 0)
|
||||
{
|
||||
i++; p->xml++;
|
||||
if ((p->xml + 3) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0 && p->datafunc)
|
||||
p->datafunc(p->data, data, i);
|
||||
while(*p->xml!='<')
|
||||
{
|
||||
p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(*p->xml!='<')
|
||||
{
|
||||
i++; p->xml++;
|
||||
if ((p->xml + 1) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0 && p->datafunc && *(p->xml + 1) == '/')
|
||||
p->datafunc(p->data, data, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(*p->xml == '/')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while((*p->xml != '>'))
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(p->endeltfunc)
|
||||
p->endeltfunc(p->data, elementname, i);
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* the parser must be initialized before calling this function */
|
||||
void parsexml(struct xmlparser * parser)
|
||||
{
|
||||
parser->xml = parser->xmlstart;
|
||||
parser->xmlend = parser->xmlstart + parser->xmlsize;
|
||||
parseelt(parser);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/* $Id: minixml.h,v 1.6 2006/11/30 11:47:21 nanard Exp $ */
|
||||
/* minimal xml parser
|
||||
*
|
||||
* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef MINIXML_H_INCLUDED
|
||||
#define MINIXML_H_INCLUDED
|
||||
#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
|
||||
|
||||
/* if a callback function pointer is set to NULL,
|
||||
* the function is not called */
|
||||
struct xmlparser {
|
||||
const char *xmlstart;
|
||||
const char *xmlend;
|
||||
const char *xml; /* pointer to current character */
|
||||
int xmlsize;
|
||||
void * data;
|
||||
void (*starteltfunc) (void *, const char *, int);
|
||||
void (*endeltfunc) (void *, const char *, int);
|
||||
void (*datafunc) (void *, const char *, int);
|
||||
void (*attfunc) (void *, const char *, int, const char *, int);
|
||||
};
|
||||
|
||||
/* parsexml()
|
||||
* the xmlparser structure must be initialized before the call
|
||||
* the following structure members have to be initialized :
|
||||
* xmlstart, xmlsize, data, *func
|
||||
* xml is for internal usage, xmlend is computed automatically */
|
||||
void parsexml(struct xmlparser *);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/* $Id: portlistingparse.c,v 1.9 2015/07/15 12:41:13 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2011-2016 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif /* DEBUG */
|
||||
#include "portlistingparse.h"
|
||||
#include "minixml.h"
|
||||
|
||||
/* list of the elements */
|
||||
static const struct {
|
||||
const portMappingElt code;
|
||||
const char * const str;
|
||||
} elements[] = {
|
||||
{ PortMappingEntry, "PortMappingEntry"},
|
||||
{ NewRemoteHost, "NewRemoteHost"},
|
||||
{ NewExternalPort, "NewExternalPort"},
|
||||
{ NewProtocol, "NewProtocol"},
|
||||
{ NewInternalPort, "NewInternalPort"},
|
||||
{ NewInternalClient, "NewInternalClient"},
|
||||
{ NewEnabled, "NewEnabled"},
|
||||
{ NewDescription, "NewDescription"},
|
||||
{ NewLeaseTime, "NewLeaseTime"},
|
||||
{ PortMappingEltNone, NULL}
|
||||
};
|
||||
|
||||
/* Helper function */
|
||||
static UNSIGNED_INTEGER
|
||||
atoui(const char * p, int l)
|
||||
{
|
||||
UNSIGNED_INTEGER r = 0;
|
||||
while(l > 0 && *p)
|
||||
{
|
||||
if(*p >= '0' && *p <= '9')
|
||||
r = r*10 + (*p - '0');
|
||||
else
|
||||
break;
|
||||
p++;
|
||||
l--;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Start element handler */
|
||||
static void
|
||||
startelt(void * d, const char * name, int l)
|
||||
{
|
||||
int i;
|
||||
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
|
||||
pdata->curelt = PortMappingEltNone;
|
||||
for(i = 0; elements[i].str; i++)
|
||||
{
|
||||
if(strlen(elements[i].str) == (size_t)l && memcmp(name, elements[i].str, l) == 0)
|
||||
{
|
||||
pdata->curelt = elements[i].code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(pdata->curelt == PortMappingEntry)
|
||||
{
|
||||
struct PortMapping * pm;
|
||||
pm = (struct PortMapping*)calloc(1, sizeof(struct PortMapping));
|
||||
if(pm == NULL)
|
||||
{
|
||||
/* malloc error */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: error allocating memory",
|
||||
"startelt");
|
||||
#endif /* DEBUG */
|
||||
return;
|
||||
}
|
||||
pm->l_next = pdata->l_head; /* insert in list */
|
||||
pdata->l_head = pm;
|
||||
}
|
||||
}
|
||||
|
||||
/* End element handler */
|
||||
static void
|
||||
endelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
|
||||
(void)name;
|
||||
(void)l;
|
||||
pdata->curelt = PortMappingEltNone;
|
||||
}
|
||||
|
||||
/* Data handler */
|
||||
static void portlisting_data(void * d, const char * data, int l)
|
||||
{
|
||||
struct PortMapping * pm;
|
||||
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
|
||||
pm = pdata->l_head;
|
||||
if(!pm)
|
||||
return;
|
||||
if(l > 63)
|
||||
l = 63;
|
||||
switch(pdata->curelt)
|
||||
{
|
||||
case NewRemoteHost:
|
||||
memcpy(pm->remoteHost, data, l);
|
||||
pm->remoteHost[l] = '\0';
|
||||
break;
|
||||
case NewExternalPort:
|
||||
pm->externalPort = (unsigned short)atoui(data, l);
|
||||
break;
|
||||
case NewProtocol:
|
||||
if(l > 3)
|
||||
l = 3;
|
||||
memcpy(pm->protocol, data, l);
|
||||
pm->protocol[l] = '\0';
|
||||
break;
|
||||
case NewInternalPort:
|
||||
pm->internalPort = (unsigned short)atoui(data, l);
|
||||
break;
|
||||
case NewInternalClient:
|
||||
memcpy(pm->internalClient, data, l);
|
||||
pm->internalClient[l] = '\0';
|
||||
break;
|
||||
case NewEnabled:
|
||||
pm->enabled = (unsigned char)atoui(data, l);
|
||||
break;
|
||||
case NewDescription:
|
||||
memcpy(pm->description, data, l);
|
||||
pm->description[l] = '\0';
|
||||
break;
|
||||
case NewLeaseTime:
|
||||
pm->leaseTime = atoui(data, l);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Parse the PortMappingList XML document for IGD version 2
|
||||
*/
|
||||
void
|
||||
ParsePortListing(const char * buffer, int bufsize,
|
||||
struct PortMappingParserData * pdata)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
|
||||
memset(pdata, 0, sizeof(struct PortMappingParserData));
|
||||
/* init xmlparser */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = pdata;
|
||||
parser.starteltfunc = startelt;
|
||||
parser.endeltfunc = endelt;
|
||||
parser.datafunc = portlisting_data;
|
||||
parser.attfunc = 0;
|
||||
parsexml(&parser);
|
||||
}
|
||||
|
||||
void
|
||||
FreePortListing(struct PortMappingParserData * pdata)
|
||||
{
|
||||
struct PortMapping * pm;
|
||||
while((pm = pdata->l_head) != NULL)
|
||||
{
|
||||
/* remove from list */
|
||||
pdata->l_head = pm->l_next;
|
||||
free(pm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/* $Id: portlistingparse.h,v 1.10 2014/11/01 10:37:32 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2011-2015 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
#ifndef PORTLISTINGPARSE_H_INCLUDED
|
||||
#define PORTLISTINGPARSE_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_declspec.h"
|
||||
/* for the definition of UNSIGNED_INTEGER */
|
||||
#include "miniupnpctypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* sample of PortMappingEntry :
|
||||
<p:PortMappingEntry>
|
||||
<p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
|
||||
<p:NewExternalPort>2345</p:NewExternalPort>
|
||||
<p:NewProtocol>TCP</p:NewProtocol>
|
||||
<p:NewInternalPort>2345</p:NewInternalPort>
|
||||
<p:NewInternalClient>192.168.1.137</p:NewInternalClient>
|
||||
<p:NewEnabled>1</p:NewEnabled>
|
||||
<p:NewDescription>dooom</p:NewDescription>
|
||||
<p:NewLeaseTime>345</p:NewLeaseTime>
|
||||
</p:PortMappingEntry>
|
||||
*/
|
||||
typedef enum { PortMappingEltNone,
|
||||
PortMappingEntry, NewRemoteHost,
|
||||
NewExternalPort, NewProtocol,
|
||||
NewInternalPort, NewInternalClient,
|
||||
NewEnabled, NewDescription,
|
||||
NewLeaseTime } portMappingElt;
|
||||
|
||||
struct PortMapping {
|
||||
struct PortMapping * l_next; /* list next element */
|
||||
UNSIGNED_INTEGER leaseTime;
|
||||
unsigned short externalPort;
|
||||
unsigned short internalPort;
|
||||
char remoteHost[64];
|
||||
char internalClient[64];
|
||||
char description[64];
|
||||
char protocol[4];
|
||||
unsigned char enabled;
|
||||
};
|
||||
|
||||
struct PortMappingParserData {
|
||||
struct PortMapping * l_head; /* list head */
|
||||
portMappingElt curelt;
|
||||
};
|
||||
|
||||
MINIUPNP_LIBSPEC void
|
||||
ParsePortListing(const char * buffer, int bufsize,
|
||||
struct PortMappingParserData * pdata);
|
||||
|
||||
MINIUPNP_LIBSPEC void
|
||||
FreePortListing(struct PortMappingParserData * pdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
/* $Id: receivedata.c,v 1.7 2015/11/09 21:51:41 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2011-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else /* _WIN32 */
|
||||
#include <unistd.h>
|
||||
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#define socklen_t int
|
||||
#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/select.h>
|
||||
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#if !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#include <poll.h>
|
||||
#endif /* !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <errno.h>
|
||||
#define MINIUPNPC_IGNORE_EINTR
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
|
||||
#else
|
||||
#define PRINT_SOCKET_ERROR(x) perror(x)
|
||||
#endif
|
||||
|
||||
#include "receivedata.h"
|
||||
|
||||
int
|
||||
receivedata(int socket,
|
||||
char * data, int length,
|
||||
int timeout, unsigned int * scope_id)
|
||||
{
|
||||
#ifdef MINIUPNPC_GET_SRC_ADDR
|
||||
struct sockaddr_storage src_addr;
|
||||
socklen_t src_addr_len = sizeof(src_addr);
|
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */
|
||||
int n;
|
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
/* using poll */
|
||||
struct pollfd fds[1]; /* for the poll */
|
||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||
do {
|
||||
#endif /* MINIUPNPC_IGNORE_EINTR */
|
||||
fds[0].fd = socket;
|
||||
fds[0].events = POLLIN;
|
||||
n = poll(fds, 1, timeout);
|
||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||
} while(n < 0 && errno == EINTR);
|
||||
#endif /* MINIUPNPC_IGNORE_EINTR */
|
||||
if(n < 0) {
|
||||
PRINT_SOCKET_ERROR("poll");
|
||||
return -1;
|
||||
} else if(n == 0) {
|
||||
/* timeout */
|
||||
return 0;
|
||||
}
|
||||
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
/* using select under _WIN32 and amigaos */
|
||||
fd_set socketSet;
|
||||
TIMEVAL timeval;
|
||||
FD_ZERO(&socketSet);
|
||||
FD_SET(socket, &socketSet);
|
||||
timeval.tv_sec = timeout / 1000;
|
||||
timeval.tv_usec = (timeout % 1000) * 1000;
|
||||
n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval);
|
||||
if(n < 0) {
|
||||
PRINT_SOCKET_ERROR("select");
|
||||
return -1;
|
||||
} else if(n == 0) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#ifdef MINIUPNPC_GET_SRC_ADDR
|
||||
memset(&src_addr, 0, sizeof(src_addr));
|
||||
n = recvfrom(socket, data, length, 0,
|
||||
(struct sockaddr *)&src_addr, &src_addr_len);
|
||||
#else /* MINIUPNPC_GET_SRC_ADDR */
|
||||
n = (int)recv(socket, data, length, 0);
|
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */
|
||||
if(n<0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("recv");
|
||||
}
|
||||
#ifdef MINIUPNPC_GET_SRC_ADDR
|
||||
if (src_addr.ss_family == AF_INET6) {
|
||||
const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr;
|
||||
#ifdef DEBUG
|
||||
printf("scope_id=%u\n", src_addr6->sin6_scope_id);
|
||||
#endif /* DEBUG */
|
||||
if(scope_id)
|
||||
*scope_id = src_addr6->sin6_scope_id;
|
||||
}
|
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/* $Id: receivedata.h,v 1.3 2012/06/23 22:34:47 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2011-2012 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef RECEIVEDATA_H_INCLUDED
|
||||
#define RECEIVEDATA_H_INCLUDED
|
||||
|
||||
/* Reads data from the specified socket.
|
||||
* Returns the number of bytes read if successful, zero if no bytes were
|
||||
* read or if we timed out. Returns negative if there was an error. */
|
||||
int receivedata(int socket,
|
||||
char * data, int length,
|
||||
int timeout, unsigned int * scope_id);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#! /bin/sh
|
||||
# $Id: updateminiupnpcstrings.sh,v 1.7 2011/01/04 11:41:53 nanard Exp $
|
||||
# project miniupnp : http://miniupnp.free.fr/
|
||||
# (c) 2009 Thomas Bernard
|
||||
|
||||
FILE=miniupnpcstrings.h
|
||||
TMPFILE=miniupnpcstrings.h.tmp
|
||||
TEMPLATE_FILE=${FILE}.in
|
||||
|
||||
# detecting the OS name and version
|
||||
OS_NAME=`uname -s`
|
||||
OS_VERSION=`uname -r`
|
||||
if [ -f /etc/debian_version ]; then
|
||||
OS_NAME=Debian
|
||||
OS_VERSION=`cat /etc/debian_version`
|
||||
fi
|
||||
# use lsb_release (Linux Standard Base) when available
|
||||
LSB_RELEASE=`which lsb_release`
|
||||
if [ 0 -eq $? -a -x "${LSB_RELEASE}" ]; then
|
||||
OS_NAME=`${LSB_RELEASE} -i -s`
|
||||
OS_VERSION=`${LSB_RELEASE} -r -s`
|
||||
case $OS_NAME in
|
||||
Debian)
|
||||
#OS_VERSION=`${LSB_RELEASE} -c -s`
|
||||
;;
|
||||
Ubuntu)
|
||||
#OS_VERSION=`${LSB_RELEASE} -c -s`
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# on AmigaOS 3, uname -r returns "unknown", so we use uname -v
|
||||
if [ "$OS_NAME" = "AmigaOS" ]; then
|
||||
if [ "$OS_VERSION" = "unknown" ]; then
|
||||
OS_VERSION=`uname -v`
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Detected OS [$OS_NAME] version [$OS_VERSION]"
|
||||
MINIUPNPC_VERSION=`cat VERSION`
|
||||
echo "MiniUPnPc version [${MINIUPNPC_VERSION}]"
|
||||
|
||||
EXPR="s|OS_STRING \".*\"|OS_STRING \"${OS_NAME}/${OS_VERSION}\"|"
|
||||
#echo $EXPR
|
||||
test -f ${FILE}.in
|
||||
echo "setting OS_STRING macro value to ${OS_NAME}/${OS_VERSION} in $FILE."
|
||||
sed -e "$EXPR" < $TEMPLATE_FILE > $TMPFILE
|
||||
|
||||
EXPR="s|MINIUPNPC_VERSION_STRING \".*\"|MINIUPNPC_VERSION_STRING \"${MINIUPNPC_VERSION}\"|"
|
||||
echo "setting MINIUPNPC_VERSION_STRING macro value to ${MINIUPNPC_VERSION} in $FILE."
|
||||
sed -e "$EXPR" < $TMPFILE > $FILE
|
||||
rm $TMPFILE
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
/* $Id: upnpcommands.h,v 1.30 2015/07/15 12:21:28 nanard Exp $ */
|
||||
/* Miniupnp project : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided within this distribution */
|
||||
#ifndef UPNPCOMMANDS_H_INCLUDED
|
||||
#define UPNPCOMMANDS_H_INCLUDED
|
||||
|
||||
#include "upnpreplyparse.h"
|
||||
#include "portlistingparse.h"
|
||||
#include "miniupnpc_declspec.h"
|
||||
#include "miniupnpctypes.h"
|
||||
|
||||
/* MiniUPnPc return codes : */
|
||||
#define UPNPCOMMAND_SUCCESS (0)
|
||||
#define UPNPCOMMAND_UNKNOWN_ERROR (-1)
|
||||
#define UPNPCOMMAND_INVALID_ARGS (-2)
|
||||
#define UPNPCOMMAND_HTTP_ERROR (-3)
|
||||
#define UPNPCOMMAND_INVALID_RESPONSE (-4)
|
||||
#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalBytesSent(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalBytesReceived(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalPacketsSent(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalPacketsReceived(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
/* UPNP_GetStatusInfo()
|
||||
* status and lastconnerror are 64 byte buffers
|
||||
* Return values :
|
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||
* or a UPnP Error code */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetStatusInfo(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * status,
|
||||
unsigned int * uptime,
|
||||
char * lastconnerror);
|
||||
|
||||
/* UPNP_GetConnectionTypeInfo()
|
||||
* argument connectionType is a 64 character buffer
|
||||
* Return Values :
|
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||
* or a UPnP Error code */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetConnectionTypeInfo(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * connectionType);
|
||||
|
||||
/* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
|
||||
* if the third arg is not null the value is copied to it.
|
||||
* at least 16 bytes must be available
|
||||
*
|
||||
* Return values :
|
||||
* 0 : SUCCESS
|
||||
* NON ZERO : ERROR Either an UPnP error code or an unknown error.
|
||||
*
|
||||
* possible UPnP Errors :
|
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||
* 501 Action Failed - See UPnP Device Architecture section on Control. */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetExternalIPAddress(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * extIpAdd);
|
||||
|
||||
/* UPNP_GetLinkLayerMaxBitRates()
|
||||
* call WANCommonInterfaceConfig:1#GetCommonLinkProperties
|
||||
*
|
||||
* return values :
|
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||
* or a UPnP Error Code. */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
|
||||
const char* servicetype,
|
||||
unsigned int * bitrateDown,
|
||||
unsigned int * bitrateUp);
|
||||
|
||||
/* UPNP_AddPortMapping()
|
||||
* if desc is NULL, it will be defaulted to "libminiupnpc"
|
||||
* remoteHost is usually NULL because IGD don't support it.
|
||||
*
|
||||
* Return values :
|
||||
* 0 : SUCCESS
|
||||
* NON ZERO : ERROR. Either an UPnP error code or an unknown error.
|
||||
*
|
||||
* List of possible UPnP errors for AddPortMapping :
|
||||
* errorCode errorDescription (short) - Description (long)
|
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||
* 501 Action Failed - See UPnP Device Architecture section on Control.
|
||||
* 606 Action not authorized - The action requested REQUIRES authorization and
|
||||
* the sender was not authorized.
|
||||
* 715 WildCardNotPermittedInSrcIP - The source IP address cannot be
|
||||
* wild-carded
|
||||
* 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded
|
||||
* 718 ConflictInMappingEntry - The port mapping entry specified conflicts
|
||||
* with a mapping assigned previously to another client
|
||||
* 724 SamePortValuesRequired - Internal and External port values
|
||||
* must be the same
|
||||
* 725 OnlyPermanentLeasesSupported - The NAT implementation only supports
|
||||
* permanent lease times on port mappings
|
||||
* 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard
|
||||
* and cannot be a specific IP address or DNS name
|
||||
* 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and
|
||||
* cannot be a specific port value
|
||||
* 728 NoPortMapsAvailable - There are not enough free ports available to
|
||||
* complete port mapping.
|
||||
* 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed
|
||||
* due to conflict with other mechanisms.
|
||||
* 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * inPort,
|
||||
const char * inClient,
|
||||
const char * desc,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
const char * leaseDuration);
|
||||
|
||||
/* UPNP_AddAnyPortMapping()
|
||||
* if desc is NULL, it will be defaulted to "libminiupnpc"
|
||||
* remoteHost is usually NULL because IGD don't support it.
|
||||
*
|
||||
* Return values :
|
||||
* 0 : SUCCESS
|
||||
* NON ZERO : ERROR. Either an UPnP error code or an unknown error.
|
||||
*
|
||||
* List of possible UPnP errors for AddPortMapping :
|
||||
* errorCode errorDescription (short) - Description (long)
|
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||
* 501 Action Failed - See UPnP Device Architecture section on Control.
|
||||
* 606 Action not authorized - The action requested REQUIRES authorization and
|
||||
* the sender was not authorized.
|
||||
* 715 WildCardNotPermittedInSrcIP - The source IP address cannot be
|
||||
* wild-carded
|
||||
* 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded
|
||||
* 728 NoPortMapsAvailable - There are not enough free ports available to
|
||||
* complete port mapping.
|
||||
* 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed
|
||||
* due to conflict with other mechanisms.
|
||||
* 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * inPort,
|
||||
const char * inClient,
|
||||
const char * desc,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
const char * leaseDuration,
|
||||
char * reservedPort);
|
||||
|
||||
/* UPNP_DeletePortMapping()
|
||||
* Use same argument values as what was used for AddPortMapping().
|
||||
* remoteHost is usually NULL because IGD don't support it.
|
||||
* Return Values :
|
||||
* 0 : SUCCESS
|
||||
* NON ZERO : error. Either an UPnP error code or an undefined error.
|
||||
*
|
||||
* List of possible UPnP errors for DeletePortMapping :
|
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||
* 606 Action not authorized - The action requested REQUIRES authorization
|
||||
* and the sender was not authorized.
|
||||
* 714 NoSuchEntryInArray - The specified value does not exist in the array */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort, const char * proto,
|
||||
const char * remoteHost);
|
||||
|
||||
/* UPNP_DeletePortRangeMapping()
|
||||
* Use same argument values as what was used for AddPortMapping().
|
||||
* remoteHost is usually NULL because IGD don't support it.
|
||||
* Return Values :
|
||||
* 0 : SUCCESS
|
||||
* NON ZERO : error. Either an UPnP error code or an undefined error.
|
||||
*
|
||||
* List of possible UPnP errors for DeletePortMapping :
|
||||
* 606 Action not authorized - The action requested REQUIRES authorization
|
||||
* and the sender was not authorized.
|
||||
* 730 PortMappingNotFound - This error message is returned if no port
|
||||
* mapping is found in the specified range.
|
||||
* 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
|
||||
const char * extPortStart, const char * extPortEnd,
|
||||
const char * proto,
|
||||
const char * manage);
|
||||
|
||||
/* UPNP_GetPortMappingNumberOfEntries()
|
||||
* not supported by all routers */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetPortMappingNumberOfEntries(const char* controlURL,
|
||||
const char* servicetype,
|
||||
unsigned int * num);
|
||||
|
||||
/* UPNP_GetSpecificPortMappingEntry()
|
||||
* retrieves an existing port mapping
|
||||
* params :
|
||||
* in extPort
|
||||
* in proto
|
||||
* in remoteHost
|
||||
* out intClient (16 bytes)
|
||||
* out intPort (6 bytes)
|
||||
* out desc (80 bytes)
|
||||
* out enabled (4 bytes)
|
||||
* out leaseDuration (16 bytes)
|
||||
*
|
||||
* return value :
|
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||
* or a UPnP Error Code.
|
||||
*
|
||||
* List of possible UPnP errors for _GetSpecificPortMappingEntry :
|
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||
* 501 Action Failed - See UPnP Device Architecture section on Control.
|
||||
* 606 Action not authorized - The action requested REQUIRES authorization
|
||||
* and the sender was not authorized.
|
||||
* 714 NoSuchEntryInArray - The specified value does not exist in the array.
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
char * intClient,
|
||||
char * intPort,
|
||||
char * desc,
|
||||
char * enabled,
|
||||
char * leaseDuration);
|
||||
|
||||
/* UPNP_GetGenericPortMappingEntry()
|
||||
* params :
|
||||
* in index
|
||||
* out extPort (6 bytes)
|
||||
* out intClient (16 bytes)
|
||||
* out intPort (6 bytes)
|
||||
* out protocol (4 bytes)
|
||||
* out desc (80 bytes)
|
||||
* out enabled (4 bytes)
|
||||
* out rHost (64 bytes)
|
||||
* out duration (16 bytes)
|
||||
*
|
||||
* return value :
|
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||
* or a UPnP Error Code.
|
||||
*
|
||||
* Possible UPNP Error codes :
|
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||
* 606 Action not authorized - The action requested REQUIRES authorization
|
||||
* and the sender was not authorized.
|
||||
* 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetGenericPortMappingEntry(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * index,
|
||||
char * extPort,
|
||||
char * intClient,
|
||||
char * intPort,
|
||||
char * protocol,
|
||||
char * desc,
|
||||
char * enabled,
|
||||
char * rHost,
|
||||
char * duration);
|
||||
|
||||
/* UPNP_GetListOfPortMappings() Available in IGD v2
|
||||
*
|
||||
*
|
||||
* Possible UPNP Error codes :
|
||||
* 606 Action not Authorized
|
||||
* 730 PortMappingNotFound - no port mapping is found in the specified range.
|
||||
* 733 InconsistantParameters - NewStartPort and NewEndPort values are not
|
||||
* consistent.
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetListOfPortMappings(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * startPort,
|
||||
const char * endPort,
|
||||
const char * protocol,
|
||||
const char * numberOfPorts,
|
||||
struct PortMappingParserData * data);
|
||||
|
||||
/* IGD:2, functions for service WANIPv6FirewallControl:1 */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetFirewallStatus(const char * controlURL,
|
||||
const char * servicetype,
|
||||
int * firewallEnabled,
|
||||
int * inboundPinholeAllowed);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype,
|
||||
const char * remoteHost,
|
||||
const char * remotePort,
|
||||
const char * intClient,
|
||||
const char * intPort,
|
||||
const char * proto,
|
||||
int * opTimeout);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_AddPinhole(const char * controlURL, const char * servicetype,
|
||||
const char * remoteHost,
|
||||
const char * remotePort,
|
||||
const char * intClient,
|
||||
const char * intPort,
|
||||
const char * proto,
|
||||
const char * leaseTime,
|
||||
char * uniqueID);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID,
|
||||
const char * leaseTime);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID, int * isWorking);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID, int * packets);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENSE file. */
|
||||
#include <stdlib.h>
|
||||
#include "upnpdev.h"
|
||||
|
||||
/* freeUPNPDevlist() should be used to
|
||||
* free the chained list returned by upnpDiscover() */
|
||||
void freeUPNPDevlist(struct UPNPDev * devlist)
|
||||
{
|
||||
struct UPNPDev * next;
|
||||
while(devlist)
|
||||
{
|
||||
next = devlist->pNext;
|
||||
free(devlist);
|
||||
devlist = next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENSE file. */
|
||||
#ifndef UPNPDEV_H_INCLUDED
|
||||
#define UPNPDEV_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_declspec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct UPNPDev {
|
||||
struct UPNPDev * pNext;
|
||||
char * descURL;
|
||||
char * st;
|
||||
unsigned int scope_id;
|
||||
char * usn;
|
||||
char buffer[3];
|
||||
};
|
||||
|
||||
/* freeUPNPDevlist()
|
||||
* free list returned by upnpDiscover() */
|
||||
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UPNPDEV_H_INCLUDED */
|
||||
@@ -0,0 +1,107 @@
|
||||
/* $Id: upnperrors.c,v 1.5 2011/04/10 11:19:36 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2007 Thomas Bernard
|
||||
* All Right reserved.
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENCE file. */
|
||||
#include <string.h>
|
||||
#include "upnperrors.h"
|
||||
#include "upnpcommands.h"
|
||||
#include "miniupnpc.h"
|
||||
|
||||
const char * strupnperror(int err)
|
||||
{
|
||||
const char * s = NULL;
|
||||
switch(err) {
|
||||
case UPNPCOMMAND_SUCCESS:
|
||||
s = "Success";
|
||||
break;
|
||||
case UPNPCOMMAND_UNKNOWN_ERROR:
|
||||
s = "Miniupnpc Unknown Error";
|
||||
break;
|
||||
case UPNPCOMMAND_INVALID_ARGS:
|
||||
s = "Miniupnpc Invalid Arguments";
|
||||
break;
|
||||
case UPNPCOMMAND_INVALID_RESPONSE:
|
||||
s = "Miniupnpc Invalid response";
|
||||
break;
|
||||
case UPNPDISCOVER_SOCKET_ERROR:
|
||||
s = "Miniupnpc Socket error";
|
||||
break;
|
||||
case UPNPDISCOVER_MEMORY_ERROR:
|
||||
s = "Miniupnpc Memory allocation error";
|
||||
break;
|
||||
case 401:
|
||||
s = "Invalid Action";
|
||||
break;
|
||||
case 402:
|
||||
s = "Invalid Args";
|
||||
break;
|
||||
case 501:
|
||||
s = "Action Failed";
|
||||
break;
|
||||
case 606:
|
||||
s = "Action not authorized";
|
||||
break;
|
||||
case 701:
|
||||
s = "PinholeSpaceExhausted";
|
||||
break;
|
||||
case 702:
|
||||
s = "FirewallDisabled";
|
||||
break;
|
||||
case 703:
|
||||
s = "InboundPinholeNotAllowed";
|
||||
break;
|
||||
case 704:
|
||||
s = "NoSuchEntry";
|
||||
break;
|
||||
case 705:
|
||||
s = "ProtocolNotSupported";
|
||||
break;
|
||||
case 706:
|
||||
s = "InternalPortWildcardingNotAllowed";
|
||||
break;
|
||||
case 707:
|
||||
s = "ProtocolWildcardingNotAllowed";
|
||||
break;
|
||||
case 708:
|
||||
s = "WildcardNotPermittedInSrcIP";
|
||||
break;
|
||||
case 709:
|
||||
s = "NoPacketSent";
|
||||
break;
|
||||
case 713:
|
||||
s = "SpecifiedArrayIndexInvalid";
|
||||
break;
|
||||
case 714:
|
||||
s = "NoSuchEntryInArray";
|
||||
break;
|
||||
case 715:
|
||||
s = "WildCardNotPermittedInSrcIP";
|
||||
break;
|
||||
case 716:
|
||||
s = "WildCardNotPermittedInExtPort";
|
||||
break;
|
||||
case 718:
|
||||
s = "ConflictInMappingEntry";
|
||||
break;
|
||||
case 724:
|
||||
s = "SamePortValuesRequired";
|
||||
break;
|
||||
case 725:
|
||||
s = "OnlyPermanentLeasesSupported";
|
||||
break;
|
||||
case 726:
|
||||
s = "RemoteHostOnlySupportsWildcard";
|
||||
break;
|
||||
case 727:
|
||||
s = "ExternalPortOnlySupportsWildcard";
|
||||
break;
|
||||
default:
|
||||
s = "UnknownError";
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 nanard Exp $ */
|
||||
/* (c) 2007-2015 Thomas Bernard
|
||||
* All rights reserved.
|
||||
* MiniUPnP Project.
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENCE file. */
|
||||
#ifndef UPNPERRORS_H_INCLUDED
|
||||
#define UPNPERRORS_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_declspec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* strupnperror()
|
||||
* Return a string description of the UPnP error code
|
||||
* or NULL for undefinded errors */
|
||||
MINIUPNP_LIBSPEC const char * strupnperror(int err);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,197 @@
|
||||
/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2015 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "upnpreplyparse.h"
|
||||
#include "minixml.h"
|
||||
|
||||
static void
|
||||
NameValueParserStartElt(void * d, const char * name, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
data->topelt = 1;
|
||||
if(l>63)
|
||||
l = 63;
|
||||
memcpy(data->curelt, name, l);
|
||||
data->curelt[l] = '\0';
|
||||
data->cdata = NULL;
|
||||
data->cdatalen = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
NameValueParserEndElt(void * d, const char * name, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
struct NameValue * nv;
|
||||
(void)name;
|
||||
(void)l;
|
||||
if(!data->topelt)
|
||||
return;
|
||||
if(strcmp(data->curelt, "NewPortListing") != 0)
|
||||
{
|
||||
int l;
|
||||
/* standard case. Limited to n chars strings */
|
||||
l = data->cdatalen;
|
||||
nv = (struct NameValue*)malloc(sizeof(struct NameValue));
|
||||
if(nv == NULL)
|
||||
{
|
||||
/* malloc error */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: error allocating memory",
|
||||
"NameValueParserEndElt");
|
||||
#endif /* DEBUG */
|
||||
return;
|
||||
}
|
||||
if(l>=(int)sizeof(nv->value))
|
||||
l = sizeof(nv->value) - 1;
|
||||
strncpy(nv->name, data->curelt, 64);
|
||||
nv->name[63] = '\0';
|
||||
if(data->cdata != NULL)
|
||||
{
|
||||
memcpy(nv->value, data->cdata, l);
|
||||
nv->value[l] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
nv->value[0] = '\0';
|
||||
}
|
||||
nv->l_next = data->l_head; /* insert in list */
|
||||
data->l_head = nv;
|
||||
}
|
||||
data->cdata = NULL;
|
||||
data->cdatalen = 0;
|
||||
data->topelt = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
NameValueParserGetData(void * d, const char * datas, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
if(strcmp(data->curelt, "NewPortListing") == 0)
|
||||
{
|
||||
/* specific case for NewPortListing which is a XML Document */
|
||||
data->portListing = (char*)malloc(l + 1);
|
||||
if(!data->portListing)
|
||||
{
|
||||
/* malloc error */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: error allocating memory",
|
||||
"NameValueParserGetData");
|
||||
#endif /* DEBUG */
|
||||
return;
|
||||
}
|
||||
memcpy(data->portListing, datas, l);
|
||||
data->portListing[l] = '\0';
|
||||
data->portListingLength = l;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* standard case. */
|
||||
data->cdata = datas;
|
||||
data->cdatalen = l;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParseNameValue(const char * buffer, int bufsize,
|
||||
struct NameValueParserData * data)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
data->l_head = NULL;
|
||||
data->portListing = NULL;
|
||||
data->portListingLength = 0;
|
||||
/* init xmlparser object */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = data;
|
||||
parser.starteltfunc = NameValueParserStartElt;
|
||||
parser.endeltfunc = NameValueParserEndElt;
|
||||
parser.datafunc = NameValueParserGetData;
|
||||
parser.attfunc = 0;
|
||||
parsexml(&parser);
|
||||
}
|
||||
|
||||
void
|
||||
ClearNameValueList(struct NameValueParserData * pdata)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
if(pdata->portListing)
|
||||
{
|
||||
free(pdata->portListing);
|
||||
pdata->portListing = NULL;
|
||||
pdata->portListingLength = 0;
|
||||
}
|
||||
while((nv = pdata->l_head) != NULL)
|
||||
{
|
||||
pdata->l_head = nv->l_next;
|
||||
free(nv);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||
const char * Name)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
char * p = NULL;
|
||||
for(nv = pdata->l_head;
|
||||
(nv != NULL) && (p == NULL);
|
||||
nv = nv->l_next)
|
||||
{
|
||||
if(strcmp(nv->name, Name) == 0)
|
||||
p = nv->value;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* useless now that minixml ignores namespaces by itself */
|
||||
char *
|
||||
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||
const char * Name)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
char * p = NULL;
|
||||
char * pname;
|
||||
for(nv = pdata->head.lh_first;
|
||||
(nv != NULL) && (p == NULL);
|
||||
nv = nv->entries.le_next)
|
||||
{
|
||||
pname = strrchr(nv->name, ':');
|
||||
if(pname)
|
||||
pname++;
|
||||
else
|
||||
pname = nv->name;
|
||||
if(strcmp(pname, Name)==0)
|
||||
p = nv->value;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* debug all-in-one function
|
||||
* do parsing then display to stdout */
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DisplayNameValueList(char * buffer, int bufsize)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
struct NameValue * nv;
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
for(nv = pdata.l_head;
|
||||
nv != NULL;
|
||||
nv = nv->l_next)
|
||||
{
|
||||
printf("%s = %s\n", nv->name, nv->value);
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2013 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#ifndef UPNPREPLYPARSE_H_INCLUDED
|
||||
#define UPNPREPLYPARSE_H_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct NameValue {
|
||||
struct NameValue * l_next;
|
||||
char name[64];
|
||||
char value[128];
|
||||
};
|
||||
|
||||
struct NameValueParserData {
|
||||
struct NameValue * l_head;
|
||||
char curelt[64];
|
||||
char * portListing;
|
||||
int portListingLength;
|
||||
int topelt;
|
||||
const char * cdata;
|
||||
int cdatalen;
|
||||
};
|
||||
|
||||
/* ParseNameValue() */
|
||||
void
|
||||
ParseNameValue(const char * buffer, int bufsize,
|
||||
struct NameValueParserData * data);
|
||||
|
||||
/* ClearNameValueList() */
|
||||
void
|
||||
ClearNameValueList(struct NameValueParserData * pdata);
|
||||
|
||||
/* GetValueFromNameValueList() */
|
||||
char *
|
||||
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||
const char * Name);
|
||||
|
||||
#if 0
|
||||
/* GetValueFromNameValueListIgnoreNS() */
|
||||
char *
|
||||
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||
const char * Name);
|
||||
#endif
|
||||
|
||||
/* DisplayNameValueList() */
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DisplayNameValueList(char * buffer, int bufsize);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHEEVOS
|
||||
#include "cheevos.h"
|
||||
#include "cheevos/cheevos.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETWORKING
|
||||
@@ -252,7 +252,6 @@ static bool load_dynamic_core(void)
|
||||
RARCH_ERR("Error(s): %s\n", dylib_error());
|
||||
|
||||
runloop_msg_queue_push(msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE), 1, 180, true);
|
||||
retroarch_fail(1, "load_dynamic_core()");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ static dylib_t dwmlib;
|
||||
|
||||
static bool dwm_composition_disabled;
|
||||
|
||||
static bool console_needs_free;
|
||||
|
||||
static void gfx_dwm_shutdown(void)
|
||||
{
|
||||
if (dwmlib)
|
||||
@@ -345,13 +347,34 @@ static void frontend_win32_attach_console(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32_WINNT_WINXP
|
||||
if (!AttachConsole(ATTACH_PARENT_PROCESS))
|
||||
|
||||
/* msys will start the process with FILE_TYPE_PIPE connected.
|
||||
* cmd will start the process with FILE_TYPE_UNKNOWN connected (since this is subsystem windows application
|
||||
* ... UNLESS stdout/stderr were redirected (then FILE_TYPE_DISK will be connected most likely)
|
||||
* explorer will start the process with NOTHING connected.
|
||||
*
|
||||
* Now, let's not reconnect anything that's already connected.
|
||||
* If any are disconnected, open a console, and connect to them.
|
||||
* In case we're launched from msys or cmd, try attaching to the parent process console first.
|
||||
* Take care to leave a record of what we did, so we can undo it precisely
|
||||
*/
|
||||
|
||||
bool need_stdout = (GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == FILE_TYPE_UNKNOWN);
|
||||
bool need_stderr = (GetFileType(GetStdHandle(STD_ERROR_HANDLE)) == FILE_TYPE_UNKNOWN);
|
||||
|
||||
if(need_stdout || need_stderr)
|
||||
{
|
||||
AllocConsole();
|
||||
AttachConsole( GetCurrentProcessId()) ;
|
||||
freopen( "CON", "w", stdout );
|
||||
freopen( "CON", "w", stderr );
|
||||
if(!AttachConsole( ATTACH_PARENT_PROCESS))
|
||||
{
|
||||
AllocConsole();
|
||||
}
|
||||
|
||||
if(need_stdout) freopen( "CONOUT$", "w", stdout );
|
||||
if(need_stderr) freopen( "CONOUT$", "w", stderr );
|
||||
|
||||
console_needs_free = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -360,12 +383,15 @@ static void frontend_win32_detach_console(void)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#ifdef _WIN32_WINNT_WINXP
|
||||
if (!AttachConsole(ATTACH_PARENT_PROCESS))
|
||||
|
||||
if(console_needs_free)
|
||||
{
|
||||
HWND wnd = GetConsoleWindow();
|
||||
/* we don't reconnect stdout/stderr to anything here, because by definition, they weren't connected to anything in the first place. */
|
||||
|
||||
FreeConsole();
|
||||
PostMessage(wnd, WM_CLOSE, 0, 0);
|
||||
console_needs_free = false;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -110,12 +110,11 @@ int rarch_main(int argc, char *argv[], void *data)
|
||||
info.args = args;
|
||||
info.environ_get = frontend_driver_environment_get_ptr();
|
||||
|
||||
if (!task_push_content_load_default(
|
||||
if (!task_push_load_content_from_cli(
|
||||
NULL,
|
||||
NULL,
|
||||
&info,
|
||||
CORE_TYPE_PLAIN,
|
||||
CONTENT_MODE_LOAD_FROM_CLI,
|
||||
NULL,
|
||||
NULL))
|
||||
return 1;
|
||||
|
||||
@@ -1800,7 +1800,7 @@ static bool vulkan_create_display_surface(gfx_ctx_vulkan_data_t *vk,
|
||||
VkDisplayModePropertiesKHR *modes = NULL;
|
||||
unsigned dpy, i, j;
|
||||
uint32_t best_plane = UINT32_MAX;
|
||||
VkDisplayPlaneAlphaFlagsKHR alpha_mode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
|
||||
VkDisplayPlaneAlphaFlagBitsKHR alpha_mode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
|
||||
VkDisplaySurfaceCreateInfoKHR create_info = { VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR };
|
||||
VkDisplayModeKHR best_mode = VK_NULL_HANDLE;
|
||||
|
||||
@@ -1937,9 +1937,7 @@ out:
|
||||
create_info.planeStackIndex = planes[best_plane].currentStackIndex;
|
||||
create_info.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
create_info.globalAlpha = 1.0f;
|
||||
/* TODO/FIXME - why is this cast needed for CXX_BUILD? Why is
|
||||
* alpha_mode not just VkDisplayPlaneAlphaFlagBitsKHR to begin with? */
|
||||
create_info.alphaMode = (VkDisplayPlaneAlphaFlagBitsKHR)alpha_mode;
|
||||
create_info.alphaMode = alpha_mode;
|
||||
create_info.imageExtent.width = *width;
|
||||
create_info.imageExtent.height = *height;
|
||||
|
||||
@@ -2271,6 +2269,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||
VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
|
||||
VkPresentModeKHR swapchain_present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
settings_t *settings = config_get_ptr();
|
||||
VkCompositeAlphaFlagBitsKHR composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
|
||||
vkDeviceWaitIdle(vk->context.device);
|
||||
|
||||
@@ -2325,6 +2324,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(vk->context.gpu,
|
||||
vk->vk_surface, &format_count, formats);
|
||||
|
||||
format.format = VK_FORMAT_UNDEFINED;
|
||||
if (format_count == 1 && formats[0].format == VK_FORMAT_UNDEFINED)
|
||||
{
|
||||
format = formats[0];
|
||||
@@ -2338,7 +2338,19 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||
return false;
|
||||
}
|
||||
|
||||
format = formats[0];
|
||||
for (i = 0; i < format_count; i++)
|
||||
{
|
||||
if (
|
||||
formats[i].format == VK_FORMAT_R8G8B8A8_UNORM ||
|
||||
formats[i].format == VK_FORMAT_B8G8R8A8_UNORM ||
|
||||
formats[i].format == VK_FORMAT_A8B8G8R8_UNORM_PACK32)
|
||||
{
|
||||
format = formats[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (format.format == VK_FORMAT_UNDEFINED)
|
||||
format = formats[0];
|
||||
}
|
||||
|
||||
if (surface_properties.currentExtent.width == -1)
|
||||
@@ -2371,6 +2383,15 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||
else
|
||||
pre_transform = surface_properties.currentTransform;
|
||||
|
||||
if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
|
||||
composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
else if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
|
||||
composite = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
|
||||
else if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
|
||||
composite = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
|
||||
else if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
|
||||
composite = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
|
||||
|
||||
old_swapchain = vk->swapchain;
|
||||
|
||||
info.surface = vk->vk_surface;
|
||||
@@ -2382,7 +2403,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||
info.imageArrayLayers = 1;
|
||||
info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
info.preTransform = pre_transform;
|
||||
info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
info.compositeAlpha = composite;
|
||||
info.presentMode = swapchain_present_mode;
|
||||
info.clipped = true;
|
||||
info.oldSwapchain = old_swapchain;
|
||||
|
||||
@@ -331,7 +331,7 @@ typedef struct vk
|
||||
struct
|
||||
{
|
||||
bool blend;
|
||||
VkPipeline pipelines[8];
|
||||
VkPipeline pipelines[7 * 2];
|
||||
struct vk_texture blank_texture;
|
||||
} display;
|
||||
|
||||
|
||||
@@ -316,11 +316,10 @@ static int win32_drag_query_file(HWND hwnd, WPARAM wparam)
|
||||
{
|
||||
/* Our previous core supports the current rom */
|
||||
content_ctx_info_t content_info = {0};
|
||||
task_push_content_load_default(
|
||||
NULL, NULL,
|
||||
task_push_load_content_with_current_core_from_companion_ui(
|
||||
NULL,
|
||||
&content_info,
|
||||
CORE_TYPE_PLAIN,
|
||||
CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_COMPANION_UI,
|
||||
NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
@@ -334,11 +333,9 @@ static int win32_drag_query_file(HWND hwnd, WPARAM wparam)
|
||||
const core_info_t *info = (const core_info_t*)&core_info[0];
|
||||
|
||||
if (info)
|
||||
task_push_content_load_default(
|
||||
task_push_load_content_with_new_core_from_companion_ui(
|
||||
info->path, NULL,
|
||||
&content_info,
|
||||
CORE_TYPE_PLAIN,
|
||||
CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_COMPANION_UI,
|
||||
NULL, NULL);
|
||||
}
|
||||
else
|
||||
@@ -347,11 +344,10 @@ static int win32_drag_query_file(HWND hwnd, WPARAM wparam)
|
||||
if(DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_PICKCORE),
|
||||
hwnd,PickCoreProc,(LPARAM)NULL)==IDOK)
|
||||
{
|
||||
task_push_content_load_default(
|
||||
NULL, NULL,
|
||||
task_push_load_content_with_current_core_from_companion_ui(
|
||||
NULL,
|
||||
&content_info,
|
||||
CORE_TYPE_PLAIN,
|
||||
CONTENT_MODE_LOAD_CONTENT_WITH_CURRENT_CORE_FROM_COMPANION_UI,
|
||||
NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#include <bcm_host.h>
|
||||
|
||||
#include <rthreads/rthreads.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../../config.h"
|
||||
#endif
|
||||
@@ -36,10 +34,6 @@ struct dispmanx_page
|
||||
/* Each page contains it's own resource handler
|
||||
* instead of pointing to in by page number */
|
||||
DISPMANX_RESOURCE_HANDLE_T resource;
|
||||
bool used;
|
||||
/* Each page has it's own mutex for
|
||||
* isolating it's used flag access. */
|
||||
slock_t *page_used_mutex;
|
||||
|
||||
/* This field will allow us to access the
|
||||
* main _dispvars struct from the vsync CB function */
|
||||
@@ -57,10 +51,7 @@ struct dispmanx_surface
|
||||
struct dispmanx_page *pages;
|
||||
/* the page that's currently on screen */
|
||||
struct dispmanx_page *current_page;
|
||||
/*The page to wich we will dump the render. We need to know this
|
||||
* already when we enter the surface update function. No time to wait
|
||||
* for free pages before blitting and showing the just rendered frame! */
|
||||
struct dispmanx_page *next_page;
|
||||
bool flip_page;
|
||||
unsigned int bpp;
|
||||
|
||||
VC_RECT_T src_rect;
|
||||
@@ -102,12 +93,6 @@ struct dispmanx_video
|
||||
unsigned int dispmanx_width;
|
||||
unsigned int dispmanx_height;
|
||||
|
||||
/* For threading */
|
||||
scond_t *vsync_condition;
|
||||
slock_t *vsync_cond_mutex;
|
||||
slock_t *pending_mutex;
|
||||
unsigned int pageflip_pending;
|
||||
|
||||
/* Menu */
|
||||
bool menu_active;
|
||||
|
||||
@@ -129,94 +114,15 @@ struct dispmanx_video
|
||||
float aspect_ratio;
|
||||
};
|
||||
|
||||
/* If no free page is available when called, wait for a page flip. */
|
||||
static struct dispmanx_page *dispmanx_get_free_page(void *data, struct dispmanx_surface *surface)
|
||||
{
|
||||
unsigned i;
|
||||
struct dispmanx_video *_dispvars = data;
|
||||
struct dispmanx_page *page = NULL;
|
||||
|
||||
while (!page)
|
||||
{
|
||||
/* Try to find a free page */
|
||||
for (i = 0; i < surface->numpages; ++i)
|
||||
{
|
||||
if (!surface->pages[i].used)
|
||||
{
|
||||
page = (surface->pages) + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no page is free at the moment,
|
||||
* wait until a free page is freed by vsync CB. */
|
||||
if (!page)
|
||||
{
|
||||
slock_lock(_dispvars->vsync_cond_mutex);
|
||||
scond_wait(_dispvars->vsync_condition, _dispvars->vsync_cond_mutex);
|
||||
slock_unlock(_dispvars->vsync_cond_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/* We mark the choosen page as used */
|
||||
slock_lock(page->page_used_mutex);
|
||||
page->used = true;
|
||||
slock_unlock(page->page_used_mutex);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
static void dispmanx_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
|
||||
{
|
||||
struct dispmanx_page *page = data;
|
||||
struct dispmanx_surface *surface = page->surface;
|
||||
|
||||
/* Marking the page as free must be done before the signaling
|
||||
* so when update_main continues (it won't continue until we signal)
|
||||
* we can chose this page as free */
|
||||
if (surface->current_page)
|
||||
{
|
||||
slock_lock(surface->current_page->page_used_mutex);
|
||||
|
||||
/* We mark as free the page that was visible until now */
|
||||
surface->current_page->used = false;
|
||||
slock_unlock(surface->current_page->page_used_mutex);
|
||||
}
|
||||
|
||||
/* The page on which we issued the flip that
|
||||
* caused this callback becomes the visible one */
|
||||
surface->current_page = page;
|
||||
|
||||
/* These two things must be isolated "atomically" to avoid getting
|
||||
* a false positive in the pending_mutex test in update_main. */
|
||||
slock_lock(page->dispvars->pending_mutex);
|
||||
|
||||
page->dispvars->pageflip_pending--;
|
||||
scond_signal(page->dispvars->vsync_condition);
|
||||
|
||||
slock_unlock(page->dispvars->pending_mutex);
|
||||
}
|
||||
|
||||
static void dispmanx_surface_free(void *data, struct dispmanx_surface **sp)
|
||||
{
|
||||
int i;
|
||||
struct dispmanx_video *_dispvars = data;
|
||||
struct dispmanx_surface *surface = *sp;
|
||||
|
||||
/* What if we run into the vsync cb code after freeing the surface?
|
||||
* We could be trying to get non-existant lock, signal non-existant condition..
|
||||
* So we wait for any pending flips to complete before freeing any surface. */
|
||||
slock_lock(_dispvars->pending_mutex);
|
||||
if (_dispvars->pageflip_pending > 0)
|
||||
scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex);
|
||||
|
||||
slock_unlock(_dispvars->pending_mutex);
|
||||
|
||||
for (i = 0; i < surface->numpages; i++)
|
||||
{
|
||||
vc_dispmanx_resource_delete(surface->pages[i].resource);
|
||||
surface->pages[i].used = false;
|
||||
slock_free(surface->pages[i].page_used_mutex);
|
||||
}
|
||||
|
||||
free(surface->pages);
|
||||
@@ -260,16 +166,12 @@ static void dispmanx_surface_setup(void *data, int src_width, int src_height,
|
||||
|
||||
for (i = 0; i < surface->numpages; i++)
|
||||
{
|
||||
surface->pages[i].used = false;
|
||||
surface->pages[i].surface = surface;
|
||||
surface->pages[i].dispvars = _dispvars;
|
||||
surface->pages[i].page_used_mutex = slock_new();
|
||||
}
|
||||
|
||||
/* No need to mutex this access to the "used" member because
|
||||
* the flipping/callbacks are not still running */
|
||||
surface->next_page = &(surface->pages[0]);
|
||||
surface->next_page->used = true;
|
||||
/* We blit to page 0 first */
|
||||
surface->flip_page = 0;
|
||||
|
||||
/* The "visible" width obtained from the core pitch. We blit based on
|
||||
* the "visible" width, for cores with things between scanlines. */
|
||||
@@ -325,40 +227,24 @@ static void dispmanx_surface_update_async(void *data, const void *frame,
|
||||
static void dispmanx_surface_update(void *data, const void *frame,
|
||||
struct dispmanx_surface *surface)
|
||||
{
|
||||
/* Updating is very delicate: we REALLY want to show the just rendered frame ASAP,
|
||||
* so we dump and issue flip, and then we can wait for free pages, but we don't
|
||||
* want to wait for free pages at the beggining of the update or we will be
|
||||
* adding lag! */
|
||||
|
||||
struct dispmanx_video *_dispvars = data;
|
||||
|
||||
struct dispmanx_page *page = NULL;
|
||||
|
||||
page = &surface->pages[surface->flip_page];
|
||||
|
||||
/* Frame blitting */
|
||||
vc_dispmanx_resource_write_data(surface->next_page->resource, surface->pixformat,
|
||||
vc_dispmanx_resource_write_data(page->resource, surface->pixformat,
|
||||
surface->pitch, (void*)frame, &(surface->bmp_rect));
|
||||
|
||||
/* Dispmanx doesn't support more than one pending pageflip. Doing so would overwrite
|
||||
* the page in the callback function, so we would be always freeing the same page. */
|
||||
slock_lock(_dispvars->pending_mutex);
|
||||
if (_dispvars->pageflip_pending > 0)
|
||||
scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex);
|
||||
slock_unlock(_dispvars->pending_mutex);
|
||||
|
||||
/* Issue a page flip that will be done at the next vsync. */
|
||||
_dispvars->update = vc_dispmanx_update_start(0);
|
||||
|
||||
vc_dispmanx_element_change_source(_dispvars->update, surface->element,
|
||||
surface->next_page->resource);
|
||||
page->resource);
|
||||
|
||||
vc_dispmanx_update_submit(_dispvars->update,
|
||||
dispmanx_vsync_callback, (void*)(surface->next_page));
|
||||
vc_dispmanx_update_submit_sync(_dispvars->update);
|
||||
|
||||
slock_lock(_dispvars->pending_mutex);
|
||||
_dispvars->pageflip_pending++;
|
||||
slock_unlock(_dispvars->pending_mutex);
|
||||
|
||||
/* Get the next page ready for our next surface_update re-entry.
|
||||
* It's OK to wait now that we've issued the flip to the last produced frame! */
|
||||
surface->next_page = dispmanx_get_free_page(_dispvars, surface);
|
||||
surface->flip_page = !surface->flip_page;
|
||||
}
|
||||
|
||||
/* Enable/disable bilinear filtering. */
|
||||
@@ -414,7 +300,6 @@ static void *dispmanx_gfx_init(const video_info_t *video,
|
||||
|
||||
/* Setup surface parameters */
|
||||
_dispvars->vc_image_ptr = 0;
|
||||
_dispvars->pageflip_pending = 0;
|
||||
_dispvars->menu_active = false;
|
||||
_dispvars->rgb32 = video->rgb32;
|
||||
|
||||
@@ -424,10 +309,7 @@ static void *dispmanx_gfx_init(const video_info_t *video,
|
||||
* before we get to gfx_frame(). */
|
||||
_dispvars->aspect_ratio = video_driver_get_aspect_ratio();
|
||||
|
||||
/* Initialize the rest of the mutexes and conditions. */
|
||||
_dispvars->vsync_condition = scond_new();
|
||||
_dispvars->vsync_cond_mutex = slock_new();
|
||||
_dispvars->pending_mutex = slock_new();
|
||||
/* Initialize the rest of video variables. */
|
||||
_dispvars->core_width = 0;
|
||||
_dispvars->core_height = 0;
|
||||
_dispvars->menu_width = 0;
|
||||
@@ -695,11 +577,6 @@ static void dispmanx_gfx_free(void *data)
|
||||
vc_dispmanx_display_close(_dispvars->display);
|
||||
bcm_host_deinit();
|
||||
|
||||
/* Destroy mutexes and conditions. */
|
||||
slock_free(_dispvars->pending_mutex);
|
||||
slock_free(_dispvars->vsync_cond_mutex);
|
||||
scond_free(_dispvars->vsync_condition);
|
||||
|
||||
free(_dispvars);
|
||||
}
|
||||
|
||||
|
||||
@@ -2748,7 +2748,7 @@ static int video_texture_load_wrap_gl_mipmap(void *data)
|
||||
return 0;
|
||||
video_texture_load_gl((struct texture_image*)data,
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, &id);
|
||||
return id;
|
||||
return (int)id;
|
||||
}
|
||||
|
||||
static int video_texture_load_wrap_gl(void *data)
|
||||
@@ -2759,7 +2759,7 @@ static int video_texture_load_wrap_gl(void *data)
|
||||
return 0;
|
||||
video_texture_load_gl((struct texture_image*)data,
|
||||
TEXTURE_FILTER_LINEAR, &id);
|
||||
return id;
|
||||
return (int)id;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -505,6 +505,7 @@ static bool sdl2_gfx_frame(void *data, const void *frame, unsigned width,
|
||||
{
|
||||
static struct retro_perf_counter sdl_copy_frame = {0};
|
||||
|
||||
SDL_RenderClear(vid->renderer);
|
||||
sdl_refresh_input_size(vid, false, vid->video.rgb32, width, height, pitch);
|
||||
|
||||
performance_counter_init(sdl_copy_frame, "sdl_copy_frame");
|
||||
|
||||
@@ -222,14 +222,14 @@ static bool vga_gfx_frame(void *data, const void *frame,
|
||||
for (x = 0; x < VGA_WIDTH; x++)
|
||||
{
|
||||
/* scale incoming frame to fit the screen */
|
||||
unsigned scaled_x = (width / (float)VGA_WIDTH) * x;
|
||||
unsigned scaled_y = (height / (float)VGA_HEIGHT) * y;
|
||||
unsigned scaled_x = (width * x) / VGA_WIDTH;
|
||||
unsigned scaled_y = (height * y) / VGA_HEIGHT;
|
||||
unsigned short pixel = ((unsigned short*)frame_to_copy)[width * scaled_y + scaled_x];
|
||||
|
||||
/* convert RGB565 to BGR332 */
|
||||
unsigned r = (7.0f / 31.0f) * ((pixel & 0xF800) >> 11);
|
||||
unsigned g = (7.0f / 63.0f) * ((pixel & 0x07E0) >> 5);
|
||||
unsigned b = (3.0f / 31.0f) * ((pixel & 0x001F) >> 0);
|
||||
unsigned r = ((pixel & 0xF800) >> 13);
|
||||
unsigned g = ((pixel & 0x07E0) >> 8);
|
||||
unsigned b = ((pixel & 0x001F) >> 3);
|
||||
|
||||
vga_frame[VGA_WIDTH * y + x] = (b << 6) | (g << 3) | r;
|
||||
}
|
||||
@@ -368,10 +368,13 @@ static void vga_set_texture_frame(void *data,
|
||||
{
|
||||
for(x = 0; x < VGA_WIDTH; x++)
|
||||
{
|
||||
unsigned short pixel = video_frame[width * y + x];
|
||||
unsigned r = (7.0f / 15.0f) * ((pixel & 0xF000) >> 12);
|
||||
unsigned g = (7.0f / 15.0f) * ((pixel & 0xF00) >> 8);
|
||||
unsigned b = (3.0f / 15.0f) * ((pixel & 0xF0) >> 4);
|
||||
/* scale incoming frame to fit the screen */
|
||||
unsigned scaled_x = (width * x) / VGA_WIDTH;
|
||||
unsigned scaled_y = (height * y) / VGA_HEIGHT;
|
||||
unsigned short pixel = video_frame[width * scaled_y + scaled_x];
|
||||
unsigned r = ((pixel & 0xF000) >> 13);
|
||||
unsigned g = ((pixel & 0xF00) >> 9);
|
||||
unsigned b = ((pixel & 0xF0) >> 6);
|
||||
vga_menu_frame[VGA_WIDTH * y + x] = (b << 6) | (g << 3) | r;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,6 +225,18 @@ static void vulkan_init_pipelines(
|
||||
#include "vulkan_shaders/pipeline_ribbon_simple.frag.inc"
|
||||
;
|
||||
|
||||
static const uint32_t pipeline_snow_simple_frag[] =
|
||||
#include "vulkan_shaders/pipeline_snow_simple.frag.inc"
|
||||
;
|
||||
|
||||
static const uint32_t pipeline_snow_frag[] =
|
||||
#include "vulkan_shaders/pipeline_snow.frag.inc"
|
||||
;
|
||||
|
||||
static const uint32_t pipeline_bokeh_frag[] =
|
||||
#include "vulkan_shaders/pipeline_bokeh.frag.inc"
|
||||
;
|
||||
|
||||
unsigned i;
|
||||
VkPipelineInputAssemblyStateCreateInfo input_assembly = {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
|
||||
@@ -390,17 +402,38 @@ static void vulkan_init_pipelines(
|
||||
vkDestroyShaderModule(vk->context->device, shader_stages[1].module, NULL);
|
||||
|
||||
/* Other menu pipelines. */
|
||||
for (i = 0; i < 4; i++)
|
||||
for (i = 0; i < ARRAY_SIZE(vk->display.pipelines) - 4; i++)
|
||||
{
|
||||
if (i & 2)
|
||||
switch (i >> 1)
|
||||
{
|
||||
module_info.codeSize = sizeof(pipeline_ribbon_simple_vert);
|
||||
module_info.pCode = pipeline_ribbon_simple_vert;
|
||||
}
|
||||
else
|
||||
{
|
||||
module_info.codeSize = sizeof(pipeline_ribbon_vert);
|
||||
module_info.pCode = pipeline_ribbon_vert;
|
||||
case 0:
|
||||
module_info.codeSize = sizeof(pipeline_ribbon_vert);
|
||||
module_info.pCode = pipeline_ribbon_vert;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
module_info.codeSize = sizeof(pipeline_ribbon_simple_vert);
|
||||
module_info.pCode = pipeline_ribbon_simple_vert;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
module_info.codeSize = sizeof(alpha_blend_vert);
|
||||
module_info.pCode = alpha_blend_vert;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
module_info.codeSize = sizeof(alpha_blend_vert);
|
||||
module_info.pCode = alpha_blend_vert;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
module_info.codeSize = sizeof(alpha_blend_vert);
|
||||
module_info.pCode = alpha_blend_vert;
|
||||
break;
|
||||
|
||||
default:
|
||||
retro_assert(0 && "No shader for menu pipeline.");
|
||||
break;
|
||||
}
|
||||
|
||||
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
@@ -408,15 +441,36 @@ static void vulkan_init_pipelines(
|
||||
vkCreateShaderModule(vk->context->device,
|
||||
&module_info, NULL, &shader_stages[0].module);
|
||||
|
||||
if (i & 2)
|
||||
switch (i >> 1)
|
||||
{
|
||||
module_info.codeSize = sizeof(pipeline_ribbon_simple_frag);
|
||||
module_info.pCode = pipeline_ribbon_simple_frag;
|
||||
}
|
||||
else
|
||||
{
|
||||
module_info.codeSize = sizeof(pipeline_ribbon_frag);
|
||||
module_info.pCode = pipeline_ribbon_frag;
|
||||
case 0:
|
||||
module_info.codeSize = sizeof(pipeline_ribbon_frag);
|
||||
module_info.pCode = pipeline_ribbon_frag;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
module_info.codeSize = sizeof(pipeline_ribbon_simple_frag);
|
||||
module_info.pCode = pipeline_ribbon_simple_frag;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
module_info.codeSize = sizeof(pipeline_snow_simple_frag);
|
||||
module_info.pCode = pipeline_snow_simple_frag;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
module_info.codeSize = sizeof(pipeline_snow_frag);
|
||||
module_info.pCode = pipeline_snow_frag;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
module_info.codeSize = sizeof(pipeline_bokeh_frag);
|
||||
module_info.pCode = pipeline_bokeh_frag;
|
||||
break;
|
||||
|
||||
default:
|
||||
retro_assert(0 && "No shader for menu pipeline.");
|
||||
break;
|
||||
}
|
||||
|
||||
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
@@ -639,7 +693,7 @@ static void vulkan_deinit_pipelines(vk_t *vk)
|
||||
vkDestroyPipeline(vk->context->device,
|
||||
vk->pipelines.font, NULL);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
for (i = 0; i < ARRAY_SIZE(vk->display.pipelines); i++)
|
||||
vkDestroyPipeline(vk->context->device,
|
||||
vk->display.pipelines[i], NULL);
|
||||
}
|
||||
@@ -1524,7 +1578,6 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
unsigned pitch, const char *msg, video_frame_info_t *video_info)
|
||||
{
|
||||
VkSemaphore signal_semaphores[2];
|
||||
VkClearValue clear_value;
|
||||
vk_t *vk = (vk_t*)data;
|
||||
struct vk_per_frame *chain = NULL;
|
||||
static struct retro_perf_counter frame_run = {0};
|
||||
@@ -1537,6 +1590,7 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
bool waits_for_semaphores = false;
|
||||
unsigned width = video_info->width;
|
||||
unsigned height = video_info->height;
|
||||
VkClearValue clear_color;
|
||||
|
||||
VkCommandBufferBeginInfo begin_info = {
|
||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
@@ -1711,16 +1765,17 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
(vulkan_filter_chain_t*)vk->filter_chain,
|
||||
vk->cmd, &vk->vk_vp);
|
||||
/* Render to backbuffer. */
|
||||
clear_value.color.float32[0] = 0.0f;
|
||||
clear_value.color.float32[1] = 0.0f;
|
||||
clear_value.color.float32[2] = 0.0f;
|
||||
clear_value.color.float32[3] = 1.0f;
|
||||
rp_info.renderPass = vk->render_pass;
|
||||
rp_info.framebuffer = chain->backbuffer.framebuffer;
|
||||
rp_info.renderArea.extent.width = vk->context->swapchain_width;
|
||||
rp_info.renderArea.extent.height = vk->context->swapchain_height;
|
||||
rp_info.clearValueCount = 1;
|
||||
rp_info.pClearValues = &clear_value;
|
||||
rp_info.pClearValues = &clear_color;
|
||||
|
||||
clear_color.color.float32[0] = 0.0f;
|
||||
clear_color.color.float32[1] = 0.0f;
|
||||
clear_color.color.float32[2] = 0.0f;
|
||||
clear_color.color.float32[3] = 0.0f;
|
||||
|
||||
/* Prepare backbuffer for rendering. We don't use WSI semaphores here. */
|
||||
vulkan_image_layout_transition(vk, vk->cmd, chain->backbuffer.image,
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(std140, set = 0, binding = 0) uniform UBO
|
||||
{
|
||||
mat4 MVP;
|
||||
vec2 OutputSize;
|
||||
float time;
|
||||
} constants;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
||||
float speed = constants.time * 4.0;
|
||||
vec2 uv = -1.0 + 2.0 * gl_FragCoord.xy / constants.OutputSize;
|
||||
uv.x *= constants.OutputSize.x / constants.OutputSize.y;
|
||||
vec3 color = vec3(0.0);
|
||||
|
||||
for( int i=0; i < 8; i++ )
|
||||
{
|
||||
float pha = sin(float(i) * 546.13 + 1.0) * 0.5 + 0.5;
|
||||
float siz = pow(sin(float(i) * 651.74 + 5.0) * 0.5 + 0.5, 4.0);
|
||||
float pox = sin(float(i) * 321.55 + 4.1) * constants.OutputSize.x / constants.OutputSize.y;
|
||||
float rad = 0.1 + 0.5 * siz + sin(pha + siz) / 4.0;
|
||||
vec2 pos = vec2(pox + sin(speed / 15. + pha + siz), - 1.0 - rad + (2.0 + 2.0 * rad) * fract(pha + 0.3 * (speed / 7.) * (0.2 + 0.8 * siz)));
|
||||
float dis = length(uv - pos);
|
||||
if(dis < rad)
|
||||
{
|
||||
vec3 col = mix(vec3(0.194 * sin(speed / 6.0) + 0.3, 0.2, 0.3 * pha), vec3(1.1 * sin(speed / 9.0) + 0.3, 0.2 * pha, 0.4), 0.5 + 0.5 * sin(float(i)));
|
||||
color += col.zyx * (1.0 - smoothstep(rad * 0.15, rad, dis));
|
||||
}
|
||||
}
|
||||
color *= sqrt(1.5 - 0.5 * length(uv));
|
||||
FragColor = vec4(color.r, color.g, color.b , 0.5);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,407 @@
|
||||
{0x07230203,0x00010000,0x000d0001,0x000000da,
|
||||
0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||
0x00000001,0x4c534c47,0x6474732e,0x3035342e,
|
||||
0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||
0x0007000f,0x00000004,0x00000004,0x6e69616d,
|
||||
0x00000000,0x0000001b,0x000000d1,0x00030010,
|
||||
0x00000004,0x00000007,0x00030003,0x00000001,
|
||||
0x00000136,0x000a0004,0x475f4c47,0x4c474f4f,
|
||||
0x70635f45,0x74735f70,0x5f656c79,0x656e696c,
|
||||
0x7269645f,0x69746365,0x00006576,0x00080004,
|
||||
0x475f4c47,0x4c474f4f,0x6e695f45,0x64756c63,
|
||||
0x69645f65,0x74636572,0x00657669,0x00040005,
|
||||
0x00000004,0x6e69616d,0x00000000,0x00040005,
|
||||
0x00000008,0x65657073,0x00000064,0x00030005,
|
||||
0x0000000c,0x004f4255,0x00040006,0x0000000c,
|
||||
0x00000000,0x0050564d,0x00060006,0x0000000c,
|
||||
0x00000001,0x7074754f,0x69537475,0x0000657a,
|
||||
0x00050006,0x0000000c,0x00000002,0x656d6974,
|
||||
0x00000000,0x00050005,0x0000000e,0x736e6f63,
|
||||
0x746e6174,0x00000073,0x00030005,0x00000017,
|
||||
0x00007675,0x00060005,0x0000001b,0x465f6c67,
|
||||
0x43676172,0x64726f6f,0x00000000,0x00040005,
|
||||
0x00000034,0x6f6c6f63,0x00000072,0x00030005,
|
||||
0x00000038,0x00000069,0x00030005,0x00000043,
|
||||
0x00616870,0x00030005,0x0000004e,0x007a6973,
|
||||
0x00030005,0x00000059,0x00786f70,0x00030005,
|
||||
0x00000067,0x00646172,0x00030005,0x00000072,
|
||||
0x00736f70,0x00030005,0x00000093,0x00736964,
|
||||
0x00030005,0x0000009d,0x006c6f63,0x00050005,
|
||||
0x000000d1,0x67617246,0x6f6c6f43,0x00000072,
|
||||
0x00030047,0x00000008,0x00000000,0x00040048,
|
||||
0x0000000c,0x00000000,0x00000005,0x00040048,
|
||||
0x0000000c,0x00000000,0x00000000,0x00050048,
|
||||
0x0000000c,0x00000000,0x00000023,0x00000000,
|
||||
0x00050048,0x0000000c,0x00000000,0x00000007,
|
||||
0x00000010,0x00040048,0x0000000c,0x00000001,
|
||||
0x00000000,0x00050048,0x0000000c,0x00000001,
|
||||
0x00000023,0x00000040,0x00040048,0x0000000c,
|
||||
0x00000002,0x00000000,0x00050048,0x0000000c,
|
||||
0x00000002,0x00000023,0x00000048,0x00030047,
|
||||
0x0000000c,0x00000002,0x00040047,0x0000000e,
|
||||
0x00000022,0x00000000,0x00040047,0x0000000e,
|
||||
0x00000021,0x00000000,0x00030047,0x00000013,
|
||||
0x00000000,0x00030047,0x00000015,0x00000000,
|
||||
0x00030047,0x00000017,0x00000000,0x00040047,
|
||||
0x0000001b,0x0000000b,0x0000000f,0x00030047,
|
||||
0x00000022,0x00000000,0x00030047,0x00000029,
|
||||
0x00000000,0x00030047,0x0000002c,0x00000000,
|
||||
0x00030047,0x0000002d,0x00000000,0x00030047,
|
||||
0x0000002f,0x00000000,0x00030047,0x00000030,
|
||||
0x00000000,0x00030047,0x00000034,0x00000000,
|
||||
0x00030047,0x00000038,0x00000000,0x00030047,
|
||||
0x0000003f,0x00000000,0x00030047,0x00000043,
|
||||
0x00000000,0x00030047,0x00000044,0x00000000,
|
||||
0x00030047,0x00000045,0x00000000,0x00030047,
|
||||
0x00000047,0x00000000,0x00030047,0x00000049,
|
||||
0x00000000,0x00030047,0x0000004a,0x00000000,
|
||||
0x00030047,0x0000004c,0x00000000,0x00030047,
|
||||
0x0000004d,0x00000000,0x00030047,0x0000004e,
|
||||
0x00000000,0x00030047,0x0000004f,0x00000000,
|
||||
0x00030047,0x00000050,0x00000000,0x00030047,
|
||||
0x00000052,0x00000000,0x00030047,0x00000054,
|
||||
0x00000000,0x00030047,0x00000055,0x00000000,
|
||||
0x00030047,0x00000056,0x00000000,0x00030047,
|
||||
0x00000057,0x00000000,0x00030047,0x00000058,
|
||||
0x00000000,0x00030047,0x00000059,0x00000000,
|
||||
0x00030047,0x0000005a,0x00000000,0x00030047,
|
||||
0x0000005b,0x00000000,0x00030047,0x0000005d,
|
||||
0x00000000,0x00030047,0x0000005f,0x00000000,
|
||||
0x00030047,0x00000060,0x00000000,0x00030047,
|
||||
0x00000062,0x00000000,0x00030047,0x00000063,
|
||||
0x00000000,0x00030047,0x00000065,0x00000000,
|
||||
0x00030047,0x00000066,0x00000000,0x00030047,
|
||||
0x00000067,0x00000000,0x00030047,0x00000069,
|
||||
0x00000000,0x00030047,0x0000006a,0x00000000,
|
||||
0x00030047,0x0000006b,0x00000000,0x00030047,
|
||||
0x0000006c,0x00000000,0x00030047,0x0000006d,
|
||||
0x00000000,0x00030047,0x0000006e,0x00000000,
|
||||
0x00030047,0x0000006f,0x00000000,0x00030047,
|
||||
0x00000070,0x00000000,0x00030047,0x00000071,
|
||||
0x00000000,0x00030047,0x00000072,0x00000000,
|
||||
0x00030047,0x00000073,0x00000000,0x00030047,
|
||||
0x00000074,0x00000000,0x00030047,0x00000076,
|
||||
0x00000000,0x00030047,0x00000077,0x00000000,
|
||||
0x00030047,0x00000078,0x00000000,0x00030047,
|
||||
0x00000079,0x00000000,0x00030047,0x0000007a,
|
||||
0x00000000,0x00030047,0x0000007b,0x00000000,
|
||||
0x00030047,0x0000007c,0x00000000,0x00030047,
|
||||
0x0000007d,0x00000000,0x00030047,0x0000007e,
|
||||
0x00000000,0x00030047,0x0000007f,0x00000000,
|
||||
0x00030047,0x00000080,0x00000000,0x00030047,
|
||||
0x00000081,0x00000000,0x00030047,0x00000082,
|
||||
0x00000000,0x00030047,0x00000084,0x00000000,
|
||||
0x00030047,0x00000086,0x00000000,0x00030047,
|
||||
0x00000087,0x00000000,0x00030047,0x0000008a,
|
||||
0x00000000,0x00030047,0x0000008b,0x00000000,
|
||||
0x00030047,0x0000008c,0x00000000,0x00030047,
|
||||
0x0000008d,0x00000000,0x00030047,0x0000008e,
|
||||
0x00000000,0x00030047,0x0000008f,0x00000000,
|
||||
0x00030047,0x00000090,0x00000000,0x00030047,
|
||||
0x00000091,0x00000000,0x00030047,0x00000092,
|
||||
0x00000000,0x00030047,0x00000093,0x00000000,
|
||||
0x00030047,0x00000094,0x00000000,0x00030047,
|
||||
0x00000095,0x00000000,0x00030047,0x00000096,
|
||||
0x00000000,0x00030047,0x00000097,0x00000000,
|
||||
0x00030047,0x00000098,0x00000000,0x00030047,
|
||||
0x00000099,0x00000000,0x00030047,0x0000009d,
|
||||
0x00000000,0x00030047,0x0000009f,0x00000000,
|
||||
0x00030047,0x000000a1,0x00000000,0x00030047,
|
||||
0x000000a2,0x00000000,0x00030047,0x000000a3,
|
||||
0x00000000,0x00030047,0x000000a4,0x00000000,
|
||||
0x00030047,0x000000a5,0x00000000,0x00030047,
|
||||
0x000000a6,0x00000000,0x00030047,0x000000a7,
|
||||
0x00000000,0x00030047,0x000000a9,0x00000000,
|
||||
0x00030047,0x000000ab,0x00000000,0x00030047,
|
||||
0x000000ac,0x00000000,0x00030047,0x000000ad,
|
||||
0x00000000,0x00030047,0x000000ae,0x00000000,
|
||||
0x00030047,0x000000af,0x00000000,0x00030047,
|
||||
0x000000b0,0x00000000,0x00030047,0x000000b2,
|
||||
0x00000000,0x00030047,0x000000b3,0x00000000,
|
||||
0x00030047,0x000000b4,0x00000000,0x00030047,
|
||||
0x000000b5,0x00000000,0x00030047,0x000000b6,
|
||||
0x00000000,0x00030047,0x000000b7,0x00000000,
|
||||
0x00030047,0x000000b8,0x00000000,0x00030047,
|
||||
0x000000b9,0x00000000,0x00030047,0x000000ba,
|
||||
0x00000000,0x00030047,0x000000bb,0x00000000,
|
||||
0x00030047,0x000000bc,0x00000000,0x00030047,
|
||||
0x000000be,0x00000000,0x00030047,0x000000bf,
|
||||
0x00000000,0x00030047,0x000000c0,0x00000000,
|
||||
0x00030047,0x000000c1,0x00000000,0x00030047,
|
||||
0x000000c2,0x00000000,0x00030047,0x000000c3,
|
||||
0x00000000,0x00030047,0x000000c4,0x00000000,
|
||||
0x00030047,0x000000c5,0x00000000,0x00030047,
|
||||
0x000000c6,0x00000000,0x00030047,0x000000c7,
|
||||
0x00000000,0x00030047,0x000000c9,0x00000000,
|
||||
0x00030047,0x000000ca,0x00000000,0x00030047,
|
||||
0x000000cb,0x00000000,0x00030047,0x000000cc,
|
||||
0x00000000,0x00030047,0x000000cd,0x00000000,
|
||||
0x00030047,0x000000ce,0x00000000,0x00030047,
|
||||
0x000000cf,0x00000000,0x00030047,0x000000d1,
|
||||
0x00000000,0x00040047,0x000000d1,0x0000001e,
|
||||
0x00000000,0x00030047,0x000000d3,0x00000000,
|
||||
0x00030047,0x000000d5,0x00000000,0x00030047,
|
||||
0x000000d8,0x00000000,0x00030047,0x000000d9,
|
||||
0x00000000,0x00020013,0x00000002,0x00030021,
|
||||
0x00000003,0x00000002,0x00030016,0x00000006,
|
||||
0x00000020,0x00040020,0x00000007,0x00000007,
|
||||
0x00000006,0x00040017,0x00000009,0x00000006,
|
||||
0x00000004,0x00040018,0x0000000a,0x00000009,
|
||||
0x00000004,0x00040017,0x0000000b,0x00000006,
|
||||
0x00000002,0x0005001e,0x0000000c,0x0000000a,
|
||||
0x0000000b,0x00000006,0x00040020,0x0000000d,
|
||||
0x00000002,0x0000000c,0x0004003b,0x0000000d,
|
||||
0x0000000e,0x00000002,0x00040015,0x0000000f,
|
||||
0x00000020,0x00000001,0x0004002b,0x0000000f,
|
||||
0x00000010,0x00000002,0x00040020,0x00000011,
|
||||
0x00000002,0x00000006,0x0004002b,0x00000006,
|
||||
0x00000014,0x40800000,0x00040020,0x00000016,
|
||||
0x00000007,0x0000000b,0x0004002b,0x00000006,
|
||||
0x00000018,0xbf800000,0x0004002b,0x00000006,
|
||||
0x00000019,0x40000000,0x00040020,0x0000001a,
|
||||
0x00000001,0x00000009,0x0004003b,0x0000001a,
|
||||
0x0000001b,0x00000001,0x0004002b,0x0000000f,
|
||||
0x0000001f,0x00000001,0x00040020,0x00000020,
|
||||
0x00000002,0x0000000b,0x00040015,0x00000026,
|
||||
0x00000020,0x00000000,0x0004002b,0x00000026,
|
||||
0x00000027,0x00000000,0x0004002b,0x00000026,
|
||||
0x0000002a,0x00000001,0x00040017,0x00000032,
|
||||
0x00000006,0x00000003,0x00040020,0x00000033,
|
||||
0x00000007,0x00000032,0x0004002b,0x00000006,
|
||||
0x00000035,0x00000000,0x0006002c,0x00000032,
|
||||
0x00000036,0x00000035,0x00000035,0x00000035,
|
||||
0x00040020,0x00000037,0x00000007,0x0000000f,
|
||||
0x0004002b,0x0000000f,0x00000039,0x00000000,
|
||||
0x0004002b,0x0000000f,0x00000040,0x00000008,
|
||||
0x00020014,0x00000041,0x0004002b,0x00000006,
|
||||
0x00000046,0x44088852,0x0004002b,0x00000006,
|
||||
0x00000048,0x3f800000,0x0004002b,0x00000006,
|
||||
0x0000004b,0x3f000000,0x0004002b,0x00000006,
|
||||
0x00000051,0x4422ef5c,0x0004002b,0x00000006,
|
||||
0x00000053,0x40a00000,0x0004002b,0x00000006,
|
||||
0x0000005c,0x43a0c666,0x0004002b,0x00000006,
|
||||
0x0000005e,0x40833333,0x0004002b,0x00000006,
|
||||
0x00000068,0x3dcccccd,0x0004002b,0x00000006,
|
||||
0x00000075,0x41700000,0x0004002b,0x00000006,
|
||||
0x00000083,0x3e99999a,0x0004002b,0x00000006,
|
||||
0x00000085,0x40e00000,0x0004002b,0x00000006,
|
||||
0x00000088,0x3e4ccccd,0x0004002b,0x00000006,
|
||||
0x00000089,0x3f4ccccd,0x0004002b,0x00000006,
|
||||
0x0000009e,0x3e46a7f0,0x0004002b,0x00000006,
|
||||
0x000000a0,0x40c00000,0x0004002b,0x00000006,
|
||||
0x000000a8,0x3f8ccccd,0x0004002b,0x00000006,
|
||||
0x000000aa,0x41100000,0x0004002b,0x00000006,
|
||||
0x000000b1,0x3ecccccd,0x0004002b,0x00000006,
|
||||
0x000000bd,0x3e19999a,0x0004002b,0x00000006,
|
||||
0x000000c8,0x3fc00000,0x00040020,0x000000d0,
|
||||
0x00000003,0x00000009,0x0004003b,0x000000d0,
|
||||
0x000000d1,0x00000003,0x0004002b,0x00000026,
|
||||
0x000000d6,0x00000002,0x00050036,0x00000002,
|
||||
0x00000004,0x00000000,0x00000003,0x000200f8,
|
||||
0x00000005,0x0004003b,0x00000007,0x00000008,
|
||||
0x00000007,0x0004003b,0x00000016,0x00000017,
|
||||
0x00000007,0x0004003b,0x00000033,0x00000034,
|
||||
0x00000007,0x0004003b,0x00000037,0x00000038,
|
||||
0x00000007,0x0004003b,0x00000007,0x00000043,
|
||||
0x00000007,0x0004003b,0x00000007,0x0000004e,
|
||||
0x00000007,0x0004003b,0x00000007,0x00000059,
|
||||
0x00000007,0x0004003b,0x00000007,0x00000067,
|
||||
0x00000007,0x0004003b,0x00000016,0x00000072,
|
||||
0x00000007,0x0004003b,0x00000007,0x00000093,
|
||||
0x00000007,0x0004003b,0x00000033,0x0000009d,
|
||||
0x00000007,0x00050041,0x00000011,0x00000012,
|
||||
0x0000000e,0x00000010,0x0004003d,0x00000006,
|
||||
0x00000013,0x00000012,0x00050085,0x00000006,
|
||||
0x00000015,0x00000013,0x00000014,0x0003003e,
|
||||
0x00000008,0x00000015,0x0004003d,0x00000009,
|
||||
0x0000001c,0x0000001b,0x0007004f,0x0000000b,
|
||||
0x0000001d,0x0000001c,0x0000001c,0x00000000,
|
||||
0x00000001,0x0005008e,0x0000000b,0x0000001e,
|
||||
0x0000001d,0x00000019,0x00050041,0x00000020,
|
||||
0x00000021,0x0000000e,0x0000001f,0x0004003d,
|
||||
0x0000000b,0x00000022,0x00000021,0x00050088,
|
||||
0x0000000b,0x00000023,0x0000001e,0x00000022,
|
||||
0x00050050,0x0000000b,0x00000024,0x00000018,
|
||||
0x00000018,0x00050081,0x0000000b,0x00000025,
|
||||
0x00000024,0x00000023,0x0003003e,0x00000017,
|
||||
0x00000025,0x00060041,0x00000011,0x00000028,
|
||||
0x0000000e,0x0000001f,0x00000027,0x0004003d,
|
||||
0x00000006,0x00000029,0x00000028,0x00060041,
|
||||
0x00000011,0x0000002b,0x0000000e,0x0000001f,
|
||||
0x0000002a,0x0004003d,0x00000006,0x0000002c,
|
||||
0x0000002b,0x00050088,0x00000006,0x0000002d,
|
||||
0x00000029,0x0000002c,0x00050041,0x00000007,
|
||||
0x0000002e,0x00000017,0x00000027,0x0004003d,
|
||||
0x00000006,0x0000002f,0x0000002e,0x00050085,
|
||||
0x00000006,0x00000030,0x0000002f,0x0000002d,
|
||||
0x00050041,0x00000007,0x00000031,0x00000017,
|
||||
0x00000027,0x0003003e,0x00000031,0x00000030,
|
||||
0x0003003e,0x00000034,0x00000036,0x0003003e,
|
||||
0x00000038,0x00000039,0x000200f9,0x0000003a,
|
||||
0x000200f8,0x0000003a,0x000400f6,0x0000003c,
|
||||
0x0000003d,0x00000000,0x000200f9,0x0000003e,
|
||||
0x000200f8,0x0000003e,0x0004003d,0x0000000f,
|
||||
0x0000003f,0x00000038,0x000500b1,0x00000041,
|
||||
0x00000042,0x0000003f,0x00000040,0x000400fa,
|
||||
0x00000042,0x0000003b,0x0000003c,0x000200f8,
|
||||
0x0000003b,0x0004003d,0x0000000f,0x00000044,
|
||||
0x00000038,0x0004006f,0x00000006,0x00000045,
|
||||
0x00000044,0x00050085,0x00000006,0x00000047,
|
||||
0x00000045,0x00000046,0x00050081,0x00000006,
|
||||
0x00000049,0x00000047,0x00000048,0x0006000c,
|
||||
0x00000006,0x0000004a,0x00000001,0x0000000d,
|
||||
0x00000049,0x00050085,0x00000006,0x0000004c,
|
||||
0x0000004a,0x0000004b,0x00050081,0x00000006,
|
||||
0x0000004d,0x0000004c,0x0000004b,0x0003003e,
|
||||
0x00000043,0x0000004d,0x0004003d,0x0000000f,
|
||||
0x0000004f,0x00000038,0x0004006f,0x00000006,
|
||||
0x00000050,0x0000004f,0x00050085,0x00000006,
|
||||
0x00000052,0x00000050,0x00000051,0x00050081,
|
||||
0x00000006,0x00000054,0x00000052,0x00000053,
|
||||
0x0006000c,0x00000006,0x00000055,0x00000001,
|
||||
0x0000000d,0x00000054,0x00050085,0x00000006,
|
||||
0x00000056,0x00000055,0x0000004b,0x00050081,
|
||||
0x00000006,0x00000057,0x00000056,0x0000004b,
|
||||
0x0007000c,0x00000006,0x00000058,0x00000001,
|
||||
0x0000001a,0x00000057,0x00000014,0x0003003e,
|
||||
0x0000004e,0x00000058,0x0004003d,0x0000000f,
|
||||
0x0000005a,0x00000038,0x0004006f,0x00000006,
|
||||
0x0000005b,0x0000005a,0x00050085,0x00000006,
|
||||
0x0000005d,0x0000005b,0x0000005c,0x00050081,
|
||||
0x00000006,0x0000005f,0x0000005d,0x0000005e,
|
||||
0x0006000c,0x00000006,0x00000060,0x00000001,
|
||||
0x0000000d,0x0000005f,0x00060041,0x00000011,
|
||||
0x00000061,0x0000000e,0x0000001f,0x00000027,
|
||||
0x0004003d,0x00000006,0x00000062,0x00000061,
|
||||
0x00050085,0x00000006,0x00000063,0x00000060,
|
||||
0x00000062,0x00060041,0x00000011,0x00000064,
|
||||
0x0000000e,0x0000001f,0x0000002a,0x0004003d,
|
||||
0x00000006,0x00000065,0x00000064,0x00050088,
|
||||
0x00000006,0x00000066,0x00000063,0x00000065,
|
||||
0x0003003e,0x00000059,0x00000066,0x0004003d,
|
||||
0x00000006,0x00000069,0x0000004e,0x00050085,
|
||||
0x00000006,0x0000006a,0x0000004b,0x00000069,
|
||||
0x00050081,0x00000006,0x0000006b,0x00000068,
|
||||
0x0000006a,0x0004003d,0x00000006,0x0000006c,
|
||||
0x00000043,0x0004003d,0x00000006,0x0000006d,
|
||||
0x0000004e,0x00050081,0x00000006,0x0000006e,
|
||||
0x0000006c,0x0000006d,0x0006000c,0x00000006,
|
||||
0x0000006f,0x00000001,0x0000000d,0x0000006e,
|
||||
0x00050088,0x00000006,0x00000070,0x0000006f,
|
||||
0x00000014,0x00050081,0x00000006,0x00000071,
|
||||
0x0000006b,0x00000070,0x0003003e,0x00000067,
|
||||
0x00000071,0x0004003d,0x00000006,0x00000073,
|
||||
0x00000059,0x0004003d,0x00000006,0x00000074,
|
||||
0x00000008,0x00050088,0x00000006,0x00000076,
|
||||
0x00000074,0x00000075,0x0004003d,0x00000006,
|
||||
0x00000077,0x00000043,0x00050081,0x00000006,
|
||||
0x00000078,0x00000076,0x00000077,0x0004003d,
|
||||
0x00000006,0x00000079,0x0000004e,0x00050081,
|
||||
0x00000006,0x0000007a,0x00000078,0x00000079,
|
||||
0x0006000c,0x00000006,0x0000007b,0x00000001,
|
||||
0x0000000d,0x0000007a,0x00050081,0x00000006,
|
||||
0x0000007c,0x00000073,0x0000007b,0x0004003d,
|
||||
0x00000006,0x0000007d,0x00000067,0x00050083,
|
||||
0x00000006,0x0000007e,0x00000018,0x0000007d,
|
||||
0x0004003d,0x00000006,0x0000007f,0x00000067,
|
||||
0x00050085,0x00000006,0x00000080,0x00000019,
|
||||
0x0000007f,0x00050081,0x00000006,0x00000081,
|
||||
0x00000019,0x00000080,0x0004003d,0x00000006,
|
||||
0x00000082,0x00000043,0x0004003d,0x00000006,
|
||||
0x00000084,0x00000008,0x00050088,0x00000006,
|
||||
0x00000086,0x00000084,0x00000085,0x00050085,
|
||||
0x00000006,0x00000087,0x00000083,0x00000086,
|
||||
0x0004003d,0x00000006,0x0000008a,0x0000004e,
|
||||
0x00050085,0x00000006,0x0000008b,0x00000089,
|
||||
0x0000008a,0x00050081,0x00000006,0x0000008c,
|
||||
0x00000088,0x0000008b,0x00050085,0x00000006,
|
||||
0x0000008d,0x00000087,0x0000008c,0x00050081,
|
||||
0x00000006,0x0000008e,0x00000082,0x0000008d,
|
||||
0x0006000c,0x00000006,0x0000008f,0x00000001,
|
||||
0x0000000a,0x0000008e,0x00050085,0x00000006,
|
||||
0x00000090,0x00000081,0x0000008f,0x00050081,
|
||||
0x00000006,0x00000091,0x0000007e,0x00000090,
|
||||
0x00050050,0x0000000b,0x00000092,0x0000007c,
|
||||
0x00000091,0x0003003e,0x00000072,0x00000092,
|
||||
0x0004003d,0x0000000b,0x00000094,0x00000017,
|
||||
0x0004003d,0x0000000b,0x00000095,0x00000072,
|
||||
0x00050083,0x0000000b,0x00000096,0x00000094,
|
||||
0x00000095,0x0006000c,0x00000006,0x00000097,
|
||||
0x00000001,0x00000042,0x00000096,0x0003003e,
|
||||
0x00000093,0x00000097,0x0004003d,0x00000006,
|
||||
0x00000098,0x00000093,0x0004003d,0x00000006,
|
||||
0x00000099,0x00000067,0x000500b8,0x00000041,
|
||||
0x0000009a,0x00000098,0x00000099,0x000300f7,
|
||||
0x0000009c,0x00000000,0x000400fa,0x0000009a,
|
||||
0x0000009b,0x0000009c,0x000200f8,0x0000009b,
|
||||
0x0004003d,0x00000006,0x0000009f,0x00000008,
|
||||
0x00050088,0x00000006,0x000000a1,0x0000009f,
|
||||
0x000000a0,0x0006000c,0x00000006,0x000000a2,
|
||||
0x00000001,0x0000000d,0x000000a1,0x00050085,
|
||||
0x00000006,0x000000a3,0x0000009e,0x000000a2,
|
||||
0x00050081,0x00000006,0x000000a4,0x000000a3,
|
||||
0x00000083,0x0004003d,0x00000006,0x000000a5,
|
||||
0x00000043,0x00050085,0x00000006,0x000000a6,
|
||||
0x00000083,0x000000a5,0x00060050,0x00000032,
|
||||
0x000000a7,0x000000a4,0x00000088,0x000000a6,
|
||||
0x0004003d,0x00000006,0x000000a9,0x00000008,
|
||||
0x00050088,0x00000006,0x000000ab,0x000000a9,
|
||||
0x000000aa,0x0006000c,0x00000006,0x000000ac,
|
||||
0x00000001,0x0000000d,0x000000ab,0x00050085,
|
||||
0x00000006,0x000000ad,0x000000a8,0x000000ac,
|
||||
0x00050081,0x00000006,0x000000ae,0x000000ad,
|
||||
0x00000083,0x0004003d,0x00000006,0x000000af,
|
||||
0x00000043,0x00050085,0x00000006,0x000000b0,
|
||||
0x00000088,0x000000af,0x00060050,0x00000032,
|
||||
0x000000b2,0x000000ae,0x000000b0,0x000000b1,
|
||||
0x0004003d,0x0000000f,0x000000b3,0x00000038,
|
||||
0x0004006f,0x00000006,0x000000b4,0x000000b3,
|
||||
0x0006000c,0x00000006,0x000000b5,0x00000001,
|
||||
0x0000000d,0x000000b4,0x00050085,0x00000006,
|
||||
0x000000b6,0x0000004b,0x000000b5,0x00050081,
|
||||
0x00000006,0x000000b7,0x0000004b,0x000000b6,
|
||||
0x00060050,0x00000032,0x000000b8,0x000000b7,
|
||||
0x000000b7,0x000000b7,0x0008000c,0x00000032,
|
||||
0x000000b9,0x00000001,0x0000002e,0x000000a7,
|
||||
0x000000b2,0x000000b8,0x0003003e,0x0000009d,
|
||||
0x000000b9,0x0004003d,0x00000032,0x000000ba,
|
||||
0x0000009d,0x0008004f,0x00000032,0x000000bb,
|
||||
0x000000ba,0x000000ba,0x00000002,0x00000001,
|
||||
0x00000000,0x0004003d,0x00000006,0x000000bc,
|
||||
0x00000067,0x00050085,0x00000006,0x000000be,
|
||||
0x000000bc,0x000000bd,0x0004003d,0x00000006,
|
||||
0x000000bf,0x00000067,0x0004003d,0x00000006,
|
||||
0x000000c0,0x00000093,0x0008000c,0x00000006,
|
||||
0x000000c1,0x00000001,0x00000031,0x000000be,
|
||||
0x000000bf,0x000000c0,0x00050083,0x00000006,
|
||||
0x000000c2,0x00000048,0x000000c1,0x0005008e,
|
||||
0x00000032,0x000000c3,0x000000bb,0x000000c2,
|
||||
0x0004003d,0x00000032,0x000000c4,0x00000034,
|
||||
0x00050081,0x00000032,0x000000c5,0x000000c4,
|
||||
0x000000c3,0x0003003e,0x00000034,0x000000c5,
|
||||
0x000200f9,0x0000009c,0x000200f8,0x0000009c,
|
||||
0x000200f9,0x0000003d,0x000200f8,0x0000003d,
|
||||
0x0004003d,0x0000000f,0x000000c6,0x00000038,
|
||||
0x00050080,0x0000000f,0x000000c7,0x000000c6,
|
||||
0x0000001f,0x0003003e,0x00000038,0x000000c7,
|
||||
0x000200f9,0x0000003a,0x000200f8,0x0000003c,
|
||||
0x0004003d,0x0000000b,0x000000c9,0x00000017,
|
||||
0x0006000c,0x00000006,0x000000ca,0x00000001,
|
||||
0x00000042,0x000000c9,0x00050085,0x00000006,
|
||||
0x000000cb,0x0000004b,0x000000ca,0x00050083,
|
||||
0x00000006,0x000000cc,0x000000c8,0x000000cb,
|
||||
0x0006000c,0x00000006,0x000000cd,0x00000001,
|
||||
0x0000001f,0x000000cc,0x0004003d,0x00000032,
|
||||
0x000000ce,0x00000034,0x0005008e,0x00000032,
|
||||
0x000000cf,0x000000ce,0x000000cd,0x0003003e,
|
||||
0x00000034,0x000000cf,0x00050041,0x00000007,
|
||||
0x000000d2,0x00000034,0x00000027,0x0004003d,
|
||||
0x00000006,0x000000d3,0x000000d2,0x00050041,
|
||||
0x00000007,0x000000d4,0x00000034,0x0000002a,
|
||||
0x0004003d,0x00000006,0x000000d5,0x000000d4,
|
||||
0x00050041,0x00000007,0x000000d7,0x00000034,
|
||||
0x000000d6,0x0004003d,0x00000006,0x000000d8,
|
||||
0x000000d7,0x00070050,0x00000009,0x000000d9,
|
||||
0x000000d3,0x000000d5,0x000000d8,0x0000004b,
|
||||
0x0003003e,0x000000d1,0x000000d9,0x000100fd,
|
||||
0x00010038}
|
||||
@@ -0,0 +1,76 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(std140, set = 0, binding = 0) uniform UBO
|
||||
{
|
||||
mat4 MVP;
|
||||
vec2 OutputSize;
|
||||
float time;
|
||||
} constants;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
const float baseScale = 3.5; // [1.0 .. 10.0]
|
||||
const float density = 0.7; // [0.01 .. 1.0]
|
||||
const float speed = 0.25; // [0.1 .. 1.0]
|
||||
|
||||
float rand(vec2 co)
|
||||
{
|
||||
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
float dist_func(vec2 distv)
|
||||
{
|
||||
float dist = sqrt((distv.x * distv.x) + (distv.y * distv.y)) * (40.0 / baseScale);
|
||||
dist = clamp(dist, 0.0, 1.0);
|
||||
return cos(dist * (3.14159265358 * 0.5)) * 0.5;
|
||||
}
|
||||
|
||||
float random_dots(vec2 co)
|
||||
{
|
||||
float part = 1.0 / 20.0;
|
||||
vec2 cd = floor(co / part);
|
||||
float p = rand(cd);
|
||||
|
||||
if (p > 0.005 * (density * 40.0))
|
||||
return 0.0;
|
||||
|
||||
vec2 dpos = (vec2(fract(p * 2.0) , p) + vec2(2.0, 2.0)) * 0.25;
|
||||
|
||||
vec2 cellpos = fract(co / part);
|
||||
vec2 distv = (cellpos - dpos);
|
||||
|
||||
return dist_func(distv);
|
||||
}
|
||||
|
||||
float snow(vec2 pos, float time, float scale)
|
||||
{
|
||||
// add wobble
|
||||
pos.x += cos(pos.y * 1.2 + time * 3.14159 * 2.0 + 1.0 / scale) / (8.0 / scale) * 4.0;
|
||||
// add gravity
|
||||
pos += time * scale * vec2(-0.5, 1.0) * 4.0;
|
||||
return random_dots(pos / scale) * (scale * 0.5 + 0.5);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
float tim = constants.time * 0.4 * speed;
|
||||
vec2 pos = gl_FragCoord.xy / constants.OutputSize.xx;
|
||||
pos.y = 1.0 - pos.y; // Flip Y
|
||||
float a = 0.0;
|
||||
// Each of these is a layer of snow
|
||||
// Remove some for better performance
|
||||
// Changing the scale (3rd value) will mess with the looping
|
||||
a += snow(pos, tim, 1.0);
|
||||
a += snow(pos, tim, 0.7);
|
||||
a += snow(pos, tim, 0.6);
|
||||
a += snow(pos, tim, 0.5);
|
||||
a += snow(pos, tim, 0.4);
|
||||
a += snow(pos, tim, 0.3);
|
||||
a += snow(pos, tim, 0.25);
|
||||
a += snow(pos, tim, 0.125);
|
||||
a = a * min(pos.y * 4.0, 1.0);
|
||||
FragColor = vec4(1.0, 1.0, 1.0, a);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,523 @@
|
||||
{0x07230203,0x00010000,0x00080001,0x00000109,
|
||||
0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||
0x00000001,0x4c534c47,0x6474732e,0x3035342e,
|
||||
0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||
0x0007000f,0x00000004,0x00000004,0x6e69616d,
|
||||
0x00000000,0x000000ac,0x00000105,0x00030010,
|
||||
0x00000004,0x00000007,0x00030003,0x00000001,
|
||||
0x00000136,0x000a0004,0x475f4c47,0x4c474f4f,
|
||||
0x70635f45,0x74735f70,0x5f656c79,0x656e696c,
|
||||
0x7269645f,0x69746365,0x00006576,0x00080004,
|
||||
0x475f4c47,0x4c474f4f,0x6e695f45,0x64756c63,
|
||||
0x69645f65,0x74636572,0x00657669,0x00040005,
|
||||
0x00000004,0x6e69616d,0x00000000,0x00050005,
|
||||
0x0000000b,0x646e6172,0x32667628,0x0000003b,
|
||||
0x00030005,0x0000000a,0x00006f63,0x00060005,
|
||||
0x0000000e,0x74736964,0x6e75665f,0x66762863,
|
||||
0x00003b32,0x00040005,0x0000000d,0x74736964,
|
||||
0x00000076,0x00070005,0x00000011,0x646e6172,
|
||||
0x645f6d6f,0x2873746f,0x3b326676,0x00000000,
|
||||
0x00030005,0x00000010,0x00006f63,0x00060005,
|
||||
0x00000018,0x776f6e73,0x32667628,0x3b31663b,
|
||||
0x003b3166,0x00030005,0x00000015,0x00736f70,
|
||||
0x00040005,0x00000016,0x656d6974,0x00000000,
|
||||
0x00040005,0x00000017,0x6c616373,0x00000065,
|
||||
0x00040005,0x00000025,0x74736964,0x00000000,
|
||||
0x00040005,0x00000043,0x74726170,0x00000000,
|
||||
0x00030005,0x00000045,0x00006463,0x00030005,
|
||||
0x0000004b,0x00000070,0x00040005,0x0000004c,
|
||||
0x61726170,0x0000006d,0x00040005,0x00000056,
|
||||
0x736f7064,0x00000000,0x00040005,0x00000061,
|
||||
0x6c6c6563,0x00736f70,0x00040005,0x00000067,
|
||||
0x74736964,0x00000076,0x00040005,0x0000006b,
|
||||
0x61726170,0x0000006d,0x00040005,0x00000094,
|
||||
0x61726170,0x0000006d,0x00030005,0x0000009c,
|
||||
0x006d6974,0x00030005,0x0000009f,0x004f4255,
|
||||
0x00040006,0x0000009f,0x00000000,0x0050564d,
|
||||
0x00060006,0x0000009f,0x00000001,0x7074754f,
|
||||
0x69537475,0x0000657a,0x00050006,0x0000009f,
|
||||
0x00000002,0x656d6974,0x00000000,0x00050005,
|
||||
0x000000a1,0x736e6f63,0x746e6174,0x00000073,
|
||||
0x00030005,0x000000aa,0x00736f70,0x00060005,
|
||||
0x000000ac,0x465f6c67,0x43676172,0x64726f6f,
|
||||
0x00000000,0x00030005,0x000000b9,0x00000061,
|
||||
0x00040005,0x000000ba,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000bc,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000be,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000c3,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000c5,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000c7,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000cc,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000ce,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000d0,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000d4,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000d6,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000d8,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000dc,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000de,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000e0,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000e5,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000e7,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000e9,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000ed,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000ef,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000f1,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000f6,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000f8,0x61726170,0x0000006d,
|
||||
0x00040005,0x000000fa,0x61726170,0x0000006d,
|
||||
0x00050005,0x00000105,0x67617246,0x6f6c6f43,
|
||||
0x00000072,0x00030047,0x0000000b,0x00000000,
|
||||
0x00030047,0x0000000a,0x00000000,0x00030047,
|
||||
0x0000000e,0x00000000,0x00030047,0x0000000d,
|
||||
0x00000000,0x00030047,0x00000011,0x00000000,
|
||||
0x00030047,0x00000010,0x00000000,0x00030047,
|
||||
0x00000018,0x00000000,0x00030047,0x00000015,
|
||||
0x00000000,0x00030047,0x00000016,0x00000000,
|
||||
0x00030047,0x00000017,0x00000000,0x00030047,
|
||||
0x0000001a,0x00000000,0x00030047,0x0000001e,
|
||||
0x00000000,0x00030047,0x0000001f,0x00000000,
|
||||
0x00030047,0x00000021,0x00000000,0x00030047,
|
||||
0x00000022,0x00000000,0x00030047,0x00000025,
|
||||
0x00000000,0x00030047,0x00000029,0x00000000,
|
||||
0x00030047,0x0000002b,0x00000000,0x00030047,
|
||||
0x0000002c,0x00000000,0x00030047,0x0000002f,
|
||||
0x00000000,0x00030047,0x00000031,0x00000000,
|
||||
0x00030047,0x00000032,0x00000000,0x00030047,
|
||||
0x00000033,0x00000000,0x00030047,0x00000034,
|
||||
0x00000000,0x00030047,0x00000036,0x00000000,
|
||||
0x00030047,0x00000037,0x00000000,0x00030047,
|
||||
0x0000003a,0x00000000,0x00030047,0x0000003b,
|
||||
0x00000000,0x00030047,0x0000003d,0x00000000,
|
||||
0x00030047,0x0000003e,0x00000000,0x00030047,
|
||||
0x00000040,0x00000000,0x00030047,0x00000043,
|
||||
0x00000000,0x00030047,0x00000045,0x00000000,
|
||||
0x00030047,0x00000046,0x00000000,0x00030047,
|
||||
0x00000047,0x00000000,0x00030047,0x00000048,
|
||||
0x00000000,0x00030047,0x00000049,0x00000000,
|
||||
0x00030047,0x0000004a,0x00000000,0x00030047,
|
||||
0x0000004b,0x00000000,0x00030047,0x0000004d,
|
||||
0x00000000,0x00030047,0x0000004e,0x00000000,
|
||||
0x00030047,0x0000004f,0x00000000,0x00030047,
|
||||
0x00000056,0x00000000,0x00030047,0x00000057,
|
||||
0x00000000,0x00030047,0x00000059,0x00000000,
|
||||
0x00030047,0x0000005a,0x00000000,0x00030047,
|
||||
0x0000005b,0x00000000,0x00030047,0x0000005c,
|
||||
0x00000000,0x00030047,0x0000005e,0x00000000,
|
||||
0x00030047,0x00000060,0x00000000,0x00030047,
|
||||
0x00000061,0x00000000,0x00030047,0x00000062,
|
||||
0x00000000,0x00030047,0x00000063,0x00000000,
|
||||
0x00030047,0x00000064,0x00000000,0x00030047,
|
||||
0x00000065,0x00000000,0x00030047,0x00000066,
|
||||
0x00000000,0x00030047,0x00000067,0x00000000,
|
||||
0x00030047,0x00000068,0x00000000,0x00030047,
|
||||
0x00000069,0x00000000,0x00030047,0x0000006a,
|
||||
0x00000000,0x00030047,0x0000006c,0x00000000,
|
||||
0x00030047,0x0000006d,0x00000000,0x00030047,
|
||||
0x00000071,0x00000000,0x00030047,0x00000073,
|
||||
0x00000000,0x00030047,0x00000074,0x00000000,
|
||||
0x00030047,0x00000076,0x00000000,0x00030047,
|
||||
0x00000077,0x00000000,0x00030047,0x00000078,
|
||||
0x00000000,0x00030047,0x00000079,0x00000000,
|
||||
0x00030047,0x0000007a,0x00000000,0x00030047,
|
||||
0x0000007b,0x00000000,0x00030047,0x0000007c,
|
||||
0x00000000,0x00030047,0x0000007e,0x00000000,
|
||||
0x00030047,0x0000007f,0x00000000,0x00030047,
|
||||
0x00000080,0x00000000,0x00030047,0x00000082,
|
||||
0x00000000,0x00030047,0x00000084,0x00000000,
|
||||
0x00030047,0x00000085,0x00000000,0x00030047,
|
||||
0x00000087,0x00000000,0x00030047,0x00000088,
|
||||
0x00000000,0x00030047,0x00000089,0x00000000,
|
||||
0x00030047,0x0000008c,0x00000000,0x00030047,
|
||||
0x0000008d,0x00000000,0x00030047,0x0000008e,
|
||||
0x00000000,0x00030047,0x0000008f,0x00000000,
|
||||
0x00030047,0x00000090,0x00000000,0x00030047,
|
||||
0x00000091,0x00000000,0x00030047,0x00000092,
|
||||
0x00000000,0x00030047,0x00000093,0x00000000,
|
||||
0x00030047,0x00000095,0x00000000,0x00030047,
|
||||
0x00000096,0x00000000,0x00030047,0x00000097,
|
||||
0x00000000,0x00030047,0x00000098,0x00000000,
|
||||
0x00030047,0x00000099,0x00000000,0x00030047,
|
||||
0x0000009c,0x00000000,0x00040048,0x0000009f,
|
||||
0x00000000,0x00000005,0x00040048,0x0000009f,
|
||||
0x00000000,0x00000000,0x00050048,0x0000009f,
|
||||
0x00000000,0x00000023,0x00000000,0x00050048,
|
||||
0x0000009f,0x00000000,0x00000007,0x00000010,
|
||||
0x00040048,0x0000009f,0x00000001,0x00000000,
|
||||
0x00050048,0x0000009f,0x00000001,0x00000023,
|
||||
0x00000040,0x00040048,0x0000009f,0x00000002,
|
||||
0x00000000,0x00050048,0x0000009f,0x00000002,
|
||||
0x00000023,0x00000048,0x00030047,0x0000009f,
|
||||
0x00000002,0x00040047,0x000000a1,0x00000022,
|
||||
0x00000000,0x00040047,0x000000a1,0x00000021,
|
||||
0x00000000,0x00030047,0x000000a6,0x00000000,
|
||||
0x00030047,0x000000a8,0x00000000,0x00030047,
|
||||
0x000000a9,0x00000000,0x00030047,0x000000aa,
|
||||
0x00000000,0x00040047,0x000000ac,0x0000000b,
|
||||
0x0000000f,0x00030047,0x000000b2,0x00000000,
|
||||
0x00030047,0x000000b3,0x00000000,0x00030047,
|
||||
0x000000b6,0x00000000,0x00030047,0x000000b7,
|
||||
0x00000000,0x00030047,0x000000b9,0x00000000,
|
||||
0x00030047,0x000000bb,0x00000000,0x00030047,
|
||||
0x000000bd,0x00000000,0x00030047,0x000000bf,
|
||||
0x00000000,0x00030047,0x000000c0,0x00000000,
|
||||
0x00030047,0x000000c1,0x00000000,0x00030047,
|
||||
0x000000c4,0x00000000,0x00030047,0x000000c6,
|
||||
0x00000000,0x00030047,0x000000c8,0x00000000,
|
||||
0x00030047,0x000000c9,0x00000000,0x00030047,
|
||||
0x000000ca,0x00000000,0x00030047,0x000000cd,
|
||||
0x00000000,0x00030047,0x000000cf,0x00000000,
|
||||
0x00030047,0x000000d1,0x00000000,0x00030047,
|
||||
0x000000d2,0x00000000,0x00030047,0x000000d3,
|
||||
0x00000000,0x00030047,0x000000d5,0x00000000,
|
||||
0x00030047,0x000000d7,0x00000000,0x00030047,
|
||||
0x000000d9,0x00000000,0x00030047,0x000000da,
|
||||
0x00000000,0x00030047,0x000000db,0x00000000,
|
||||
0x00030047,0x000000dd,0x00000000,0x00030047,
|
||||
0x000000df,0x00000000,0x00030047,0x000000e1,
|
||||
0x00000000,0x00030047,0x000000e2,0x00000000,
|
||||
0x00030047,0x000000e3,0x00000000,0x00030047,
|
||||
0x000000e6,0x00000000,0x00030047,0x000000e8,
|
||||
0x00000000,0x00030047,0x000000ea,0x00000000,
|
||||
0x00030047,0x000000eb,0x00000000,0x00030047,
|
||||
0x000000ec,0x00000000,0x00030047,0x000000ee,
|
||||
0x00000000,0x00030047,0x000000f0,0x00000000,
|
||||
0x00030047,0x000000f2,0x00000000,0x00030047,
|
||||
0x000000f3,0x00000000,0x00030047,0x000000f4,
|
||||
0x00000000,0x00030047,0x000000f7,0x00000000,
|
||||
0x00030047,0x000000f9,0x00000000,0x00030047,
|
||||
0x000000fb,0x00000000,0x00030047,0x000000fc,
|
||||
0x00000000,0x00030047,0x000000fd,0x00000000,
|
||||
0x00030047,0x000000fe,0x00000000,0x00030047,
|
||||
0x00000100,0x00000000,0x00030047,0x00000101,
|
||||
0x00000000,0x00030047,0x00000102,0x00000000,
|
||||
0x00030047,0x00000103,0x00000000,0x00030047,
|
||||
0x00000105,0x00000000,0x00040047,0x00000105,
|
||||
0x0000001e,0x00000000,0x00030047,0x00000106,
|
||||
0x00000000,0x00030047,0x00000107,0x00000000,
|
||||
0x00030047,0x00000108,0x00000000,0x00030047,
|
||||
0x000000c2,0x00000000,0x00030047,0x0000005f,
|
||||
0x00000000,0x00020013,0x00000002,0x00030021,
|
||||
0x00000003,0x00000002,0x00030016,0x00000006,
|
||||
0x00000020,0x00040017,0x00000007,0x00000006,
|
||||
0x00000002,0x00040020,0x00000008,0x00000007,
|
||||
0x00000007,0x00040021,0x00000009,0x00000006,
|
||||
0x00000008,0x00040020,0x00000013,0x00000007,
|
||||
0x00000006,0x00060021,0x00000014,0x00000006,
|
||||
0x00000008,0x00000013,0x00000013,0x0004002b,
|
||||
0x00000006,0x0000001b,0x414fd639,0x0004002b,
|
||||
0x00000006,0x0000001c,0x429c774c,0x0005002c,
|
||||
0x00000007,0x0000001d,0x0000001b,0x0000001c,
|
||||
0x0004002b,0x00000006,0x00000020,0x472aee8c,
|
||||
0x00040015,0x00000026,0x00000020,0x00000000,
|
||||
0x0004002b,0x00000026,0x00000027,0x00000000,
|
||||
0x0004002b,0x00000026,0x0000002d,0x00000001,
|
||||
0x0004002b,0x00000006,0x00000035,0x4136db6e,
|
||||
0x0004002b,0x00000006,0x00000038,0x00000000,
|
||||
0x0004002b,0x00000006,0x00000039,0x3f800000,
|
||||
0x0004002b,0x00000006,0x0000003c,0x3fc90fdb,
|
||||
0x0004002b,0x00000006,0x0000003f,0x3f000000,
|
||||
0x0004002b,0x00000006,0x00000044,0x3d4ccccd,
|
||||
0x0004002b,0x00000006,0x00000050,0x3e0f5c29,
|
||||
0x00020014,0x00000051,0x0004002b,0x00000006,
|
||||
0x00000058,0x40000000,0x0005002c,0x00000007,
|
||||
0x0000005d,0x00000058,0x00000058,0x0004002b,
|
||||
0x00000006,0x0000005f,0x3e800000,0x0004002b,
|
||||
0x00000006,0x00000072,0x3f99999a,0x0004002b,
|
||||
0x00000006,0x00000075,0x40490fd0,0x0004002b,
|
||||
0x00000006,0x0000007d,0x41000000,0x0004002b,
|
||||
0x00000006,0x00000081,0x40800000,0x0004002b,
|
||||
0x00000006,0x0000008a,0xbf000000,0x0005002c,
|
||||
0x00000007,0x0000008b,0x0000008a,0x00000039,
|
||||
0x00040017,0x0000009d,0x00000006,0x00000004,
|
||||
0x00040018,0x0000009e,0x0000009d,0x00000004,
|
||||
0x0005001e,0x0000009f,0x0000009e,0x00000007,
|
||||
0x00000006,0x00040020,0x000000a0,0x00000002,
|
||||
0x0000009f,0x0004003b,0x000000a0,0x000000a1,
|
||||
0x00000002,0x00040015,0x000000a2,0x00000020,
|
||||
0x00000001,0x0004002b,0x000000a2,0x000000a3,
|
||||
0x00000002,0x00040020,0x000000a4,0x00000002,
|
||||
0x00000006,0x0004002b,0x00000006,0x000000a7,
|
||||
0x3ecccccd,0x00040020,0x000000ab,0x00000001,
|
||||
0x0000009d,0x0004003b,0x000000ab,0x000000ac,
|
||||
0x00000001,0x0004002b,0x000000a2,0x000000af,
|
||||
0x00000001,0x00040020,0x000000b0,0x00000002,
|
||||
0x00000007,0x0004002b,0x00000006,0x000000c2,
|
||||
0x3f333333,0x0004002b,0x00000006,0x000000cb,
|
||||
0x3f19999a,0x0004002b,0x00000006,0x000000e4,
|
||||
0x3e99999a,0x0004002b,0x00000006,0x000000f5,
|
||||
0x3e000000,0x00040020,0x00000104,0x00000003,
|
||||
0x0000009d,0x0004003b,0x00000104,0x00000105,
|
||||
0x00000003,0x0004002b,0x00000006,0x00000108,
|
||||
0x40600000,0x00050036,0x00000002,0x00000004,
|
||||
0x00000000,0x00000003,0x000200f8,0x00000005,
|
||||
0x0004003b,0x00000013,0x0000009c,0x00000007,
|
||||
0x0004003b,0x00000008,0x000000aa,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000b9,0x00000007,
|
||||
0x0004003b,0x00000008,0x000000ba,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000bc,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000be,0x00000007,
|
||||
0x0004003b,0x00000008,0x000000c3,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000c5,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000c7,0x00000007,
|
||||
0x0004003b,0x00000008,0x000000cc,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000ce,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000d0,0x00000007,
|
||||
0x0004003b,0x00000008,0x000000d4,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000d6,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000d8,0x00000007,
|
||||
0x0004003b,0x00000008,0x000000dc,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000de,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000e0,0x00000007,
|
||||
0x0004003b,0x00000008,0x000000e5,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000e7,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000e9,0x00000007,
|
||||
0x0004003b,0x00000008,0x000000ed,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000ef,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000f1,0x00000007,
|
||||
0x0004003b,0x00000008,0x000000f6,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000f8,0x00000007,
|
||||
0x0004003b,0x00000013,0x000000fa,0x00000007,
|
||||
0x00050041,0x000000a4,0x000000a5,0x000000a1,
|
||||
0x000000a3,0x0004003d,0x00000006,0x000000a6,
|
||||
0x000000a5,0x00050085,0x00000006,0x000000a8,
|
||||
0x000000a6,0x000000a7,0x00050085,0x00000006,
|
||||
0x000000a9,0x000000a8,0x0000005f,0x0003003e,
|
||||
0x0000009c,0x000000a9,0x0004003d,0x0000009d,
|
||||
0x000000ad,0x000000ac,0x0007004f,0x00000007,
|
||||
0x000000ae,0x000000ad,0x000000ad,0x00000000,
|
||||
0x00000001,0x00050041,0x000000b0,0x000000b1,
|
||||
0x000000a1,0x000000af,0x0004003d,0x00000007,
|
||||
0x000000b2,0x000000b1,0x0007004f,0x00000007,
|
||||
0x000000b3,0x000000b2,0x000000b2,0x00000000,
|
||||
0x00000000,0x00050088,0x00000007,0x000000b4,
|
||||
0x000000ae,0x000000b3,0x0003003e,0x000000aa,
|
||||
0x000000b4,0x00050041,0x00000013,0x000000b5,
|
||||
0x000000aa,0x0000002d,0x0004003d,0x00000006,
|
||||
0x000000b6,0x000000b5,0x00050083,0x00000006,
|
||||
0x000000b7,0x00000039,0x000000b6,0x00050041,
|
||||
0x00000013,0x000000b8,0x000000aa,0x0000002d,
|
||||
0x0003003e,0x000000b8,0x000000b7,0x0003003e,
|
||||
0x000000b9,0x00000038,0x0004003d,0x00000007,
|
||||
0x000000bb,0x000000aa,0x0003003e,0x000000ba,
|
||||
0x000000bb,0x0004003d,0x00000006,0x000000bd,
|
||||
0x0000009c,0x0003003e,0x000000bc,0x000000bd,
|
||||
0x0003003e,0x000000be,0x00000039,0x00070039,
|
||||
0x00000006,0x000000bf,0x00000018,0x000000ba,
|
||||
0x000000bc,0x000000be,0x0004003d,0x00000006,
|
||||
0x000000c0,0x000000b9,0x00050081,0x00000006,
|
||||
0x000000c1,0x000000c0,0x000000bf,0x0003003e,
|
||||
0x000000b9,0x000000c1,0x0004003d,0x00000007,
|
||||
0x000000c4,0x000000aa,0x0003003e,0x000000c3,
|
||||
0x000000c4,0x0004003d,0x00000006,0x000000c6,
|
||||
0x0000009c,0x0003003e,0x000000c5,0x000000c6,
|
||||
0x0003003e,0x000000c7,0x000000c2,0x00070039,
|
||||
0x00000006,0x000000c8,0x00000018,0x000000c3,
|
||||
0x000000c5,0x000000c7,0x0004003d,0x00000006,
|
||||
0x000000c9,0x000000b9,0x00050081,0x00000006,
|
||||
0x000000ca,0x000000c9,0x000000c8,0x0003003e,
|
||||
0x000000b9,0x000000ca,0x0004003d,0x00000007,
|
||||
0x000000cd,0x000000aa,0x0003003e,0x000000cc,
|
||||
0x000000cd,0x0004003d,0x00000006,0x000000cf,
|
||||
0x0000009c,0x0003003e,0x000000ce,0x000000cf,
|
||||
0x0003003e,0x000000d0,0x000000cb,0x00070039,
|
||||
0x00000006,0x000000d1,0x00000018,0x000000cc,
|
||||
0x000000ce,0x000000d0,0x0004003d,0x00000006,
|
||||
0x000000d2,0x000000b9,0x00050081,0x00000006,
|
||||
0x000000d3,0x000000d2,0x000000d1,0x0003003e,
|
||||
0x000000b9,0x000000d3,0x0004003d,0x00000007,
|
||||
0x000000d5,0x000000aa,0x0003003e,0x000000d4,
|
||||
0x000000d5,0x0004003d,0x00000006,0x000000d7,
|
||||
0x0000009c,0x0003003e,0x000000d6,0x000000d7,
|
||||
0x0003003e,0x000000d8,0x0000003f,0x00070039,
|
||||
0x00000006,0x000000d9,0x00000018,0x000000d4,
|
||||
0x000000d6,0x000000d8,0x0004003d,0x00000006,
|
||||
0x000000da,0x000000b9,0x00050081,0x00000006,
|
||||
0x000000db,0x000000da,0x000000d9,0x0003003e,
|
||||
0x000000b9,0x000000db,0x0004003d,0x00000007,
|
||||
0x000000dd,0x000000aa,0x0003003e,0x000000dc,
|
||||
0x000000dd,0x0004003d,0x00000006,0x000000df,
|
||||
0x0000009c,0x0003003e,0x000000de,0x000000df,
|
||||
0x0003003e,0x000000e0,0x000000a7,0x00070039,
|
||||
0x00000006,0x000000e1,0x00000018,0x000000dc,
|
||||
0x000000de,0x000000e0,0x0004003d,0x00000006,
|
||||
0x000000e2,0x000000b9,0x00050081,0x00000006,
|
||||
0x000000e3,0x000000e2,0x000000e1,0x0003003e,
|
||||
0x000000b9,0x000000e3,0x0004003d,0x00000007,
|
||||
0x000000e6,0x000000aa,0x0003003e,0x000000e5,
|
||||
0x000000e6,0x0004003d,0x00000006,0x000000e8,
|
||||
0x0000009c,0x0003003e,0x000000e7,0x000000e8,
|
||||
0x0003003e,0x000000e9,0x000000e4,0x00070039,
|
||||
0x00000006,0x000000ea,0x00000018,0x000000e5,
|
||||
0x000000e7,0x000000e9,0x0004003d,0x00000006,
|
||||
0x000000eb,0x000000b9,0x00050081,0x00000006,
|
||||
0x000000ec,0x000000eb,0x000000ea,0x0003003e,
|
||||
0x000000b9,0x000000ec,0x0004003d,0x00000007,
|
||||
0x000000ee,0x000000aa,0x0003003e,0x000000ed,
|
||||
0x000000ee,0x0004003d,0x00000006,0x000000f0,
|
||||
0x0000009c,0x0003003e,0x000000ef,0x000000f0,
|
||||
0x0003003e,0x000000f1,0x0000005f,0x00070039,
|
||||
0x00000006,0x000000f2,0x00000018,0x000000ed,
|
||||
0x000000ef,0x000000f1,0x0004003d,0x00000006,
|
||||
0x000000f3,0x000000b9,0x00050081,0x00000006,
|
||||
0x000000f4,0x000000f3,0x000000f2,0x0003003e,
|
||||
0x000000b9,0x000000f4,0x0004003d,0x00000007,
|
||||
0x000000f7,0x000000aa,0x0003003e,0x000000f6,
|
||||
0x000000f7,0x0004003d,0x00000006,0x000000f9,
|
||||
0x0000009c,0x0003003e,0x000000f8,0x000000f9,
|
||||
0x0003003e,0x000000fa,0x000000f5,0x00070039,
|
||||
0x00000006,0x000000fb,0x00000018,0x000000f6,
|
||||
0x000000f8,0x000000fa,0x0004003d,0x00000006,
|
||||
0x000000fc,0x000000b9,0x00050081,0x00000006,
|
||||
0x000000fd,0x000000fc,0x000000fb,0x0003003e,
|
||||
0x000000b9,0x000000fd,0x0004003d,0x00000006,
|
||||
0x000000fe,0x000000b9,0x00050041,0x00000013,
|
||||
0x000000ff,0x000000aa,0x0000002d,0x0004003d,
|
||||
0x00000006,0x00000100,0x000000ff,0x00050085,
|
||||
0x00000006,0x00000101,0x00000100,0x00000081,
|
||||
0x0007000c,0x00000006,0x00000102,0x00000001,
|
||||
0x00000025,0x00000101,0x00000039,0x00050085,
|
||||
0x00000006,0x00000103,0x000000fe,0x00000102,
|
||||
0x0003003e,0x000000b9,0x00000103,0x0004003d,
|
||||
0x00000006,0x00000106,0x000000b9,0x00070050,
|
||||
0x0000009d,0x00000107,0x00000039,0x00000039,
|
||||
0x00000039,0x00000106,0x0003003e,0x00000105,
|
||||
0x00000107,0x000100fd,0x00010038,0x00050036,
|
||||
0x00000006,0x0000000b,0x00000000,0x00000009,
|
||||
0x00030037,0x00000008,0x0000000a,0x000200f8,
|
||||
0x0000000c,0x0004003d,0x00000007,0x0000001a,
|
||||
0x0000000a,0x00050094,0x00000006,0x0000001e,
|
||||
0x0000001a,0x0000001d,0x0006000c,0x00000006,
|
||||
0x0000001f,0x00000001,0x0000000d,0x0000001e,
|
||||
0x00050085,0x00000006,0x00000021,0x0000001f,
|
||||
0x00000020,0x0006000c,0x00000006,0x00000022,
|
||||
0x00000001,0x0000000a,0x00000021,0x000200fe,
|
||||
0x00000022,0x00010038,0x00050036,0x00000006,
|
||||
0x0000000e,0x00000000,0x00000009,0x00030037,
|
||||
0x00000008,0x0000000d,0x000200f8,0x0000000f,
|
||||
0x0004003b,0x00000013,0x00000025,0x00000007,
|
||||
0x00050041,0x00000013,0x00000028,0x0000000d,
|
||||
0x00000027,0x0004003d,0x00000006,0x00000029,
|
||||
0x00000028,0x00050041,0x00000013,0x0000002a,
|
||||
0x0000000d,0x00000027,0x0004003d,0x00000006,
|
||||
0x0000002b,0x0000002a,0x00050085,0x00000006,
|
||||
0x0000002c,0x00000029,0x0000002b,0x00050041,
|
||||
0x00000013,0x0000002e,0x0000000d,0x0000002d,
|
||||
0x0004003d,0x00000006,0x0000002f,0x0000002e,
|
||||
0x00050041,0x00000013,0x00000030,0x0000000d,
|
||||
0x0000002d,0x0004003d,0x00000006,0x00000031,
|
||||
0x00000030,0x00050085,0x00000006,0x00000032,
|
||||
0x0000002f,0x00000031,0x00050081,0x00000006,
|
||||
0x00000033,0x0000002c,0x00000032,0x0006000c,
|
||||
0x00000006,0x00000034,0x00000001,0x0000001f,
|
||||
0x00000033,0x00050085,0x00000006,0x00000036,
|
||||
0x00000034,0x00000035,0x0003003e,0x00000025,
|
||||
0x00000036,0x0004003d,0x00000006,0x00000037,
|
||||
0x00000025,0x0008000c,0x00000006,0x0000003a,
|
||||
0x00000001,0x0000002b,0x00000037,0x00000038,
|
||||
0x00000039,0x0003003e,0x00000025,0x0000003a,
|
||||
0x0004003d,0x00000006,0x0000003b,0x00000025,
|
||||
0x00050085,0x00000006,0x0000003d,0x0000003b,
|
||||
0x0000003c,0x0006000c,0x00000006,0x0000003e,
|
||||
0x00000001,0x0000000e,0x0000003d,0x00050085,
|
||||
0x00000006,0x00000040,0x0000003e,0x0000003f,
|
||||
0x000200fe,0x00000040,0x00010038,0x00050036,
|
||||
0x00000006,0x00000011,0x00000000,0x00000009,
|
||||
0x00030037,0x00000008,0x00000010,0x000200f8,
|
||||
0x00000012,0x0004003b,0x00000013,0x00000043,
|
||||
0x00000007,0x0004003b,0x00000008,0x00000045,
|
||||
0x00000007,0x0004003b,0x00000013,0x0000004b,
|
||||
0x00000007,0x0004003b,0x00000008,0x0000004c,
|
||||
0x00000007,0x0004003b,0x00000008,0x00000056,
|
||||
0x00000007,0x0004003b,0x00000008,0x00000061,
|
||||
0x00000007,0x0004003b,0x00000008,0x00000067,
|
||||
0x00000007,0x0004003b,0x00000008,0x0000006b,
|
||||
0x00000007,0x0003003e,0x00000043,0x00000044,
|
||||
0x0004003d,0x00000007,0x00000046,0x00000010,
|
||||
0x0004003d,0x00000006,0x00000047,0x00000043,
|
||||
0x00050050,0x00000007,0x00000048,0x00000047,
|
||||
0x00000047,0x00050088,0x00000007,0x00000049,
|
||||
0x00000046,0x00000048,0x0006000c,0x00000007,
|
||||
0x0000004a,0x00000001,0x00000008,0x00000049,
|
||||
0x0003003e,0x00000045,0x0000004a,0x0004003d,
|
||||
0x00000007,0x0000004d,0x00000045,0x0003003e,
|
||||
0x0000004c,0x0000004d,0x00050039,0x00000006,
|
||||
0x0000004e,0x0000000b,0x0000004c,0x0003003e,
|
||||
0x0000004b,0x0000004e,0x0004003d,0x00000006,
|
||||
0x0000004f,0x0000004b,0x000500ba,0x00000051,
|
||||
0x00000052,0x0000004f,0x00000050,0x000300f7,
|
||||
0x00000054,0x00000000,0x000400fa,0x00000052,
|
||||
0x00000053,0x00000054,0x000200f8,0x00000053,
|
||||
0x000200fe,0x00000038,0x000200f8,0x00000054,
|
||||
0x0004003d,0x00000006,0x00000057,0x0000004b,
|
||||
0x00050085,0x00000006,0x00000059,0x00000057,
|
||||
0x00000058,0x0006000c,0x00000006,0x0000005a,
|
||||
0x00000001,0x0000000a,0x00000059,0x0004003d,
|
||||
0x00000006,0x0000005b,0x0000004b,0x00050050,
|
||||
0x00000007,0x0000005c,0x0000005a,0x0000005b,
|
||||
0x00050081,0x00000007,0x0000005e,0x0000005c,
|
||||
0x0000005d,0x0005008e,0x00000007,0x00000060,
|
||||
0x0000005e,0x0000005f,0x0003003e,0x00000056,
|
||||
0x00000060,0x0004003d,0x00000007,0x00000062,
|
||||
0x00000010,0x0004003d,0x00000006,0x00000063,
|
||||
0x00000043,0x00050050,0x00000007,0x00000064,
|
||||
0x00000063,0x00000063,0x00050088,0x00000007,
|
||||
0x00000065,0x00000062,0x00000064,0x0006000c,
|
||||
0x00000007,0x00000066,0x00000001,0x0000000a,
|
||||
0x00000065,0x0003003e,0x00000061,0x00000066,
|
||||
0x0004003d,0x00000007,0x00000068,0x00000061,
|
||||
0x0004003d,0x00000007,0x00000069,0x00000056,
|
||||
0x00050083,0x00000007,0x0000006a,0x00000068,
|
||||
0x00000069,0x0003003e,0x00000067,0x0000006a,
|
||||
0x0004003d,0x00000007,0x0000006c,0x00000067,
|
||||
0x0003003e,0x0000006b,0x0000006c,0x00050039,
|
||||
0x00000006,0x0000006d,0x0000000e,0x0000006b,
|
||||
0x000200fe,0x0000006d,0x00010038,0x00050036,
|
||||
0x00000006,0x00000018,0x00000000,0x00000014,
|
||||
0x00030037,0x00000008,0x00000015,0x00030037,
|
||||
0x00000013,0x00000016,0x00030037,0x00000013,
|
||||
0x00000017,0x000200f8,0x00000019,0x0004003b,
|
||||
0x00000008,0x00000094,0x00000007,0x00050041,
|
||||
0x00000013,0x00000070,0x00000015,0x0000002d,
|
||||
0x0004003d,0x00000006,0x00000071,0x00000070,
|
||||
0x00050085,0x00000006,0x00000073,0x00000071,
|
||||
0x00000072,0x0004003d,0x00000006,0x00000074,
|
||||
0x00000016,0x00050085,0x00000006,0x00000076,
|
||||
0x00000074,0x00000075,0x00050085,0x00000006,
|
||||
0x00000077,0x00000076,0x00000058,0x00050081,
|
||||
0x00000006,0x00000078,0x00000073,0x00000077,
|
||||
0x0004003d,0x00000006,0x00000079,0x00000017,
|
||||
0x00050088,0x00000006,0x0000007a,0x00000039,
|
||||
0x00000079,0x00050081,0x00000006,0x0000007b,
|
||||
0x00000078,0x0000007a,0x0006000c,0x00000006,
|
||||
0x0000007c,0x00000001,0x0000000e,0x0000007b,
|
||||
0x0004003d,0x00000006,0x0000007e,0x00000017,
|
||||
0x00050088,0x00000006,0x0000007f,0x0000007d,
|
||||
0x0000007e,0x00050088,0x00000006,0x00000080,
|
||||
0x0000007c,0x0000007f,0x00050085,0x00000006,
|
||||
0x00000082,0x00000080,0x00000081,0x00050041,
|
||||
0x00000013,0x00000083,0x00000015,0x00000027,
|
||||
0x0004003d,0x00000006,0x00000084,0x00000083,
|
||||
0x00050081,0x00000006,0x00000085,0x00000084,
|
||||
0x00000082,0x00050041,0x00000013,0x00000086,
|
||||
0x00000015,0x00000027,0x0003003e,0x00000086,
|
||||
0x00000085,0x0004003d,0x00000006,0x00000087,
|
||||
0x00000016,0x0004003d,0x00000006,0x00000088,
|
||||
0x00000017,0x00050085,0x00000006,0x00000089,
|
||||
0x00000087,0x00000088,0x0005008e,0x00000007,
|
||||
0x0000008c,0x0000008b,0x00000089,0x0005008e,
|
||||
0x00000007,0x0000008d,0x0000008c,0x00000081,
|
||||
0x0004003d,0x00000007,0x0000008e,0x00000015,
|
||||
0x00050081,0x00000007,0x0000008f,0x0000008e,
|
||||
0x0000008d,0x0003003e,0x00000015,0x0000008f,
|
||||
0x0004003d,0x00000007,0x00000090,0x00000015,
|
||||
0x0004003d,0x00000006,0x00000091,0x00000017,
|
||||
0x00050050,0x00000007,0x00000092,0x00000091,
|
||||
0x00000091,0x00050088,0x00000007,0x00000093,
|
||||
0x00000090,0x00000092,0x0003003e,0x00000094,
|
||||
0x00000093,0x00050039,0x00000006,0x00000095,
|
||||
0x00000011,0x00000094,0x0004003d,0x00000006,
|
||||
0x00000096,0x00000017,0x00050085,0x00000006,
|
||||
0x00000097,0x00000096,0x0000003f,0x00050081,
|
||||
0x00000006,0x00000098,0x00000097,0x0000003f,
|
||||
0x00050085,0x00000006,0x00000099,0x00000095,
|
||||
0x00000098,0x000200fe,0x00000099,0x00010038}
|
||||
@@ -1,18 +1,18 @@
|
||||
#version 310 es
|
||||
precision highp float;
|
||||
precision mediump float;
|
||||
|
||||
layout(std140, set = 0, binding = 0) uniform UBO
|
||||
{
|
||||
vec4 OutputSize;
|
||||
mat4 MVP;
|
||||
vec2 OutputSize;
|
||||
float time;
|
||||
} global;
|
||||
} constants;
|
||||
|
||||
layout(location = 0) in vec2 vTexCoord;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
float baseScale = 1.25; // [1.0 .. 10.0]
|
||||
float density = 0.5; // [0.01 .. 1.0]
|
||||
float speed = 0.15; // [0.1 .. 1.0]
|
||||
const float baseScale = 1.25; // [1.0 .. 10.0]
|
||||
const float density = 0.5; // [0.01 .. 1.0]
|
||||
const float speed = 0.15; // [0.1 .. 1.0]
|
||||
|
||||
float rand(vec2 co)
|
||||
{
|
||||
@@ -29,7 +29,7 @@ float dist_func(vec2 distv)
|
||||
float random_dots(vec2 co)
|
||||
{
|
||||
float part = 1.0 / 20.0;
|
||||
vec2 cd = floor(co / vec2(part));
|
||||
vec2 cd = floor(co / part);
|
||||
float p = rand(cd);
|
||||
|
||||
if (p > 0.005 * (density * 40.0))
|
||||
@@ -47,19 +47,17 @@ float snow(vec2 pos, float time, float scale)
|
||||
{
|
||||
// add wobble
|
||||
pos.x += cos(pos.y * 1.2 + time * 3.14159 * 2.0 + 1.0 / scale) / (8.0 / scale) * 4.0;
|
||||
|
||||
// add gravity
|
||||
pos += time * scale * vec2(-0.5, 1.0) * 4.0;
|
||||
|
||||
return random_dots(pos / vec2(scale)) * (scale * 0.5 + 0.5);
|
||||
return random_dots(pos / scale) * (scale * 0.5 + 0.5);
|
||||
}
|
||||
|
||||
void main()
|
||||
void main(void)
|
||||
{
|
||||
float tim = global.time * 0.4 * speed;
|
||||
vec2 pos = vTexCoord.xy / global.OutputSize.xx;
|
||||
float tim = constants.time * 0.4 * speed;
|
||||
vec2 pos = gl_FragCoord.xy / constants.OutputSize.xx;
|
||||
pos.y = 1.0 - pos.y; // Flip Y
|
||||
float a = 0.0;
|
||||
|
||||
// Each of these is a layer of snow
|
||||
// Remove some for better performance
|
||||
// Changing the scale (3rd value) will mess with the looping
|
||||
@@ -72,6 +70,7 @@ void main()
|
||||
a += snow(pos, tim, 0.25);
|
||||
a += snow(pos, tim, 0.125);
|
||||
a = a * min(pos.y * 4.0, 1.0);
|
||||
|
||||
FragColor = vec4(1.0, 1.0, 1.0, a);
|
||||
}
|
||||
|
||||
|
||||