mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-22 12:40:31 +00:00
Merge branch 'master' into vr
This commit is contained in:
15
.github/scripts/Windows/install_spout.sh
vendored
Executable file
15
.github/scripts/Windows/install_spout.sh
vendored
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh -eux
|
||||
# Install SPOUT
|
||||
|
||||
git clone --depth 1 https://github.com/leadedge/Spout2.git
|
||||
mkdir Spout2/SpoutSDK/Source/build
|
||||
cd Spout2/SpoutSDK/Source/build
|
||||
cmake -DBUILD_SHARED_LIBS=ON -G 'MSYS Makefiles' ..
|
||||
cmake --build .
|
||||
cp libSpout.dll /usr/local/bin
|
||||
cp libSpout.dll.a /usr/local/lib
|
||||
cd -
|
||||
mkdir /usr/local/include/SpoutSDK
|
||||
cp Spout2/SpoutSDK/Source/*.h /usr/local/include/SpoutSDK
|
||||
rm -rf Spout2
|
||||
|
||||
13
.github/scripts/Windows/prepare_msys.sh
vendored
13
.github/scripts/Windows/prepare_msys.sh
vendored
@@ -6,7 +6,7 @@ mkdir -p /usr/local/lib /usr/local/bin /usr/local/include
|
||||
cat >> ~/.bash_profile <<'EOF'
|
||||
export PATH=/mingw64/bin:/usr/local/bin:$PATH
|
||||
export CPATH=/usr/local/include
|
||||
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/mingw64/lib/pkgconfig
|
||||
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:/mingw64/lib/pkgconfig
|
||||
export LIBRARY_PATH=/usr/local/lib
|
||||
|
||||
CUDA_D=$(ls -d /c/Program\ Files/NVIDIA\ GPU\ Computing\ Toolkit/CUDA/*)
|
||||
@@ -27,7 +27,10 @@ if test -d "$JACK_D"; then
|
||||
export LIBRARY_PATH=$LIBRARY_PATH:$JACK_D/lib
|
||||
fi
|
||||
|
||||
unset temp tmp # defined by /etc/profile, causes CineForm MSBuild fail (GitHub issue #99)
|
||||
|
||||
cd `cygpath $GITHUB_WORKSPACE`
|
||||
|
||||
EOF
|
||||
|
||||
. ~/.bash_profile
|
||||
@@ -61,11 +64,7 @@ cd /c/live555
|
||||
make install
|
||||
cd -
|
||||
|
||||
# Install SPOUT
|
||||
wget --no-verbose https://frakira.fi.muni.cz/~xpulec/SpoutSDK.zip # this is the SDK subdirectory installed by Spout installer
|
||||
unzip SpoutSDK.zip -d src
|
||||
MSBuild.exe -p:PlatformToolset=v142 -p:Configuration=Release -p:Platform=x64 src/SpoutSDK/VS2012
|
||||
data/scripts/build_spout64.sh src/SpoutSDK/VS2012/x64/Release
|
||||
$GITHUB_WORKSPACE/.github/scripts/Windows/install_spout.sh
|
||||
|
||||
# Install FFMPEG
|
||||
wget --no-verbose https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full-shared.7z && 7z x ffmpeg-release-full-shared.7z && cp -r ffmpeg-*build-shared/{bin,lib,include} /usr/local && rm -rf ffmpeg-* || exit 1
|
||||
@@ -74,5 +73,5 @@ wget --no-verbose https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full-shared.
|
||||
( wget --no-verbose https://github.com/CESNET/GPUJPEG/releases/download/continuous/GPUJPEG.zip && unzip GPUJPEG.zip && cp -r GPUJPEG/* /usr/local || exit 1 )
|
||||
|
||||
# Build CineForm
|
||||
( git submodule update --init cineform-sdk && cd cineform-sdk && cmake -DBUILD_STATIC=false -DBUILD_TOOLS=false -A x64 && MSBuild.exe CineFormSDK.sln -property:Configuration=Release && cp Release/CFHDCodec.dll /usr/local/bin && cp Release/CFHDCodec.lib /usr/local/lib && cp Common/* /usr/local/include && cp libcineformsdk.pc /usr/local/lib/pkgconfig || exit 1 )
|
||||
( git submodule update --init cineform-sdk && cd cineform-sdk && cmake -DBUILD_STATIC=false -DBUILD_TOOLS=false -A x64 . && MSBuild.exe CineFormSDK.sln -property:Configuration=Release && cp Release/CFHDCodec.dll /usr/local/bin && cp Release/CFHDCodec.lib /usr/local/lib && cp Common/* /usr/local/include && cp libcineformsdk.pc /usr/local/lib/pkgconfig || exit 1 )
|
||||
|
||||
|
||||
70
COPYRIGHT
70
COPYRIGHT
@@ -1,5 +1,5 @@
|
||||
|
||||
UltraGrid - A High Definition Collaboratory
|
||||
===========================================
|
||||
|
||||
Copyright (c) 2005-2018 CESNET z.s.p.o.
|
||||
Copyright (c) 2013-2014 Fundació i2CAT, Internet I Innovació Digital a Catalunya
|
||||
@@ -60,3 +60,71 @@ UltraGrid - A High Definition Collaboratory
|
||||
for use in the OpenSSL Toolkit. (http://www.openssl.org/)
|
||||
This product includes EmbeddableWebServer created by Forrest Heller.
|
||||
|
||||
External libraries
|
||||
------------------
|
||||
|
||||
### libnatpmp
|
||||
|
||||
Copyright (c) 2007-2011, 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.
|
||||
|
||||
### Speex
|
||||
|
||||
Copyright 2002-2008 Xiph.org Foundation
|
||||
Copyright 2002-2008 Jean-Marc Valin
|
||||
Copyright 2005-2007 Analog Devices Inc.
|
||||
Copyright 2005-2008 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO)
|
||||
Copyright 1993, 2002, 2006 David Rowe
|
||||
Copyright 2003 EpicGames
|
||||
Copyright 1992-1994 Jutta Degener, Carsten Bormann
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of the Xiph.org Foundation nor the names of its
|
||||
contributors may 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 FOUNDATION 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.
|
||||
|
||||
16
Makefile.in
16
Makefile.in
@@ -139,6 +139,7 @@ COMMON_OBJS = \
|
||||
src/utils/jpeg_reader.o \
|
||||
src/utils/list.o \
|
||||
src/utils/misc.o \
|
||||
src/utils/nat.o \
|
||||
src/utils/net.o \
|
||||
src/utils/packet_counter.o \
|
||||
src/utils/resource_manager.o \
|
||||
@@ -195,6 +196,7 @@ COMMON_OBJS = \
|
||||
ldgm/matrix-gen/matrix-generator.o \
|
||||
ldgm/matrix-gen/ldpc-matrix.o \
|
||||
rs/fec.o \
|
||||
ext-deps/libnatpmp-20150609/libnatpmp.a \
|
||||
|
||||
OBJS = @OBJS@ \
|
||||
$(COMMON_OBJS)
|
||||
@@ -269,6 +271,17 @@ lib/libug$(DLEXT): src/dir-stamp $(OBJS) $(GENERATED_HEADERS) src/libug.o
|
||||
%.cu.lib: %.cu $(ALL_INCLUDES)
|
||||
$(MKDIR_P) $(dir $@)
|
||||
"$(CUDA_COMPILER)" $(CUDA_FLAGS) -DEXPORT_DLL_SYMBOLS $(INC) --shared $< -o $<.dll
|
||||
touch $@
|
||||
|
||||
ext-deps/libnatpmp-20150609/libnatpmp.a:
|
||||
$(MKDIR_P) $(dir $@)
|
||||
ifeq ($(SYSTEM),Windows)
|
||||
cd $(srcdir)/ext-deps/libnatpmp-20150609 && cmd /c build.bat
|
||||
mv $(srcdir)/ext-deps/libnatpmp-20150609/natpmp.a $(dir $@)/libnatpmp.a
|
||||
else
|
||||
make -C $(srcdir)/ext-deps/libnatpmp-20150609 libnatpmp.a
|
||||
[ -f $@ ] || mv $(srcdir)/ext-deps/libnatpmp-20150609/libnatpmp.a $(dir $@)
|
||||
endif
|
||||
|
||||
src/libavcodec_common.o: src/libavcodec_common.c $(ALL_INCLUDES)
|
||||
$(MKDIR_P) $(dir $@)
|
||||
@@ -673,7 +686,6 @@ install: all
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(docdir)
|
||||
$(INSTALL) -m 644 $(DOCS) $(DESTDIR)$(docdir)
|
||||
$(INSTALL) -m 644 $(srcdir)/CONTRIBUTING.md $(srcdir)/COPYRIGHT $(srcdir)/INSTALL $(srcdir)/NEWS $(srcdir)/README.md $(DESTDIR)$(docdir)
|
||||
$(CP) $(srcdir)/speex-1.2rc1/COPYING $(DESTDIR)$(docdir)/COPYING.speex
|
||||
$(INSTALL) -m 755 $(srcdir)/data/ultragrid-bugreport-collect.sh $(DESTDIR)$(docdir)
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
|
||||
$(INSTALL) -m 644 $(srcdir)/data/uv.1 $(srcdir)/data/hd-rum-transcode.1 $(DESTDIR)$(man1dir)
|
||||
@@ -685,7 +697,6 @@ uninstall:
|
||||
if [ -n "@MODULES@" ]; then for n in @MODULES@; do $(RM) $(DESTDIR)$(libdir)/ultragrid/`basename $$n`; done; fi
|
||||
for n in $(DOCS); do $(RM) $(DESTDIR)$(docdir)$$n; done;
|
||||
$(RM) $(DESTDIR)$(docdir)/CONTRIBUTING.md $(DESTDIR)$(docdir)/COPYRIGHT $(DESTDIR)$(docdir)/INSTALL $(DESTDIR)$(docdir)/NEWS $(DESTDIR)$(docdir)/README.md
|
||||
$(RM) $(DESTDIR)$(docdir)/COPYING.speex
|
||||
$(RM) $(DESTDIR)$(docdir)/ultragrid-bugreport-collect.sh
|
||||
if [ -f "$(GUI_TARGET)" ]; then \
|
||||
$(RM) $(DESTDIR)$(bindir)/`basename $(GUI_TARGET)`;\
|
||||
@@ -693,3 +704,4 @@ uninstall:
|
||||
$(RM) $(DESTDIR)$(datadir)/pixmaps/ultragrid.png;\
|
||||
fi
|
||||
|
||||
# vim: set noexpandtab
|
||||
|
||||
28
configure.ac
28
configure.ac
@@ -2201,9 +2201,16 @@ AC_ARG_ENABLE(gpujpeg,
|
||||
[gpujpeg_req=$build_default])
|
||||
|
||||
|
||||
PKG_CHECK_MODULES([LIBGPUJPEG], [libgpujpeg >= 0.0.2 ], [found_gpujpeg=yes], [found_gpujpeg=no])
|
||||
PKG_CHECK_MODULES([LIBGPUJPEG_ANY], [ libgpujpeg ], [ found_gpujpeg_any=yes ], [ found_gpujpeg_any=no ])
|
||||
PKG_CHECK_MODULES([LIBGPUJPEG], [ libgpujpeg >= 0.11 ], [ found_gpujpeg=yes ], [ found_gpujpeg=no ])
|
||||
|
||||
if test "$found_gpujpeg" != yes
|
||||
if test "$found_gpujpeg_any" = yes -a "$found_gpujpeg" = no; then
|
||||
AC_MSG_WARN([Old GPUJPEG version found, please upgrade]);
|
||||
fi
|
||||
|
||||
# try to find without pkg-config (but only if old version was not detected - to avoid side-loading
|
||||
# that version without pkg-config version check)
|
||||
if test "$found_gpujpeg_any" != yes -a "$found_gpujpeg" != yes
|
||||
then
|
||||
GPUJPEG_LIB="$GPUJPEG_LIB -lgpujpeg"
|
||||
SAVED_LIBS=$LIBS
|
||||
@@ -2896,17 +2903,24 @@ AC_ARG_ENABLE(spout,
|
||||
[spout_req=$build_default]
|
||||
)
|
||||
|
||||
FOUND_SPOUT_WRAPPER=no
|
||||
FOUND_SPOUT=no
|
||||
if test $system = Windows
|
||||
then
|
||||
AC_CHECK_LIB(spout_wrapper, spout_create_receiver, [FOUND_SPOUT_WRAPPER=yes])
|
||||
AC_LANG_PUSH([C++])
|
||||
SAVED_LIBS="$LIBS"
|
||||
LIBS="$LIBS -lSpout"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <SpoutSDK/Spout.h>]],
|
||||
[[SpoutSender *sender = new SpoutSender;]])],
|
||||
FOUND_SPOUT=yes, FOUND_SPOUT=no)
|
||||
LIBS=$SAVED_LIBS
|
||||
AC_LANG_POP([C++])
|
||||
fi
|
||||
|
||||
if test $spout_req != no -a "$OPENGL" = yes -a $FOUND_SPOUT_WRAPPER = yes
|
||||
if test $spout_req != no -a "$OPENGL" = yes -a $FOUND_SPOUT = yes
|
||||
then
|
||||
AC_DEFINE([HAVE_SPOUT], [1], [Build with Spout support])
|
||||
LIBS="$LIBS -lspout_wrapper"
|
||||
OBJS="$OBJS src/video_capture/spout.o"
|
||||
LIBS="$LIBS -lSpout"
|
||||
OBJS="$OBJS src/spout_sender.o src/video_capture/spout.o"
|
||||
spout=yes
|
||||
fi
|
||||
|
||||
|
||||
1
data/README.md
Normal file
1
data/README.md
Normal file
@@ -0,0 +1 @@
|
||||
screen-capture-recorder-x64.dll is taken from https://sourceforge.net/projects/screencapturer/
|
||||
0
data/screen-capture-recorder-x64.dll
Executable file → Normal file
0
data/screen-capture-recorder-x64.dll
Executable file → Normal file
@@ -1,47 +0,0 @@
|
||||
#!/bin/bash -eu
|
||||
|
||||
#######################################
|
||||
# USAGE
|
||||
#
|
||||
# 1) Copy SpoutSDK to src
|
||||
# 2) run build_spout.sh (this script)
|
||||
#######################################
|
||||
|
||||
function run_in_vs_env
|
||||
{
|
||||
eval vssetup=\$$1'\\..\\..\\VC\\bin\\amd64\\vcvars64.bat'
|
||||
cmd //Q //C call "$vssetup" "&&" "${@:2}"
|
||||
}
|
||||
|
||||
function run_vs16
|
||||
{
|
||||
eval vssetup='C:\\Program\ Files\ \(x86\)\\Microsoft\ Visual\ Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat'
|
||||
cmd //Q //C call "$vssetup" "&&" "$@"
|
||||
}
|
||||
|
||||
function run_vs12
|
||||
{
|
||||
run_in_vs_env VS120COMNTOOLS "$@"
|
||||
}
|
||||
|
||||
|
||||
function run_vs11
|
||||
{
|
||||
run_in_vs_env VS110COMNTOOLS "$@"
|
||||
}
|
||||
|
||||
function run_vs10
|
||||
{
|
||||
run_in_vs_env VS100COMNTOOLS "$@"
|
||||
}
|
||||
|
||||
LIBDIR=${1:-src/SpoutSDK/Binaries/x64}
|
||||
MSVS_PATH=`/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/Installer/vswhere.exe -latest -property installationPath`
|
||||
|
||||
eval vssetup=\"$MSVS_PATH\"'\\VC\\Auxiliary\\Build\\vcvars64.bat'
|
||||
cmd //Q //C call "$vssetup" "&&" cl //DEXPORT_DLL_SYMBOLS src/spout_sender.cpp src/spout_receiver.cpp //LD $LIBDIR/Spout.lib //Fespout_wrapper
|
||||
|
||||
cp spout_wrapper.dll /usr/local/bin
|
||||
cp spout_wrapper.lib /usr/local/lib
|
||||
cp $LIBDIR/Spout.dll /usr/local/bin
|
||||
|
||||
7
ext-deps/libnatpmp-20150609/.gitignore
vendored
Normal file
7
ext-deps/libnatpmp-20150609/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
!*
|
||||
*.a
|
||||
*.o
|
||||
*.so
|
||||
natpmpc-shared
|
||||
natpmpc-static
|
||||
testgetgateway
|
||||
98
ext-deps/libnatpmp-20150609/Changelog.txt
Normal file
98
ext-deps/libnatpmp-20150609/Changelog.txt
Normal file
@@ -0,0 +1,98 @@
|
||||
$Id: Changelog.txt,v 1.33 2013/11/26 08:47:36 nanard Exp $
|
||||
|
||||
2013/11/26:
|
||||
enforce strict aliasing rules.
|
||||
|
||||
2013/09/10:
|
||||
small patch for MSVC >= 16
|
||||
rename win32 implementation of gettimeofday() to natpmp_gettimeofday()
|
||||
|
||||
2012/08/21:
|
||||
Little change in Makefile
|
||||
removed warnings in testgetgateway.c
|
||||
Fixed bugs in command line argumentparsing in natpmpc.c
|
||||
|
||||
2011/08/07:
|
||||
Patch to build on debian/kFreeBSD.
|
||||
|
||||
2011/07/15:
|
||||
Put 3 clauses BSD licence at the top of source files.
|
||||
|
||||
2011/06/18:
|
||||
--no-undefined => -Wl,--no-undefined
|
||||
adding a natpmpc.1 man page
|
||||
|
||||
2011/05/19:
|
||||
Small fix in libnatpmpmodule.c thanks to Manuel Mausz
|
||||
|
||||
2011/01/03:
|
||||
Added an argument to initnatpmp() in order to force the gateway to be used
|
||||
|
||||
2011/01/01:
|
||||
fix in make install
|
||||
|
||||
2010/05/21:
|
||||
make install now working under MacOSX (and BSD)
|
||||
|
||||
2010/04/12:
|
||||
cplusplus stuff in natpmp.h
|
||||
|
||||
2010/02/02:
|
||||
Fixed compilation under Mac OS X
|
||||
|
||||
2009/12/19:
|
||||
improve and fix building under Windows.
|
||||
Project files for MS Visual Studio 2008
|
||||
More simple (and working) code for Win32.
|
||||
More checks in the /proc/net/route parsing. Add some comments.
|
||||
|
||||
2009/08/04:
|
||||
improving getgateway.c for windows
|
||||
|
||||
2009/07/13:
|
||||
Adding Haiku code in getgateway.c
|
||||
|
||||
2009/06/04:
|
||||
Adding Python module thanks to David Wu
|
||||
|
||||
2009/03/10:
|
||||
Trying to have windows get gateway working if not using DHCP
|
||||
|
||||
2009/02/27:
|
||||
dont include declspec.h if not under WIN32.
|
||||
|
||||
2009/01/23:
|
||||
Prefixed the libraries name with lib
|
||||
|
||||
2008/10/06:
|
||||
Fixed a memory leak in getdefaultgateway() (USE_SYSCTL_NET_ROUTE)
|
||||
|
||||
2008/07/03:
|
||||
Adding WIN32 code from Robbie Hanson
|
||||
|
||||
2008/06/30:
|
||||
added a Solaris implementation for getgateway().
|
||||
added a LICENCE file to the distribution
|
||||
|
||||
2008/05/29:
|
||||
Anonymous unions are forbidden in ANSI C. That was causing problems with
|
||||
non-GCC compilers.
|
||||
|
||||
2008/04/28:
|
||||
introduced strnatpmperr()
|
||||
improved natpmpc.c sample
|
||||
make install now install the binary
|
||||
|
||||
2007/12/13:
|
||||
Fixed getgateway.c for working under OS X ;)
|
||||
Fixed values for NATPMP_PROTOCOL_TCP and NATPMP_PROTOCOL_UDP
|
||||
|
||||
2007/12/11:
|
||||
Fixed getgateway.c for compilation under Mac OS X
|
||||
|
||||
2007/12/01:
|
||||
added some comments in .h
|
||||
|
||||
2007/11/30:
|
||||
implemented almost everything
|
||||
|
||||
42
ext-deps/libnatpmp-20150609/JavaTest.java
Normal file
42
ext-deps/libnatpmp-20150609/JavaTest.java
Normal file
@@ -0,0 +1,42 @@
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import fr.free.miniupnp.libnatpmp.NatPmp;
|
||||
import fr.free.miniupnp.libnatpmp.NatPmpResponse;
|
||||
|
||||
class JavaTest {
|
||||
public static void main(String[] args) {
|
||||
NatPmp natpmp = new NatPmp();
|
||||
|
||||
natpmp.sendPublicAddressRequest();
|
||||
NatPmpResponse response = new NatPmpResponse();
|
||||
|
||||
int result = -1;
|
||||
do{
|
||||
result = natpmp.readNatPmpResponseOrRetry(response);
|
||||
try {
|
||||
Thread.sleep(4000);
|
||||
} catch (InterruptedException e) {
|
||||
//fallthrough
|
||||
}
|
||||
} while (result != 0);
|
||||
|
||||
byte[] bytes = intToByteArray(response.addr);
|
||||
|
||||
try {
|
||||
InetAddress inetAddress = InetAddress.getByAddress(bytes);
|
||||
System.out.println("Public address is " + inetAddress);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final byte[] intToByteArray(int value) {
|
||||
return new byte[] {
|
||||
(byte)value,
|
||||
(byte)(value >>> 8),
|
||||
(byte)(value >>> 16),
|
||||
(byte)(value >>> 24)};
|
||||
}
|
||||
}
|
||||
26
ext-deps/libnatpmp-20150609/LICENSE
Normal file
26
ext-deps/libnatpmp-20150609/LICENSE
Normal file
@@ -0,0 +1,26 @@
|
||||
Copyright (c) 2007-2011, 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.
|
||||
|
||||
177
ext-deps/libnatpmp-20150609/Makefile
Normal file
177
ext-deps/libnatpmp-20150609/Makefile
Normal file
@@ -0,0 +1,177 @@
|
||||
# $Id: Makefile,v 1.23 2013/11/26 16:38:15 nanard Exp $
|
||||
# This Makefile is designed for use with GNU make
|
||||
# libnatpmp
|
||||
# (c) 2007-2013 Thomas Bernard
|
||||
# http://miniupnp.free.fr/libnatpmp.html
|
||||
|
||||
OS = $(shell uname -s)
|
||||
CC = gcc
|
||||
INSTALL = install -p
|
||||
ARCH = $(shell uname -m | sed -e s/i.86/i686/)
|
||||
VERSION = $(shell cat VERSION)
|
||||
|
||||
ifeq ($(OS), Darwin)
|
||||
JARSUFFIX=mac
|
||||
endif
|
||||
ifeq ($(OS), Linux)
|
||||
JARSUFFIX=linux
|
||||
endif
|
||||
ifneq (,$(findstring WIN,$(OS)))
|
||||
JARSUFFIX=win32
|
||||
endif
|
||||
|
||||
# APIVERSION is used in soname
|
||||
APIVERSION = 1
|
||||
#LDFLAGS = -Wl,--no-undefined
|
||||
CFLAGS ?= -Os
|
||||
#CFLAGS = -g -O0
|
||||
CFLAGS += -fPIC
|
||||
CFLAGS += -Wall
|
||||
#CFLAGS += -Wextra
|
||||
CFLAGS += -DENABLE_STRNATPMPERR
|
||||
#CFLAGS += -Wstrict-aliasing
|
||||
|
||||
LIBOBJS = natpmp.o getgateway.o
|
||||
|
||||
OBJS = $(LIBOBJS) testgetgateway.o natpmpc.o natpmp-jni.o
|
||||
|
||||
STATICLIB = libnatpmp.a
|
||||
ifeq ($(OS), Darwin)
|
||||
SHAREDLIB = libnatpmp.dylib
|
||||
JNISHAREDLIB = libjninatpmp.dylib
|
||||
SONAME = $(basename $(SHAREDLIB)).$(APIVERSION).dylib
|
||||
CFLAGS := -DMACOSX -D_DARWIN_C_SOURCE $(CFLAGS)
|
||||
SONAMEFLAGS=-Wl,-install_name,$(JNISHAREDLIB) -dynamiclib -framework JavaVM
|
||||
else
|
||||
ifneq (,$(findstring WIN,$(OS)))
|
||||
SHAREDLIB = natpmp.dll
|
||||
JNISHAREDLIB = jninatpmp.dll
|
||||
CC = i686-w64-mingw32-gcc
|
||||
EXTRA_LD = -lws2_32 -lIphlpapi -Wl,--no-undefined -Wl,--enable-runtime-pseudo-reloc --Wl,kill-at
|
||||
else
|
||||
SHAREDLIB = libnatpmp.so
|
||||
JNISHAREDLIB = libjninatpmp.so
|
||||
SONAME = $(SHAREDLIB).$(APIVERSION)
|
||||
SONAMEFLAGS=-Wl,-soname,$(JNISHAREDLIB)
|
||||
endif
|
||||
endif
|
||||
|
||||
HEADERS = natpmp.h
|
||||
|
||||
EXECUTABLES = testgetgateway natpmpc-shared natpmpc-static
|
||||
|
||||
INSTALLPREFIX ?= $(PREFIX)/usr
|
||||
INSTALLDIRINC = $(INSTALLPREFIX)/include
|
||||
INSTALLDIRLIB = $(INSTALLPREFIX)/lib
|
||||
INSTALLDIRBIN = $(INSTALLPREFIX)/bin
|
||||
|
||||
JAVA ?= java
|
||||
JAVAC ?= javac
|
||||
JAVAH ?= javah
|
||||
JAVAPACKAGE = fr/free/miniupnp/libnatpmp
|
||||
JAVACLASSES = $(JAVAPACKAGE)/NatPmp.class $(JAVAPACKAGE)/NatPmpResponse.class $(JAVAPACKAGE)/LibraryExtractor.class $(JAVAPACKAGE)/URLUtils.class
|
||||
JNIHEADERS = fr_free_miniupnp_libnatpmp_NatPmp.h
|
||||
|
||||
.PHONY: all clean depend install cleaninstall installpythonmodule
|
||||
|
||||
all: $(STATICLIB) $(SHAREDLIB) $(EXECUTABLES)
|
||||
|
||||
pythonmodule: $(STATICLIB) libnatpmpmodule.c setup.py
|
||||
python setup.py build
|
||||
touch $@
|
||||
|
||||
installpythonmodule: pythonmodule
|
||||
python setup.py install
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJS) $(EXECUTABLES) $(STATICLIB) $(SHAREDLIB) $(JAVACLASSES) $(JNISHAREDLIB)
|
||||
$(RM) pythonmodule
|
||||
$(RM) -r build/ dist/ libraries/
|
||||
|
||||
depend:
|
||||
makedepend -f$(MAKEFILE_LIST) -Y $(OBJS:.o=.c) 2>/dev/null
|
||||
|
||||
install: $(HEADERS) $(STATICLIB) $(SHAREDLIB) natpmpc-shared
|
||||
$(INSTALL) -d $(INSTALLDIRINC)
|
||||
$(INSTALL) -m 644 $(HEADERS) $(INSTALLDIRINC)
|
||||
$(INSTALL) -d $(INSTALLDIRLIB)
|
||||
$(INSTALL) -m 644 $(STATICLIB) $(INSTALLDIRLIB)
|
||||
$(INSTALL) -m 644 $(SHAREDLIB) $(INSTALLDIRLIB)/$(SONAME)
|
||||
$(INSTALL) -d $(INSTALLDIRBIN)
|
||||
$(INSTALL) -m 755 natpmpc-shared $(INSTALLDIRBIN)/natpmpc
|
||||
ln -s -f $(SONAME) $(INSTALLDIRLIB)/$(SHAREDLIB)
|
||||
|
||||
$(JNIHEADERS): fr/free/miniupnp/libnatpmp/NatPmp.class
|
||||
$(JAVAH) -jni fr.free.miniupnp.libnatpmp.NatPmp
|
||||
|
||||
%.class: %.java
|
||||
$(JAVAC) -cp . $<
|
||||
|
||||
$(JNISHAREDLIB): $(SHAREDLIB) $(JNIHEADERS) $(JAVACLASSES)
|
||||
ifeq (,$(JAVA_HOME))
|
||||
@echo "Check your JAVA_HOME environement variable" && false
|
||||
endif
|
||||
ifneq (,$(findstring WIN,$(OS)))
|
||||
$(CC) -m32 -D_JNI_Implementation_ -Wl,--kill-at \
|
||||
-I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/win32" \
|
||||
natpmp-jni.c -shared \
|
||||
-o $(JNISHAREDLIB) -L. -lnatpmp -lws2_32 -lIphlpapi
|
||||
else
|
||||
$(CC) $(CFLAGS) -c -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/win32" natpmp-jni.c
|
||||
$(CC) $(CFLAGS) -o $(JNISHAREDLIB) -shared $(SONAMEFLAGS) natpmp-jni.o -lc -L. -lnatpmp
|
||||
endif
|
||||
|
||||
jar: $(JNISHAREDLIB)
|
||||
find fr -name '*.class' -print > classes.list
|
||||
$(eval JNISHAREDLIBPATH := $(shell java fr.free.miniupnp.libnatpmp.LibraryExtractor))
|
||||
mkdir -p libraries/$(JNISHAREDLIBPATH)
|
||||
mv $(JNISHAREDLIB) libraries/$(JNISHAREDLIBPATH)/$(JNISHAREDLIB)
|
||||
jar cf natpmp_$(JARSUFFIX).jar @classes.list libraries/$(JNISHAREDLIBPATH)/$(JNISHAREDLIB)
|
||||
$(RM) classes.list
|
||||
|
||||
jnitest: $(JNISHAREDLIB) JavaTest.class
|
||||
$(RM) libjninatpmp.so
|
||||
$(JAVA) -Djna.nosys=true -cp . JavaTest
|
||||
|
||||
mvn_install:
|
||||
mvn install:install-file -Dfile=java/natpmp_$(JARSUFFIX).jar \
|
||||
-DgroupId=com.github \
|
||||
-DartifactId=natpmp \
|
||||
-Dversion=$(VERSION) \
|
||||
-Dpackaging=jar \
|
||||
-Dclassifier=$(JARSUFFIX) \
|
||||
-DgeneratePom=true \
|
||||
-DcreateChecksum=true
|
||||
|
||||
cleaninstall:
|
||||
$(RM) $(addprefix $(INSTALLDIRINC), $(HEADERS))
|
||||
$(RM) $(INSTALLDIRLIB)/$(SONAME)
|
||||
$(RM) $(INSTALLDIRLIB)/$(SHAREDLIB)
|
||||
$(RM) $(INSTALLDIRLIB)/$(STATICLIB)
|
||||
|
||||
testgetgateway: testgetgateway.o getgateway.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(EXTRA_LD)
|
||||
|
||||
natpmpc-static: natpmpc.o $(STATICLIB)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(EXTRA_LD)
|
||||
|
||||
natpmpc-shared: natpmpc.o $(SHAREDLIB)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(EXTRA_LD)
|
||||
|
||||
$(STATICLIB): $(LIBOBJS)
|
||||
$(AR) crs $@ $?
|
||||
|
||||
$(SHAREDLIB): $(LIBOBJS)
|
||||
ifeq ($(OS), Darwin)
|
||||
$(CC) -dynamiclib -Wl,-install_name,$(SONAME) -o $@ $^
|
||||
else
|
||||
$(CC) -shared -Wl,-soname,$(SONAME) -o $@ $^ $(EXTRA_LD)
|
||||
endif
|
||||
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
natpmp.o: natpmp.h getgateway.h declspec.h
|
||||
getgateway.o: getgateway.h declspec.h
|
||||
testgetgateway.o: getgateway.h declspec.h
|
||||
natpmpc.o: natpmp.h
|
||||
7
ext-deps/libnatpmp-20150609/README
Normal file
7
ext-deps/libnatpmp-20150609/README
Normal file
@@ -0,0 +1,7 @@
|
||||
libnatpmp (c) 2007-2009 Thomas Bernard
|
||||
contact : miniupnp@free.fr
|
||||
|
||||
see http://miniupnp.free.fr/libnatpmp.html
|
||||
or http://miniupnp.tuxfamily.org/libnatpmp.html
|
||||
for some documentation and code samples.
|
||||
|
||||
30
ext-deps/libnatpmp-20150609/build.bat
Normal file
30
ext-deps/libnatpmp-20150609/build.bat
Normal file
@@ -0,0 +1,30 @@
|
||||
@echo Compiling with MinGW
|
||||
@SET LIBS=-lws2_32 -liphlpapi
|
||||
|
||||
@echo Compile getgateway
|
||||
gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR getgateway.c
|
||||
gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR testgetgateway.c
|
||||
gcc -o testgetgateway getgateway.o testgetgateway.o %LIBS%
|
||||
del testgetgateway.o
|
||||
|
||||
@echo Compile natpmp-static:
|
||||
gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR getgateway.c
|
||||
gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR natpmp.c
|
||||
gcc -c -Wall -Os -DWIN32 wingettimeofday.c
|
||||
ar cr natpmp.a getgateway.o natpmp.o wingettimeofday.o
|
||||
del getgateway.o natpmp.o
|
||||
gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR natpmpc.c
|
||||
gcc -o natpmpc-static natpmpc.o natpmp.a %LIBS%
|
||||
upx --best natpmpc-static.exe
|
||||
del natpmpc.o
|
||||
|
||||
@echo Create natpmp.dll:
|
||||
gcc -c -Wall -Os -DWIN32 -DENABLE_STRNATPMPERR -DNATPMP_EXPORTS getgateway.c
|
||||
gcc -c -Wall -Os -DWIN32 -DENABLE_STRNATPMPERR -DNATPMP_EXPORTS natpmp.c
|
||||
dllwrap -k --driver-name gcc --def natpmp.def --output-def natpmp.dll.def --implib natpmp.lib -o natpmp.dll getgateway.o natpmp.o wingettimeofday.o %LIBS%
|
||||
|
||||
@echo Compile natpmp-shared:
|
||||
gcc -c -Wall -Os -DWIN32 -DENABLE_STRNATPMPERR -DNATPMP_EXPORTS natpmpc.c
|
||||
gcc -o natpmpc-shared natpmpc.o natpmp.lib -lws2_32
|
||||
upx --best natpmpc-shared.exe
|
||||
del *.o
|
||||
21
ext-deps/libnatpmp-20150609/declspec.h
Normal file
21
ext-deps/libnatpmp-20150609/declspec.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef DECLSPEC_H_INCLUDED
|
||||
#define DECLSPEC_H_INCLUDED
|
||||
|
||||
#if defined(WIN32) && !defined(STATICLIB)
|
||||
/* for windows dll */
|
||||
#ifdef NATPMP_EXPORTS
|
||||
#define LIBSPEC __declspec(dllexport)
|
||||
#else
|
||||
#define LIBSPEC __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
/* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */
|
||||
#define LIBSPEC __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define LIBSPEC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
package fr.free.miniupnp.libnatpmp;
|
||||
|
||||
/** I (Leah X Schmidt) copied this code from jnaerator, because
|
||||
JNAerator's extractor requires you to buy into the whole JNA
|
||||
concept.
|
||||
|
||||
JNAErator is
|
||||
Copyright (c) 2009 Olivier Chafik, All Rights Reserved
|
||||
|
||||
JNAerator 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 Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
JNAerator 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 JNAerator. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class LibraryExtractor {
|
||||
|
||||
private static boolean libPathSet = false;
|
||||
|
||||
public static String getLibraryPath(String libraryName, boolean extractAllLibraries, Class<?> cl) {
|
||||
try {
|
||||
String customPath = System.getProperty("library." + libraryName);
|
||||
if (customPath == null)
|
||||
customPath = System.getenv(libraryName.toUpperCase() + "_LIBRARY");
|
||||
if (customPath != null) {
|
||||
File f = new File(customPath);
|
||||
if (!f.exists())
|
||||
System.err.println("Library file '" + customPath + "' does not exist !");
|
||||
else
|
||||
return f.getAbsolutePath();
|
||||
}
|
||||
//ClassLoader cl = LibraryExtractor.class.getClassLoader();
|
||||
String prefix = "(?i)" + (isWindows() ? "" : "lib") + libraryName + "[^A-Za-z_].*";
|
||||
String libsuffix = "(?i).*\\.(so|dll|dylib|jnilib)";
|
||||
//String othersuffix = "(?i).*\\.(pdb)";
|
||||
|
||||
URL sourceURL = null;
|
||||
List<URL> otherURLs = new ArrayList<URL>();
|
||||
|
||||
|
||||
String arch = getCurrentOSAndArchString();
|
||||
//System.out.println("libURL = " + libURL);
|
||||
List<URL> list = URLUtils.listFiles(URLUtils.getResource(cl, "libraries/" + arch)),
|
||||
noArchList = URLUtils.listFiles(URLUtils.getResource(cl, "libraries/noarch"));
|
||||
|
||||
Set<String> names = new HashSet<String>();
|
||||
for (URL url : list) {
|
||||
String name = getFileName(url);
|
||||
names.add(name);
|
||||
}
|
||||
for (URL url : noArchList) {
|
||||
String name = getFileName(url);
|
||||
if (names.add(name))
|
||||
list.add(url);
|
||||
}
|
||||
|
||||
for (File f : new File(".").listFiles())
|
||||
if (f.isFile())
|
||||
list.add(f.toURI().toURL());
|
||||
|
||||
for (URL url : list) {
|
||||
String name = getFileName(url);
|
||||
boolean pref = name.matches(prefix), suff = name.matches(libsuffix);
|
||||
if (pref && suff)
|
||||
sourceURL = url;
|
||||
else //if (suff || fileName.matches(othersuffix))
|
||||
otherURLs.add(url);
|
||||
}
|
||||
List<File> files = new ArrayList<File>();
|
||||
if (extractAllLibraries) {
|
||||
for (URL url : otherURLs)
|
||||
files.add(extract(url));
|
||||
}
|
||||
|
||||
if (System.getProperty("javawebstart.version") != null) {
|
||||
if (isWindows()) {
|
||||
//File f = new File("c:\\Windows\\" + (Platform.is64Bit() ? "SysWOW64\\" : "System32\\") + libraryName + ".dll");
|
||||
File f = new File("c:\\Windows\\" + "System32\\" + libraryName + ".dll");
|
||||
if (f.exists())
|
||||
return f.toString();
|
||||
} else if (isMac()) {
|
||||
File f = new File("/System/Library/Frameworks/" + libraryName + ".framework/" + libraryName);
|
||||
if (f.exists())
|
||||
return f.toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceURL == null)
|
||||
return libraryName;
|
||||
else {
|
||||
File file = extract(sourceURL);
|
||||
files.add(file);
|
||||
|
||||
int lastSize;
|
||||
do {
|
||||
lastSize = files.size();
|
||||
for (Iterator<File> it = files.iterator(); it.hasNext();) {
|
||||
File f = it.next();
|
||||
if (!f.getName().matches(libsuffix))
|
||||
continue;
|
||||
|
||||
try {
|
||||
System.load(f.toString());
|
||||
it.remove();
|
||||
} catch (Throwable ex) {
|
||||
System.err.println("Loading " + f.getName() + " failed (" + ex + ")");
|
||||
}
|
||||
}
|
||||
} while (files.size() < lastSize);
|
||||
|
||||
return file.getCanonicalPath();
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
System.err.println("ERROR: Failed to extract library " + libraryName);
|
||||
ex.printStackTrace();
|
||||
return libraryName;
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean isWindows() {
|
||||
String osName = System.getProperty("os.name");
|
||||
return osName.startsWith("Windows");
|
||||
}
|
||||
|
||||
public static final boolean isMac() {
|
||||
String osName = System.getProperty("os.name");
|
||||
return osName.startsWith("Mac") || osName.startsWith("Darwin");
|
||||
}
|
||||
|
||||
//this code is from JNA, but JNA has a fallback to some native
|
||||
//stuff in case this doesn't work. Since sun.arch.data.model is
|
||||
//defined for Sun and IBM, this should work nearly everywhere.
|
||||
public static final boolean is64Bit() {
|
||||
String model = System.getProperty("sun.arch.data.model",
|
||||
System.getProperty("com.ibm.vm.bitmode"));
|
||||
if (model != null) {
|
||||
return "64".equals(model);
|
||||
}
|
||||
String arch = System.getProperty("os.arch").toLowerCase();
|
||||
if ("x86_64".equals(arch)
|
||||
|| "ia64".equals(arch)
|
||||
|| "ppc64".equals(arch)
|
||||
|| "sparcv9".equals(arch)
|
||||
|| "amd64".equals(arch)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getCurrentOSAndArchString() {
|
||||
String os = System.getProperty("os.name"), arch = System.getProperty("os.arch");
|
||||
if (os.equals("Mac OS X")) {
|
||||
os = "darwin";
|
||||
arch = "fat";
|
||||
} else if (os.startsWith("Windows")) {
|
||||
return "win" + (is64Bit() ? "64" : "32");
|
||||
} else if (os.matches("SunOS|Solaris"))
|
||||
os = "solaris";
|
||||
return os + "-" + arch;
|
||||
}
|
||||
|
||||
private static File extract(URL url) throws IOException {
|
||||
File localFile;
|
||||
if ("file".equals(url.getProtocol()))
|
||||
localFile = new File(URLDecoder.decode(url.getFile(), "UTF-8"));
|
||||
else {
|
||||
File f = new File(System.getProperty("user.home"));
|
||||
f = new File(f, ".jnaerator");
|
||||
f = new File(f, "extractedLibraries");
|
||||
if (!f.exists())
|
||||
f.mkdirs();
|
||||
|
||||
if (!libPathSet) {
|
||||
String path = System.getProperty("java.library.path");
|
||||
if (path == null) {
|
||||
System.setProperty("java.library.path", f.toString());
|
||||
} else {
|
||||
System.setProperty("java.library.path", path + ":" + f);
|
||||
}
|
||||
|
||||
libPathSet = true;
|
||||
}
|
||||
localFile = new File(f, new File(url.getFile()).getName());
|
||||
URLConnection c = url.openConnection();
|
||||
if (localFile.exists() && localFile.lastModified() > c.getLastModified()) {
|
||||
c.getInputStream().close();
|
||||
} else {
|
||||
System.out.println("Extracting " + url);
|
||||
InputStream in = c.getInputStream();
|
||||
OutputStream out = new FileOutputStream(localFile);
|
||||
int len;
|
||||
byte[] b = new byte[1024];
|
||||
while ((len = in.read(b)) > 0)
|
||||
out.write(b, 0, len);
|
||||
out.close();
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
return localFile;
|
||||
}
|
||||
|
||||
private static String getFileName(URL url) {
|
||||
return new File(url.getFile()).getName();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(getCurrentOSAndArchString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package fr.free.miniupnp.libnatpmp;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
public class NatPmp {
|
||||
private static final String JNA_LIBRARY_NAME = LibraryExtractor.getLibraryPath("jninatpmp", true, NatPmp.class);
|
||||
|
||||
static {
|
||||
String s = JNA_LIBRARY_NAME;
|
||||
startup();
|
||||
}
|
||||
|
||||
public ByteBuffer natpmp;
|
||||
|
||||
public NatPmp() {
|
||||
init(0, 0);
|
||||
}
|
||||
|
||||
public NatPmp(int forcedgw) {
|
||||
init(1, forcedgw);
|
||||
}
|
||||
|
||||
/** Cleans up the native resources used by this object.
|
||||
Attempting to use the object after this has been called
|
||||
will lead to crashes.*/
|
||||
public void dispose() {
|
||||
free();
|
||||
}
|
||||
|
||||
|
||||
protected void finalize() {
|
||||
if (natpmp != null)
|
||||
free();
|
||||
}
|
||||
|
||||
private native void init(int forcegw, int forcedgw);
|
||||
private native void free();
|
||||
|
||||
private static native void startup();
|
||||
|
||||
public native int sendPublicAddressRequest();
|
||||
public native int sendNewPortMappingRequest(int protocol, int privateport, int publicport, int lifetime);
|
||||
|
||||
//returns a number of milliseconds, in accordance with Java convention
|
||||
public native long getNatPmpRequestTimeout();
|
||||
|
||||
public native int readNatPmpResponseOrRetry(NatPmpResponse response);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package fr.free.miniupnp.libnatpmp;
|
||||
|
||||
public class NatPmpResponse {
|
||||
|
||||
public static final int TYPE_PUBLICADDRESS=0;
|
||||
public static final int TYPE_UDPPORTMAPPING=1;
|
||||
public static final int TYPE_TCPPORTMAPPING=2;
|
||||
|
||||
/** see TYPE_* constants */
|
||||
public short type;
|
||||
/** NAT-PMP response code */
|
||||
public short resultcode;
|
||||
/** milliseconds since start of epoch */
|
||||
public long epoch;
|
||||
|
||||
/** only defined if type == 0*/
|
||||
public int addr;
|
||||
|
||||
/** only defined if type != 0 */
|
||||
public int privateport;
|
||||
|
||||
/** only defined if type != 0 */
|
||||
public int mappedpublicport;
|
||||
|
||||
/** only defined if type != 0 */
|
||||
public long lifetime; //milliseconds
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package fr.free.miniupnp.libnatpmp;
|
||||
|
||||
/** I (Leah X Schmidt) copied this code from jnaerator, because
|
||||
JNAerator's extractor requires you to buy into the whole JNA
|
||||
concept.
|
||||
|
||||
JNAErator is
|
||||
Copyright (c) 2009 Olivier Chafik, All Rights Reserved
|
||||
|
||||
JNAerator 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 Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
JNAerator 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 JNAerator. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
|
||||
public class URLUtils {
|
||||
|
||||
public static URL getResource(Class<?> cl, String path) throws IOException {
|
||||
String clp = cl.getName().replace('.', '/') + ".class";
|
||||
URL clu = cl.getClassLoader().getResource(clp);
|
||||
String s = clu.toString();
|
||||
if (s.endsWith(clp))
|
||||
return new URL(s.substring(0, s.length() - clp.length()) + path);
|
||||
|
||||
if (s.startsWith("jar:")) {
|
||||
String[] ss = s.split("!");
|
||||
return new URL(ss[1] + "!/" + path);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<URL> listFiles(URL directory) throws IOException {
|
||||
List<URL> ret = new ArrayList<URL>();
|
||||
String s = directory.toString();
|
||||
if (s.startsWith("jar:")) {
|
||||
String[] ss = s.substring("jar:".length()).split("!");
|
||||
String path = ss[1];
|
||||
URL target = new URL(ss[0]);
|
||||
InputStream tin = target.openStream();
|
||||
try {
|
||||
JarInputStream jin = new JarInputStream(tin);
|
||||
JarEntry je;
|
||||
while ((je = jin.getNextJarEntry()) != null) {
|
||||
String p = "/" + je.getName();
|
||||
if (p.startsWith(path) && p.indexOf('/', path.length() + 1) < 0)
|
||||
|
||||
ret.add(new URL("jar:" + target + "!" + p));
|
||||
}
|
||||
} finally {
|
||||
tin.close();
|
||||
}
|
||||
} else if (s.startsWith("file:")) {
|
||||
File f = new File(directory.getFile());
|
||||
File[] ffs = f.listFiles();
|
||||
if (ffs != null)
|
||||
for (File ff : ffs)
|
||||
ret.add(ff.toURI().toURL());
|
||||
} else
|
||||
throw new IOException("Cannot list contents of " + directory);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
573
ext-deps/libnatpmp-20150609/getgateway.c
Normal file
573
ext-deps/libnatpmp-20150609/getgateway.c
Normal file
@@ -0,0 +1,573 @@
|
||||
/* $Id: getgateway.c,v 1.25 2014/04/22 10:28:57 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
|
||||
Copyright (c) 2007-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 <stdio.h>
|
||||
#include <ctype.h>
|
||||
#ifndef WIN32
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#if !defined(_MSC_VER)
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
/* There is no portable method to get the default route gateway.
|
||||
* So below are four (or five ?) differents functions implementing this.
|
||||
* Parsing /proc/net/route is for linux.
|
||||
* sysctl is the way to access such informations on BSD systems.
|
||||
* Many systems should provide route information through raw PF_ROUTE
|
||||
* sockets.
|
||||
* In MS Windows, default gateway is found by looking into the registry
|
||||
* or by using GetBestRoute(). */
|
||||
#ifdef __linux__
|
||||
#define USE_PROC_NET_ROUTE
|
||||
#undef USE_SOCKET_ROUTE
|
||||
#undef USE_SYSCTL_NET_ROUTE
|
||||
#endif
|
||||
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
#undef USE_PROC_NET_ROUTE
|
||||
#define USE_SOCKET_ROUTE
|
||||
#undef USE_SYSCTL_NET_ROUTE
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#undef USE_PROC_NET_ROUTE
|
||||
#undef USE_SOCKET_ROUTE
|
||||
#define USE_SYSCTL_NET_ROUTE
|
||||
#endif
|
||||
|
||||
#if (defined(sun) && defined(__SVR4))
|
||||
#undef USE_PROC_NET_ROUTE
|
||||
#define USE_SOCKET_ROUTE
|
||||
#undef USE_SYSCTL_NET_ROUTE
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#undef USE_PROC_NET_ROUTE
|
||||
#undef USE_SOCKET_ROUTE
|
||||
#undef USE_SYSCTL_NET_ROUTE
|
||||
//#define USE_WIN32_CODE
|
||||
#define USE_WIN32_CODE_2
|
||||
#endif
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
#undef USE_PROC_NET_ROUTE
|
||||
#undef USE_SOCKET_ROUTE
|
||||
#undef USE_SYSCTL_NET_ROUTE
|
||||
#define USE_WIN32_CODE
|
||||
#include <stdarg.h>
|
||||
#include <w32api/windef.h>
|
||||
#include <w32api/winbase.h>
|
||||
#include <w32api/winreg.h>
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/sockio.h>
|
||||
#define USE_HAIKU_CODE
|
||||
#endif
|
||||
|
||||
#ifdef USE_SYSCTL_NET_ROUTE
|
||||
#include <stdlib.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
#ifdef USE_SOCKET_ROUTE
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIN32_CODE
|
||||
#include <unknwn.h>
|
||||
#include <winreg.h>
|
||||
#define MAX_KEY_LENGTH 255
|
||||
#define MAX_VALUE_LENGTH 16383
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIN32_CODE_2
|
||||
#include <windows.h>
|
||||
#include <iphlpapi.h>
|
||||
#endif
|
||||
|
||||
#include "getgateway.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#define SUCCESS (0)
|
||||
#define FAILED (-1)
|
||||
#endif
|
||||
|
||||
#ifdef USE_PROC_NET_ROUTE
|
||||
/*
|
||||
parse /proc/net/route which is as follow :
|
||||
|
||||
Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
wlan0 0001A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0
|
||||
eth0 0000FEA9 00000000 0001 0 0 0 0000FFFF 0 0 0
|
||||
wlan0 00000000 0101A8C0 0003 0 0 0 00000000 0 0 0
|
||||
eth0 00000000 00000000 0001 0 0 1000 00000000 0 0 0
|
||||
|
||||
One header line, and then one line by route by route table entry.
|
||||
*/
|
||||
int getdefaultgateway(in_addr_t * addr)
|
||||
{
|
||||
unsigned long d, g;
|
||||
char buf[256];
|
||||
int line = 0;
|
||||
FILE * f;
|
||||
char * p;
|
||||
f = fopen("/proc/net/route", "r");
|
||||
if(!f)
|
||||
return FAILED;
|
||||
while(fgets(buf, sizeof(buf), f)) {
|
||||
if(line > 0) { /* skip the first line */
|
||||
p = buf;
|
||||
/* skip the interface name */
|
||||
while(*p && !isspace(*p))
|
||||
p++;
|
||||
while(*p && isspace(*p))
|
||||
p++;
|
||||
if(sscanf(p, "%lx%lx", &d, &g)==2) {
|
||||
if(d == 0 && g != 0) { /* default */
|
||||
*addr = g;
|
||||
fclose(f);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
line++;
|
||||
}
|
||||
/* default route not found ! */
|
||||
if(f)
|
||||
fclose(f);
|
||||
return FAILED;
|
||||
}
|
||||
#endif /* #ifdef USE_PROC_NET_ROUTE */
|
||||
|
||||
|
||||
#ifdef USE_SYSCTL_NET_ROUTE
|
||||
|
||||
#define ROUNDUP(a) \
|
||||
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
|
||||
|
||||
int getdefaultgateway(in_addr_t * addr)
|
||||
{
|
||||
#if 0
|
||||
/* net.route.0.inet.dump.0.0 ? */
|
||||
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
|
||||
NET_RT_DUMP, 0, 0/*tableid*/};
|
||||
#endif
|
||||
/* net.route.0.inet.flags.gateway */
|
||||
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
|
||||
NET_RT_FLAGS, RTF_GATEWAY};
|
||||
size_t l;
|
||||
char * buf, * p;
|
||||
struct rt_msghdr * rt;
|
||||
struct sockaddr * sa;
|
||||
struct sockaddr * sa_tab[RTAX_MAX];
|
||||
int i;
|
||||
int r = FAILED;
|
||||
if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
|
||||
return FAILED;
|
||||
}
|
||||
if(l>0) {
|
||||
buf = malloc(l);
|
||||
if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
|
||||
free(buf);
|
||||
return FAILED;
|
||||
}
|
||||
for(p=buf; p<buf+l; p+=rt->rtm_msglen) {
|
||||
rt = (struct rt_msghdr *)p;
|
||||
sa = (struct sockaddr *)(rt + 1);
|
||||
for(i=0; i<RTAX_MAX; i++) {
|
||||
if(rt->rtm_addrs & (1 << i)) {
|
||||
sa_tab[i] = sa;
|
||||
sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
|
||||
} else {
|
||||
sa_tab[i] = NULL;
|
||||
}
|
||||
}
|
||||
if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
|
||||
&& sa_tab[RTAX_DST]->sa_family == AF_INET
|
||||
&& sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
|
||||
if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
|
||||
*addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
|
||||
r = SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif /* #ifdef USE_SYSCTL_NET_ROUTE */
|
||||
|
||||
|
||||
#ifdef USE_SOCKET_ROUTE
|
||||
/* Thanks to Darren Kenny for this code */
|
||||
#define NEXTADDR(w, u) \
|
||||
if (rtm_addrs & (w)) {\
|
||||
l = sizeof(struct sockaddr); memmove(cp, &(u), l); cp += l;\
|
||||
}
|
||||
|
||||
#define rtm m_rtmsg.m_rtm
|
||||
|
||||
struct {
|
||||
struct rt_msghdr m_rtm;
|
||||
char m_space[512];
|
||||
} m_rtmsg;
|
||||
|
||||
int getdefaultgateway(in_addr_t *addr)
|
||||
{
|
||||
int s, seq, l, rtm_addrs, i;
|
||||
pid_t pid;
|
||||
struct sockaddr so_dst, so_mask;
|
||||
char *cp = m_rtmsg.m_space;
|
||||
struct sockaddr *gate = NULL, *sa;
|
||||
struct rt_msghdr *msg_hdr;
|
||||
|
||||
pid = getpid();
|
||||
seq = 0;
|
||||
rtm_addrs = RTA_DST | RTA_NETMASK;
|
||||
|
||||
memset(&so_dst, 0, sizeof(so_dst));
|
||||
memset(&so_mask, 0, sizeof(so_mask));
|
||||
memset(&rtm, 0, sizeof(struct rt_msghdr));
|
||||
|
||||
rtm.rtm_type = RTM_GET;
|
||||
rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
|
||||
rtm.rtm_version = RTM_VERSION;
|
||||
rtm.rtm_seq = ++seq;
|
||||
rtm.rtm_addrs = rtm_addrs;
|
||||
|
||||
so_dst.sa_family = AF_INET;
|
||||
so_mask.sa_family = AF_INET;
|
||||
|
||||
NEXTADDR(RTA_DST, so_dst);
|
||||
NEXTADDR(RTA_NETMASK, so_mask);
|
||||
|
||||
rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
|
||||
|
||||
s = socket(PF_ROUTE, SOCK_RAW, 0);
|
||||
|
||||
if (write(s, (char *)&m_rtmsg, l) < 0) {
|
||||
close(s);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
do {
|
||||
l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
|
||||
} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
|
||||
|
||||
close(s);
|
||||
|
||||
msg_hdr = &rtm;
|
||||
|
||||
cp = ((char *)(msg_hdr + 1));
|
||||
if (msg_hdr->rtm_addrs) {
|
||||
for (i = 1; i; i <<= 1)
|
||||
if (i & msg_hdr->rtm_addrs) {
|
||||
sa = (struct sockaddr *)cp;
|
||||
if (i == RTA_GATEWAY )
|
||||
gate = sa;
|
||||
|
||||
cp += sizeof(struct sockaddr);
|
||||
}
|
||||
} else {
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
|
||||
if (gate != NULL ) {
|
||||
*addr = ((struct sockaddr_in *)gate)->sin_addr.s_addr;
|
||||
return SUCCESS;
|
||||
} else {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
#endif /* #ifdef USE_SOCKET_ROUTE */
|
||||
|
||||
#ifdef USE_WIN32_CODE
|
||||
LIBSPEC int getdefaultgateway(in_addr_t * addr)
|
||||
{
|
||||
HKEY networkCardsKey;
|
||||
HKEY networkCardKey;
|
||||
HKEY interfacesKey;
|
||||
HKEY interfaceKey;
|
||||
DWORD i = 0;
|
||||
DWORD numSubKeys = 0;
|
||||
TCHAR keyName[MAX_KEY_LENGTH];
|
||||
DWORD keyNameLength = MAX_KEY_LENGTH;
|
||||
TCHAR keyValue[MAX_VALUE_LENGTH];
|
||||
DWORD keyValueLength = MAX_VALUE_LENGTH;
|
||||
DWORD keyValueType = REG_SZ;
|
||||
TCHAR gatewayValue[MAX_VALUE_LENGTH];
|
||||
DWORD gatewayValueLength = MAX_VALUE_LENGTH;
|
||||
DWORD gatewayValueType = REG_MULTI_SZ;
|
||||
int done = 0;
|
||||
|
||||
//const char * networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
|
||||
//const char * interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
|
||||
#ifdef UNICODE
|
||||
LPCTSTR networkCardsPath = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
|
||||
LPCTSTR interfacesPath = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
|
||||
#define STR_SERVICENAME L"ServiceName"
|
||||
#define STR_DHCPDEFAULTGATEWAY L"DhcpDefaultGateway"
|
||||
#define STR_DEFAULTGATEWAY L"DefaultGateway"
|
||||
#else
|
||||
LPCTSTR networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
|
||||
LPCTSTR interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
|
||||
#define STR_SERVICENAME "ServiceName"
|
||||
#define STR_DHCPDEFAULTGATEWAY "DhcpDefaultGateway"
|
||||
#define STR_DEFAULTGATEWAY "DefaultGateway"
|
||||
#endif
|
||||
// The windows registry lists its primary network devices in the following location:
|
||||
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards
|
||||
//
|
||||
// Each network device has its own subfolder, named with an index, with various properties:
|
||||
// -NetworkCards
|
||||
// -5
|
||||
// -Description = Broadcom 802.11n Network Adapter
|
||||
// -ServiceName = {E35A72F8-5065-4097-8DFE-C7790774EE4D}
|
||||
// -8
|
||||
// -Description = Marvell Yukon 88E8058 PCI-E Gigabit Ethernet Controller
|
||||
// -ServiceName = {86226414-5545-4335-A9D1-5BD7120119AD}
|
||||
//
|
||||
// The above service name is the name of a subfolder within:
|
||||
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces
|
||||
//
|
||||
// There may be more subfolders in this interfaces path than listed in the network cards path above:
|
||||
// -Interfaces
|
||||
// -{3a539854-6a70-11db-887c-806e6f6e6963}
|
||||
// -DhcpIPAddress = 0.0.0.0
|
||||
// -[more]
|
||||
// -{E35A72F8-5065-4097-8DFE-C7790774EE4D}
|
||||
// -DhcpIPAddress = 10.0.1.4
|
||||
// -DhcpDefaultGateway = 10.0.1.1
|
||||
// -[more]
|
||||
// -{86226414-5545-4335-A9D1-5BD7120119AD}
|
||||
// -DhcpIpAddress = 10.0.1.5
|
||||
// -DhcpDefaultGateay = 10.0.1.1
|
||||
// -[more]
|
||||
//
|
||||
// In order to extract this information, we enumerate each network card, and extract the ServiceName value.
|
||||
// This is then used to open the interface subfolder, and attempt to extract a DhcpDefaultGateway value.
|
||||
// Once one is found, we're done.
|
||||
//
|
||||
// It may be possible to simply enumerate the interface folders until we find one with a DhcpDefaultGateway value.
|
||||
// However, the technique used is the technique most cited on the web, and we assume it to be more correct.
|
||||
|
||||
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predifined key
|
||||
networkCardsPath, // Name of registry subkey to open
|
||||
0, // Reserved - must be zero
|
||||
KEY_READ, // Mask - desired access rights
|
||||
&networkCardsKey)) // Pointer to output key
|
||||
{
|
||||
// Unable to open network cards keys
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predefined key
|
||||
interfacesPath, // Name of registry subkey to open
|
||||
0, // Reserved - must be zero
|
||||
KEY_READ, // Mask - desired access rights
|
||||
&interfacesKey)) // Pointer to output key
|
||||
{
|
||||
// Unable to open interfaces key
|
||||
RegCloseKey(networkCardsKey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Figure out how many subfolders are within the NetworkCards folder
|
||||
RegQueryInfoKey(networkCardsKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
//printf( "Number of subkeys: %u\n", (unsigned int)numSubKeys);
|
||||
|
||||
// Enumrate through each subfolder within the NetworkCards folder
|
||||
for(i = 0; i < numSubKeys && !done; i++)
|
||||
{
|
||||
keyNameLength = MAX_KEY_LENGTH;
|
||||
if(ERROR_SUCCESS == RegEnumKeyEx(networkCardsKey, // Open registry key
|
||||
i, // Index of subkey to retrieve
|
||||
keyName, // Buffer that receives the name of the subkey
|
||||
&keyNameLength, // Variable that receives the size of the above buffer
|
||||
NULL, // Reserved - must be NULL
|
||||
NULL, // Buffer that receives the class string
|
||||
NULL, // Variable that receives the size of the above buffer
|
||||
NULL)) // Variable that receives the last write time of subkey
|
||||
{
|
||||
if(RegOpenKeyEx(networkCardsKey, keyName, 0, KEY_READ, &networkCardKey) == ERROR_SUCCESS)
|
||||
{
|
||||
keyValueLength = MAX_VALUE_LENGTH;
|
||||
if(ERROR_SUCCESS == RegQueryValueEx(networkCardKey, // Open registry key
|
||||
STR_SERVICENAME, // Name of key to query
|
||||
NULL, // Reserved - must be NULL
|
||||
&keyValueType, // Receives value type
|
||||
(LPBYTE)keyValue, // Receives value
|
||||
&keyValueLength)) // Receives value length in bytes
|
||||
{
|
||||
// printf("keyValue: %s\n", keyValue);
|
||||
if(RegOpenKeyEx(interfacesKey, keyValue, 0, KEY_READ, &interfaceKey) == ERROR_SUCCESS)
|
||||
{
|
||||
gatewayValueLength = MAX_VALUE_LENGTH;
|
||||
if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key
|
||||
STR_DHCPDEFAULTGATEWAY, // Name of key to query
|
||||
NULL, // Reserved - must be NULL
|
||||
&gatewayValueType, // Receives value type
|
||||
(LPBYTE)gatewayValue, // Receives value
|
||||
&gatewayValueLength)) // Receives value length in bytes
|
||||
{
|
||||
// Check to make sure it's a string
|
||||
if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1))
|
||||
{
|
||||
//printf("gatewayValue: %s\n", gatewayValue);
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
else if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key
|
||||
STR_DEFAULTGATEWAY, // Name of key to query
|
||||
NULL, // Reserved - must be NULL
|
||||
&gatewayValueType, // Receives value type
|
||||
(LPBYTE)gatewayValue,// Receives value
|
||||
&gatewayValueLength)) // Receives value length in bytes
|
||||
{
|
||||
// Check to make sure it's a string
|
||||
if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1))
|
||||
{
|
||||
//printf("gatewayValue: %s\n", gatewayValue);
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
RegCloseKey(interfaceKey);
|
||||
}
|
||||
}
|
||||
RegCloseKey(networkCardKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(interfacesKey);
|
||||
RegCloseKey(networkCardsKey);
|
||||
|
||||
if(done)
|
||||
{
|
||||
#if UNICODE
|
||||
char tmp[32];
|
||||
for(i = 0; i < 32; i++) {
|
||||
tmp[i] = (char)gatewayValue[i];
|
||||
if(!tmp[i])
|
||||
break;
|
||||
}
|
||||
tmp[31] = '\0';
|
||||
*addr = inet_addr(tmp);
|
||||
#else
|
||||
*addr = inet_addr(gatewayValue);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif /* #ifdef USE_WIN32_CODE */
|
||||
|
||||
#ifdef USE_WIN32_CODE_2
|
||||
int getdefaultgateway(in_addr_t *addr)
|
||||
{
|
||||
MIB_IPFORWARDROW ip_forward;
|
||||
memset(&ip_forward, 0, sizeof(ip_forward));
|
||||
if(GetBestRoute(inet_addr("0.0.0.0"), 0, &ip_forward) != NO_ERROR)
|
||||
return -1;
|
||||
*addr = ip_forward.dwForwardNextHop;
|
||||
return 0;
|
||||
}
|
||||
#endif /* #ifdef USE_WIN32_CODE_2 */
|
||||
|
||||
#ifdef USE_HAIKU_CODE
|
||||
int getdefaultgateway(in_addr_t *addr)
|
||||
{
|
||||
int fd, ret = -1;
|
||||
struct ifconf config;
|
||||
void *buffer = NULL;
|
||||
struct ifreq *interface;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(fd, SIOCGRTSIZE, &config, sizeof(config)) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
if (config.ifc_value < 1) {
|
||||
goto fail; /* No routes */
|
||||
}
|
||||
if ((buffer = malloc(config.ifc_value)) == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
config.ifc_len = config.ifc_value;
|
||||
config.ifc_buf = buffer;
|
||||
if (ioctl(fd, SIOCGRTTABLE, &config, sizeof(config)) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
for (interface = buffer;
|
||||
(uint8_t *)interface < (uint8_t *)buffer + config.ifc_len; ) {
|
||||
struct route_entry route = interface->ifr_route;
|
||||
int intfSize;
|
||||
if (route.flags & (RTF_GATEWAY | RTF_DEFAULT)) {
|
||||
*addr = ((struct sockaddr_in *)route.gateway)->sin_addr.s_addr;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
intfSize = sizeof(route) + IF_NAMESIZE;
|
||||
if (route.destination != NULL) {
|
||||
intfSize += route.destination->sa_len;
|
||||
}
|
||||
if (route.mask != NULL) {
|
||||
intfSize += route.mask->sa_len;
|
||||
}
|
||||
if (route.gateway != NULL) {
|
||||
intfSize += route.gateway->sa_len;
|
||||
}
|
||||
interface = (struct ifreq *)((uint8_t *)interface + intfSize);
|
||||
}
|
||||
fail:
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
#endif /* #ifdef USE_HAIKU_CODE */
|
||||
|
||||
#if !defined(USE_PROC_NET_ROUTE) && !defined(USE_SOCKET_ROUTE) && !defined(USE_SYSCTL_NET_ROUTE) && !defined(USE_WIN32_CODE) && !defined(USE_WIN32_CODE_2) && !defined(USE_HAIKU_CODE)
|
||||
int getdefaultgateway(in_addr_t * addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
49
ext-deps/libnatpmp-20150609/getgateway.h
Normal file
49
ext-deps/libnatpmp-20150609/getgateway.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* $Id: getgateway.h,v 1.8 2014/04/22 09:15:40 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-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.
|
||||
*/
|
||||
#ifndef __GETGATEWAY_H__
|
||||
#define __GETGATEWAY_H__
|
||||
|
||||
#ifdef WIN32
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1600
|
||||
#include <stdint.h>
|
||||
#else
|
||||
typedef unsigned long uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
#endif
|
||||
#define in_addr_t uint32_t
|
||||
#endif
|
||||
/* #include "declspec.h" */
|
||||
|
||||
/* getdefaultgateway() :
|
||||
* return value :
|
||||
* 0 : success
|
||||
* -1 : failure */
|
||||
/* LIBSPEC */int getdefaultgateway(in_addr_t * addr);
|
||||
|
||||
#endif
|
||||
281
ext-deps/libnatpmp-20150609/libnatpmpmodule.c
Normal file
281
ext-deps/libnatpmp-20150609/libnatpmpmodule.c
Normal file
@@ -0,0 +1,281 @@
|
||||
/* $Id: libnatpmpmodule.c,v 1.7 2012/03/05 19:38:37 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
* http://miniupnp.free.fr/libnatpmp.html
|
||||
Copyright (c) 2007-2011, 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 <Python.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#define STATICLIB
|
||||
#include "structmember.h"
|
||||
#include "natpmp.h"
|
||||
|
||||
/* for compatibility with Python < 2.4 */
|
||||
#ifndef Py_RETURN_NONE
|
||||
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
|
||||
#endif
|
||||
|
||||
#ifndef Py_RETURN_TRUE
|
||||
#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
|
||||
#endif
|
||||
|
||||
#ifndef Py_RETURN_FALSE
|
||||
#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
|
||||
/* Type-specific fields go here. */
|
||||
unsigned int discoverdelay;
|
||||
|
||||
natpmp_t natpmp;
|
||||
} NATPMPObject;
|
||||
|
||||
static PyMemberDef NATPMP_members[] = {
|
||||
{"discoverdelay", T_UINT, offsetof(NATPMPObject, discoverdelay),
|
||||
0/*READWRITE*/, "value in ms used to wait for NATPMP responses"
|
||||
},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
NATPMPObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
NATPMPObject *self;
|
||||
|
||||
self = (NATPMPObject *)type->tp_alloc(type, 0);
|
||||
if (self) {
|
||||
initnatpmp(&self->natpmp, 0, 0);
|
||||
}
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
static void
|
||||
NATPMPObject_dealloc(NATPMPObject *self)
|
||||
{
|
||||
closenatpmp(&self->natpmp);
|
||||
self->ob_type->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
NATPMP_externalipaddress(NATPMPObject *self)
|
||||
{
|
||||
int r;
|
||||
struct timeval timeout;
|
||||
fd_set fds;
|
||||
natpmpresp_t response;
|
||||
|
||||
r = sendpublicaddressrequest(&self->natpmp);
|
||||
|
||||
if (r < 0) {
|
||||
#ifdef ENABLE_STRNATPMPERR
|
||||
PyErr_SetString(PyExc_Exception, strnatpmperr(r));
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(self->natpmp.s, &fds);
|
||||
getnatpmprequesttimeout(&self->natpmp, &timeout);
|
||||
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
|
||||
r = readnatpmpresponseorretry(&self->natpmp, &response);
|
||||
if (r < 0 && r != NATPMP_TRYAGAIN) {
|
||||
#ifdef ENABLE_STRNATPMPERR
|
||||
PyErr_SetString(PyExc_Exception, strnatpmperr(r));
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
} while (r == NATPMP_TRYAGAIN);
|
||||
|
||||
return Py_BuildValue("s", inet_ntoa(response.pnu.publicaddress.addr));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
NATPMP_domapping(natpmp_t *n, unsigned short eport, unsigned short iport,
|
||||
const char *protocol, unsigned int lifetime)
|
||||
{
|
||||
int proto;
|
||||
struct timeval timeout;
|
||||
fd_set fds;
|
||||
natpmpresp_t response;
|
||||
int r;
|
||||
|
||||
if (!strncasecmp("tcp", protocol, 3)) {
|
||||
proto = NATPMP_PROTOCOL_TCP;
|
||||
} else if (!strncasecmp("udp", protocol, 3)) {
|
||||
proto = NATPMP_PROTOCOL_UDP;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_Exception, "Unknown protocol");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = sendnewportmappingrequest(n, proto, iport, eport,
|
||||
lifetime);
|
||||
|
||||
if (r < 0) {
|
||||
#ifdef ENABLE_STRNATPMPERR
|
||||
PyErr_SetString(PyExc_Exception, strnatpmperr(r));
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(n->s, &fds);
|
||||
getnatpmprequesttimeout(n, &timeout);
|
||||
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
|
||||
r = readnatpmpresponseorretry(n, &response);
|
||||
if (r < 0 && r != NATPMP_TRYAGAIN) {
|
||||
#ifdef ENABLE_STRNATPMPERR
|
||||
PyErr_SetString(PyExc_Exception, strnatpmperr(r));
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
} while (r == NATPMP_TRYAGAIN);
|
||||
|
||||
return Py_BuildValue("H", response.pnu.newportmapping.mappedpublicport);
|
||||
}
|
||||
|
||||
|
||||
/* AddPortMapping(externalPort, protocol, internalPort, lifetime)
|
||||
* protocol is 'UDP' or 'TCP' */
|
||||
static PyObject *
|
||||
NATPMP_addportmapping(NATPMPObject *self, PyObject *args)
|
||||
{
|
||||
unsigned short eport;
|
||||
unsigned short iport;
|
||||
unsigned int lifetime;
|
||||
const char *protocol;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "HsHI", &eport, &protocol, &iport, &lifetime))
|
||||
return NULL;
|
||||
|
||||
return NATPMP_domapping(&self->natpmp, eport, iport, protocol, lifetime);
|
||||
}
|
||||
|
||||
/* DeletePortMapping(externalPort, protocol, internalPort)
|
||||
* protocol is 'UDP' or 'TCP' */
|
||||
static PyObject *
|
||||
NATPMP_deleteportmapping(NATPMPObject *self, PyObject *args)
|
||||
{
|
||||
unsigned short eport;
|
||||
unsigned short iport;
|
||||
const char *protocol;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "HsH", &eport, &protocol, &iport))
|
||||
return NULL;
|
||||
|
||||
return NATPMP_domapping(&self->natpmp, eport, iport, protocol, 0);
|
||||
}
|
||||
|
||||
/* natpmp.NATPMP object Method Table */
|
||||
static PyMethodDef NATPMP_methods[] = {
|
||||
{"externalipaddress", (PyCFunction)NATPMP_externalipaddress, METH_NOARGS,
|
||||
"return external IP address"
|
||||
},
|
||||
{"addportmapping", (PyCFunction)NATPMP_addportmapping, METH_VARARGS,
|
||||
"add a port mapping"
|
||||
},
|
||||
{"deleteportmapping", (PyCFunction)NATPMP_deleteportmapping, METH_VARARGS,
|
||||
"delete a port mapping"
|
||||
},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyTypeObject NATPMPType = {
|
||||
PyObject_HEAD_INIT(NULL)
|
||||
0, /*ob_size*/
|
||||
"libnatpmp.NATPMP", /*tp_name*/
|
||||
sizeof(NATPMPObject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
(destructor)NATPMPObject_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash */
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||
"NATPMP objects", /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
NATPMP_methods, /* tp_methods */
|
||||
NATPMP_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
NATPMPObject_new, /* tp_new */
|
||||
};
|
||||
|
||||
/* module methods */
|
||||
static PyMethodDef libnatpmp_methods[] = {
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
|
||||
#define PyMODINIT_FUNC void
|
||||
#endif
|
||||
PyMODINIT_FUNC
|
||||
initlibnatpmp(void)
|
||||
{
|
||||
PyObject* m;
|
||||
|
||||
if (PyType_Ready(&NATPMPType) < 0)
|
||||
return;
|
||||
|
||||
m = Py_InitModule3("libnatpmp", libnatpmp_methods,
|
||||
"libnatpmp module.");
|
||||
|
||||
Py_INCREF(&NATPMPType);
|
||||
PyModule_AddObject(m, "NATPMP", (PyObject *)&NATPMPType);
|
||||
}
|
||||
|
||||
29
ext-deps/libnatpmp-20150609/msvc/libnatpmp.sln
Normal file
29
ext-deps/libnatpmp-20150609/msvc/libnatpmp.sln
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnatpmp", "libnatpmp.vcproj", "{D59B6527-F3DE-4D26-A08D-52F1EE989301}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "natpmpc-static", "natpmpc-static.vcproj", "{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{D59B6527-F3DE-4D26-A08D-52F1EE989301} = {D59B6527-F3DE-4D26-A08D-52F1EE989301}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D59B6527-F3DE-4D26-A08D-52F1EE989301}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{D59B6527-F3DE-4D26-A08D-52F1EE989301}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{D59B6527-F3DE-4D26-A08D-52F1EE989301}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{D59B6527-F3DE-4D26-A08D-52F1EE989301}.Release|Win32.Build.0 = Release|Win32
|
||||
{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
195
ext-deps/libnatpmp-20150609/msvc/libnatpmp.vcproj
Normal file
195
ext-deps/libnatpmp-20150609/msvc/libnatpmp.vcproj
Normal file
@@ -0,0 +1,195 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="libnatpmp"
|
||||
ProjectGUID="{D59B6527-F3DE-4D26-A08D-52F1EE989301}"
|
||||
RootNamespace="libnatpmp"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;STATICLIB"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;STATICLIB"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Fichiers sources"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\getgateway.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\natpmp.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\wingettimeofday.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Fichiers d'en-tête"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\declspec.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\getgateway.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\natpmp.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\wingettimeofday.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Fichiers de ressources"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
195
ext-deps/libnatpmp-20150609/msvc/natpmpc-static.vcproj
Normal file
195
ext-deps/libnatpmp-20150609/msvc/natpmpc-static.vcproj
Normal file
@@ -0,0 +1,195 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="natpmpc-static"
|
||||
ProjectGUID="{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}"
|
||||
RootNamespace="natpmpcstatic"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;STATICLIB;_CRT_SECURE_NO_WARNINGS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="ws2_32.lib Iphlpapi.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;STATICLIB;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="ws2_32.lib iphlpapi.lib"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Fichiers sources"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\natpmpc.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Fichiers d'en-tête"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Fichiers de ressources"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
157
ext-deps/libnatpmp-20150609/natpmp-jni.c
Normal file
157
ext-deps/libnatpmp-20150609/natpmp-jni.c
Normal file
@@ -0,0 +1,157 @@
|
||||
#ifdef __CYGWIN__
|
||||
#include <stdint.h>
|
||||
#define __int64 uint64_t
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "natpmp.h"
|
||||
|
||||
#include "fr_free_miniupnp_libnatpmp_NatPmp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
JNIEXPORT void JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_init (JNIEnv *env, jobject obj, jint forcegw, jint forcedgw) {
|
||||
natpmp_t *p = malloc (sizeof(natpmp_t));
|
||||
if (p == NULL) return;
|
||||
|
||||
initnatpmp(p, forcegw, (in_addr_t) forcedgw);
|
||||
|
||||
jobject wrapped = (*env)->NewDirectByteBuffer(env, p, sizeof(natpmp_t));
|
||||
if (wrapped == NULL) return;
|
||||
|
||||
jclass thisClass = (*env)->GetObjectClass(env,obj);
|
||||
if (thisClass == NULL) return;
|
||||
|
||||
jfieldID fid = (*env)->GetFieldID(env, thisClass, "natpmp", "Ljava/nio/ByteBuffer;");
|
||||
if (fid == NULL) return;
|
||||
(*env)->SetObjectField(env, obj, fid, wrapped);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_free (JNIEnv *env, jobject obj) {
|
||||
|
||||
jclass thisClass = (*env)->GetObjectClass(env,obj);
|
||||
if (thisClass == NULL) return;
|
||||
|
||||
jfieldID fid = (*env)->GetFieldID(env, thisClass, "natpmp", "Ljava/nio/ByteBuffer;");
|
||||
|
||||
if (fid == NULL) return;
|
||||
jobject wrapped = (*env)->GetObjectField(env, obj, fid);
|
||||
if (wrapped == NULL) return;
|
||||
|
||||
natpmp_t* natpmp = (natpmp_t*) (*env)->GetDirectBufferAddress(env, wrapped);
|
||||
|
||||
closenatpmp(natpmp);
|
||||
|
||||
if (natpmp == NULL) return;
|
||||
free(natpmp);
|
||||
|
||||
(*env)->SetObjectField(env, obj, fid, NULL);
|
||||
}
|
||||
|
||||
static natpmp_t* getNatPmp(JNIEnv* env, jobject obj) {
|
||||
jclass thisClass = (*env)->GetObjectClass(env,obj);
|
||||
if (thisClass == NULL) return NULL;
|
||||
|
||||
jfieldID fid = (*env)->GetFieldID(env, thisClass, "natpmp", "Ljava/nio/ByteBuffer;");
|
||||
|
||||
if (fid == NULL) return NULL;
|
||||
jobject wrapped = (*env)->GetObjectField(env, obj, fid);
|
||||
if (wrapped == NULL) return NULL;
|
||||
|
||||
natpmp_t* natpmp = (natpmp_t*) (*env)->GetDirectBufferAddress(env, wrapped);
|
||||
|
||||
return natpmp;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_sendPublicAddressRequest(JNIEnv* env, jobject obj) {
|
||||
natpmp_t* natpmp = getNatPmp(env, obj);
|
||||
if (natpmp == NULL) return -1;
|
||||
|
||||
return sendpublicaddressrequest(natpmp);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_startup(JNIEnv* env, jclass cls) {
|
||||
(void)env;
|
||||
(void)cls;
|
||||
#ifdef WIN32
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_sendNewPortMappingRequest(JNIEnv* env, jobject obj, jint protocol, jint privateport, jint publicport, jint lifetime) {
|
||||
natpmp_t* natpmp = getNatPmp(env, obj);
|
||||
if (natpmp == NULL) return -1;
|
||||
|
||||
return sendnewportmappingrequest(natpmp, protocol, privateport, publicport, lifetime);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_getNatPmpRequestTimeout(JNIEnv* env, jobject obj) {
|
||||
natpmp_t* natpmp = getNatPmp(env, obj);
|
||||
|
||||
struct timeval timeout;
|
||||
|
||||
getnatpmprequesttimeout(natpmp, &timeout);
|
||||
|
||||
return ((jlong) timeout.tv_sec) * 1000 + (timeout.tv_usec / 1000);
|
||||
|
||||
}
|
||||
|
||||
#define SET_FIELD(prefix, name, type, longtype) { \
|
||||
jfieldID fid = (*env)->GetFieldID(env, thisClass, #name, type); \
|
||||
if (fid == NULL) return -1; \
|
||||
(*env)->Set ## longtype ## Field(env, response, fid, resp. prefix name); \
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_readNatPmpResponseOrRetry(JNIEnv* env, jobject obj, jobject response) {
|
||||
|
||||
natpmp_t* natpmp = getNatPmp(env, obj);
|
||||
natpmpresp_t resp;
|
||||
int result = readnatpmpresponseorretry(natpmp, &resp);
|
||||
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
jclass thisClass = (*env)->GetObjectClass(env, response);
|
||||
if (thisClass == NULL) return -1;
|
||||
|
||||
SET_FIELD(,type, "S", Short);
|
||||
SET_FIELD(,resultcode, "S", Short);
|
||||
|
||||
jfieldID fid = (*env)->GetFieldID(env, thisClass, "epoch", "J");
|
||||
if (fid == NULL) return -1;
|
||||
(*env)->SetLongField(env, response, fid, ((jlong)resp.epoch) * 1000);
|
||||
|
||||
if (resp.type == 0) {
|
||||
jfieldID fid = (*env)->GetFieldID(env, thisClass, "addr", "I");
|
||||
if (fid == NULL) return -1;
|
||||
(*env)->SetIntField(env, response, fid, resp.pnu.publicaddress.addr.s_addr);
|
||||
|
||||
|
||||
} else {
|
||||
SET_FIELD(pnu.newportmapping., privateport, "I", Int);
|
||||
SET_FIELD(pnu.newportmapping., mappedpublicport, "I", Int);
|
||||
|
||||
jfieldID fid = (*env)->GetFieldID(env, thisClass, "lifetime", "J");
|
||||
if (fid == NULL) return -1;
|
||||
(*env)->SetLongField(env, response, fid, ((jlong) resp.pnu.newportmapping.lifetime) * 1000 * 1000);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
379
ext-deps/libnatpmp-20150609/natpmp.c
Normal file
379
ext-deps/libnatpmp-20150609/natpmp.c
Normal file
@@ -0,0 +1,379 @@
|
||||
/* $Id: natpmp.c,v 1.20 2015/05/27 12:43:15 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-2015, 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.
|
||||
*/
|
||||
#ifdef __linux__
|
||||
#define _BSD_SOURCE 1
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#if !defined(_MSC_VER)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
#include <errno.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#include "wingettimeofday.h"
|
||||
#define gettimeofday natpmp_gettimeofday
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#define closesocket close
|
||||
#endif
|
||||
#include "natpmp.h"
|
||||
#include "getgateway.h"
|
||||
#include <stdio.h>
|
||||
|
||||
LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw)
|
||||
{
|
||||
#ifdef WIN32
|
||||
u_long ioctlArg = 1;
|
||||
#else
|
||||
int flags;
|
||||
#endif
|
||||
struct sockaddr_in addr;
|
||||
if(!p)
|
||||
return NATPMP_ERR_INVALIDARGS;
|
||||
memset(p, 0, sizeof(natpmp_t));
|
||||
p->s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if(p->s < 0)
|
||||
return NATPMP_ERR_SOCKETERROR;
|
||||
#ifdef WIN32
|
||||
if(ioctlsocket(p->s, FIONBIO, &ioctlArg) == SOCKET_ERROR)
|
||||
return NATPMP_ERR_FCNTLERROR;
|
||||
#else
|
||||
if((flags = fcntl(p->s, F_GETFL, 0)) < 0)
|
||||
return NATPMP_ERR_FCNTLERROR;
|
||||
if(fcntl(p->s, F_SETFL, flags | O_NONBLOCK) < 0)
|
||||
return NATPMP_ERR_FCNTLERROR;
|
||||
#endif
|
||||
|
||||
if(forcegw) {
|
||||
p->gateway = forcedgw;
|
||||
} else {
|
||||
if(getdefaultgateway(&(p->gateway)) < 0)
|
||||
return NATPMP_ERR_CANNOTGETGATEWAY;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(NATPMP_PORT);
|
||||
addr.sin_addr.s_addr = p->gateway;
|
||||
if(connect(p->s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
||||
return NATPMP_ERR_CONNECTERR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBSPEC int closenatpmp(natpmp_t * p)
|
||||
{
|
||||
if(!p)
|
||||
return NATPMP_ERR_INVALIDARGS;
|
||||
if(closesocket(p->s) < 0)
|
||||
return NATPMP_ERR_CLOSEERR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sendpendingrequest(natpmp_t * p)
|
||||
{
|
||||
int r;
|
||||
/* struct sockaddr_in addr;*/
|
||||
if(!p)
|
||||
return NATPMP_ERR_INVALIDARGS;
|
||||
/* memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(NATPMP_PORT);
|
||||
addr.sin_addr.s_addr = p->gateway;
|
||||
r = (int)sendto(p->s, p->pending_request, p->pending_request_len, 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr));*/
|
||||
r = (int)send(p->s, (const char *)p->pending_request, p->pending_request_len, 0);
|
||||
return (r<0) ? NATPMP_ERR_SENDERR : r;
|
||||
}
|
||||
|
||||
int sendnatpmprequest(natpmp_t * p)
|
||||
{
|
||||
int n;
|
||||
if(!p)
|
||||
return NATPMP_ERR_INVALIDARGS;
|
||||
/* TODO : check if no request is already pending */
|
||||
p->has_pending_request = 1;
|
||||
p->try_number = 1;
|
||||
n = sendpendingrequest(p);
|
||||
gettimeofday(&p->retry_time, NULL); // check errors !
|
||||
p->retry_time.tv_usec += 250000; /* add 250ms */
|
||||
if(p->retry_time.tv_usec >= 1000000) {
|
||||
p->retry_time.tv_usec -= 1000000;
|
||||
p->retry_time.tv_sec++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout)
|
||||
{
|
||||
struct timeval now;
|
||||
if(!p || !timeout)
|
||||
return NATPMP_ERR_INVALIDARGS;
|
||||
if(!p->has_pending_request)
|
||||
return NATPMP_ERR_NOPENDINGREQ;
|
||||
if(gettimeofday(&now, NULL) < 0)
|
||||
return NATPMP_ERR_GETTIMEOFDAYERR;
|
||||
timeout->tv_sec = p->retry_time.tv_sec - now.tv_sec;
|
||||
timeout->tv_usec = p->retry_time.tv_usec - now.tv_usec;
|
||||
if(timeout->tv_usec < 0) {
|
||||
timeout->tv_usec += 1000000;
|
||||
timeout->tv_sec--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBSPEC int sendpublicaddressrequest(natpmp_t * p)
|
||||
{
|
||||
if(!p)
|
||||
return NATPMP_ERR_INVALIDARGS;
|
||||
//static const unsigned char request[] = { 0, 0 };
|
||||
p->pending_request[0] = 0;
|
||||
p->pending_request[1] = 0;
|
||||
p->pending_request_len = 2;
|
||||
// TODO: return 0 instead of sizeof(request) ??
|
||||
return sendnatpmprequest(p);
|
||||
}
|
||||
|
||||
LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol,
|
||||
uint16_t privateport, uint16_t publicport,
|
||||
uint32_t lifetime)
|
||||
{
|
||||
if(!p || (protocol!=NATPMP_PROTOCOL_TCP && protocol!=NATPMP_PROTOCOL_UDP))
|
||||
return NATPMP_ERR_INVALIDARGS;
|
||||
p->pending_request[0] = 0;
|
||||
p->pending_request[1] = protocol;
|
||||
p->pending_request[2] = 0;
|
||||
p->pending_request[3] = 0;
|
||||
/* break strict-aliasing rules :
|
||||
*((uint16_t *)(p->pending_request + 4)) = htons(privateport); */
|
||||
p->pending_request[4] = (privateport >> 8) & 0xff;
|
||||
p->pending_request[5] = privateport & 0xff;
|
||||
/* break stric-aliasing rules :
|
||||
*((uint16_t *)(p->pending_request + 6)) = htons(publicport); */
|
||||
p->pending_request[6] = (publicport >> 8) & 0xff;
|
||||
p->pending_request[7] = publicport & 0xff;
|
||||
/* break stric-aliasing rules :
|
||||
*((uint32_t *)(p->pending_request + 8)) = htonl(lifetime); */
|
||||
p->pending_request[8] = (lifetime >> 24) & 0xff;
|
||||
p->pending_request[9] = (lifetime >> 16) & 0xff;
|
||||
p->pending_request[10] = (lifetime >> 8) & 0xff;
|
||||
p->pending_request[11] = lifetime & 0xff;
|
||||
p->pending_request_len = 12;
|
||||
return sendnatpmprequest(p);
|
||||
}
|
||||
|
||||
LIBSPEC int readnatpmpresponse(natpmp_t * p, natpmpresp_t * response)
|
||||
{
|
||||
unsigned char buf[16];
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
int n;
|
||||
if(!p)
|
||||
return NATPMP_ERR_INVALIDARGS;
|
||||
n = recvfrom(p->s, (char *)buf, sizeof(buf), 0,
|
||||
(struct sockaddr *)&addr, &addrlen);
|
||||
if(n<0)
|
||||
#ifdef WIN32
|
||||
switch(WSAGetLastError()) {
|
||||
#else
|
||||
switch(errno) {
|
||||
#endif
|
||||
/*case EAGAIN:*/
|
||||
case EWOULDBLOCK:
|
||||
n = NATPMP_TRYAGAIN;
|
||||
break;
|
||||
case ECONNREFUSED:
|
||||
n = NATPMP_ERR_NOGATEWAYSUPPORT;
|
||||
break;
|
||||
default:
|
||||
n = NATPMP_ERR_RECVFROM;
|
||||
}
|
||||
/* check that addr is correct (= gateway) */
|
||||
else if(addr.sin_addr.s_addr != p->gateway)
|
||||
n = NATPMP_ERR_WRONGPACKETSOURCE;
|
||||
else {
|
||||
response->resultcode = ntohs(*((uint16_t *)(buf + 2)));
|
||||
response->epoch = ntohl(*((uint32_t *)(buf + 4)));
|
||||
if(buf[0] != 0)
|
||||
n = NATPMP_ERR_UNSUPPORTEDVERSION;
|
||||
else if(buf[1] < 128 || buf[1] > 130)
|
||||
n = NATPMP_ERR_UNSUPPORTEDOPCODE;
|
||||
else if(response->resultcode != 0) {
|
||||
switch(response->resultcode) {
|
||||
case 1:
|
||||
n = NATPMP_ERR_UNSUPPORTEDVERSION;
|
||||
break;
|
||||
case 2:
|
||||
n = NATPMP_ERR_NOTAUTHORIZED;
|
||||
break;
|
||||
case 3:
|
||||
n = NATPMP_ERR_NETWORKFAILURE;
|
||||
break;
|
||||
case 4:
|
||||
n = NATPMP_ERR_OUTOFRESOURCES;
|
||||
break;
|
||||
case 5:
|
||||
n = NATPMP_ERR_UNSUPPORTEDOPCODE;
|
||||
break;
|
||||
default:
|
||||
n = NATPMP_ERR_UNDEFINEDERROR;
|
||||
}
|
||||
} else {
|
||||
response->type = buf[1] & 0x7f;
|
||||
if(buf[1] == 128)
|
||||
//response->publicaddress.addr = *((uint32_t *)(buf + 8));
|
||||
response->pnu.publicaddress.addr.s_addr = *((uint32_t *)(buf + 8));
|
||||
else {
|
||||
response->pnu.newportmapping.privateport = ntohs(*((uint16_t *)(buf + 8)));
|
||||
response->pnu.newportmapping.mappedpublicport = ntohs(*((uint16_t *)(buf + 10)));
|
||||
response->pnu.newportmapping.lifetime = ntohl(*((uint32_t *)(buf + 12)));
|
||||
}
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response)
|
||||
{
|
||||
int n;
|
||||
if(!p || !response)
|
||||
return NATPMP_ERR_INVALIDARGS;
|
||||
if(!p->has_pending_request)
|
||||
return NATPMP_ERR_NOPENDINGREQ;
|
||||
n = readnatpmpresponse(p, response);
|
||||
if(n<0) {
|
||||
if(n==NATPMP_TRYAGAIN) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL); // check errors !
|
||||
if(timercmp(&now, &p->retry_time, >=)) {
|
||||
int delay, r;
|
||||
if(p->try_number >= 9) {
|
||||
return NATPMP_ERR_NOGATEWAYSUPPORT;
|
||||
}
|
||||
/*printf("retry! %d\n", p->try_number);*/
|
||||
delay = 250 * (1<<p->try_number); // ms
|
||||
/*for(i=0; i<p->try_number; i++)
|
||||
delay += delay;*/
|
||||
p->retry_time.tv_sec += (delay / 1000);
|
||||
p->retry_time.tv_usec += (delay % 1000) * 1000;
|
||||
if(p->retry_time.tv_usec >= 1000000) {
|
||||
p->retry_time.tv_usec -= 1000000;
|
||||
p->retry_time.tv_sec++;
|
||||
}
|
||||
p->try_number++;
|
||||
r = sendpendingrequest(p);
|
||||
if(r<0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p->has_pending_request = 0;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_STRNATPMPERR
|
||||
LIBSPEC const char * strnatpmperr(int r)
|
||||
{
|
||||
const char * s;
|
||||
switch(r) {
|
||||
case NATPMP_ERR_INVALIDARGS:
|
||||
s = "invalid arguments";
|
||||
break;
|
||||
case NATPMP_ERR_SOCKETERROR:
|
||||
s = "socket() failed";
|
||||
break;
|
||||
case NATPMP_ERR_CANNOTGETGATEWAY:
|
||||
s = "cannot get default gateway ip address";
|
||||
break;
|
||||
case NATPMP_ERR_CLOSEERR:
|
||||
#ifdef WIN32
|
||||
s = "closesocket() failed";
|
||||
#else
|
||||
s = "close() failed";
|
||||
#endif
|
||||
break;
|
||||
case NATPMP_ERR_RECVFROM:
|
||||
s = "recvfrom() failed";
|
||||
break;
|
||||
case NATPMP_ERR_NOPENDINGREQ:
|
||||
s = "no pending request";
|
||||
break;
|
||||
case NATPMP_ERR_NOGATEWAYSUPPORT:
|
||||
s = "the gateway does not support nat-pmp";
|
||||
break;
|
||||
case NATPMP_ERR_CONNECTERR:
|
||||
s = "connect() failed";
|
||||
break;
|
||||
case NATPMP_ERR_WRONGPACKETSOURCE:
|
||||
s = "packet not received from the default gateway";
|
||||
break;
|
||||
case NATPMP_ERR_SENDERR:
|
||||
s = "send() failed";
|
||||
break;
|
||||
case NATPMP_ERR_FCNTLERROR:
|
||||
s = "fcntl() failed";
|
||||
break;
|
||||
case NATPMP_ERR_GETTIMEOFDAYERR:
|
||||
s = "gettimeofday() failed";
|
||||
break;
|
||||
case NATPMP_ERR_UNSUPPORTEDVERSION:
|
||||
s = "unsupported nat-pmp version error from server";
|
||||
break;
|
||||
case NATPMP_ERR_UNSUPPORTEDOPCODE:
|
||||
s = "unsupported nat-pmp opcode error from server";
|
||||
break;
|
||||
case NATPMP_ERR_UNDEFINEDERROR:
|
||||
s = "undefined nat-pmp server error";
|
||||
break;
|
||||
case NATPMP_ERR_NOTAUTHORIZED:
|
||||
s = "not authorized";
|
||||
break;
|
||||
case NATPMP_ERR_NETWORKFAILURE:
|
||||
s = "network failure";
|
||||
break;
|
||||
case NATPMP_ERR_OUTOFRESOURCES:
|
||||
s = "nat-pmp server out of resources";
|
||||
break;
|
||||
default:
|
||||
s = "Unknown libnatpmp error";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
11
ext-deps/libnatpmp-20150609/natpmp.def
Normal file
11
ext-deps/libnatpmp-20150609/natpmp.def
Normal file
@@ -0,0 +1,11 @@
|
||||
LIBRARY
|
||||
; libnatpmp library
|
||||
|
||||
EXPORTS
|
||||
initnatpmp
|
||||
closenatpmp
|
||||
sendpublicaddressrequest
|
||||
sendnewportmappingrequest
|
||||
getnatpmprequesttimeout
|
||||
readnatpmpresponseorretry
|
||||
strnatpmperr
|
||||
219
ext-deps/libnatpmp-20150609/natpmp.h
Normal file
219
ext-deps/libnatpmp-20150609/natpmp.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/* $Id: natpmp.h,v 1.20 2014/04/22 09:15:40 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-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.
|
||||
*/
|
||||
#ifndef __NATPMP_H__
|
||||
#define __NATPMP_H__
|
||||
|
||||
/* NAT-PMP Port as defined by the NAT-PMP draft */
|
||||
#define NATPMP_PORT (5351)
|
||||
|
||||
#include <time.h>
|
||||
#if !defined(_MSC_VER)
|
||||
#include <sys/time.h>
|
||||
#endif /* !defined(_MSC_VER) */
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1600
|
||||
#include <stdint.h>
|
||||
#else /* !defined(_MSC_VER) || _MSC_VER >= 1600 */
|
||||
typedef unsigned long uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
#endif /* !defined(_MSC_VER) || _MSC_VER >= 1600 */
|
||||
#define in_addr_t uint32_t
|
||||
#include "declspec.h"
|
||||
#else /* WIN32 */
|
||||
#define LIBSPEC
|
||||
#include <netinet/in.h>
|
||||
#endif /* WIN32 */
|
||||
|
||||
/* causes problem when installing. Maybe should it be inlined ? */
|
||||
/* #include "declspec.h" */
|
||||
|
||||
typedef struct {
|
||||
int s; /* socket */
|
||||
in_addr_t gateway; /* default gateway (IPv4) */
|
||||
int has_pending_request;
|
||||
unsigned char pending_request[12];
|
||||
int pending_request_len;
|
||||
int try_number;
|
||||
struct timeval retry_time;
|
||||
} natpmp_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t type; /* NATPMP_RESPTYPE_* */
|
||||
uint16_t resultcode; /* NAT-PMP response code */
|
||||
uint32_t epoch; /* Seconds since start of epoch */
|
||||
union {
|
||||
struct {
|
||||
//in_addr_t addr;
|
||||
struct in_addr addr;
|
||||
} publicaddress;
|
||||
struct {
|
||||
uint16_t privateport;
|
||||
uint16_t mappedpublicport;
|
||||
uint32_t lifetime;
|
||||
} newportmapping;
|
||||
} pnu;
|
||||
} natpmpresp_t;
|
||||
|
||||
/* possible values for type field of natpmpresp_t */
|
||||
#define NATPMP_RESPTYPE_PUBLICADDRESS (0)
|
||||
#define NATPMP_RESPTYPE_UDPPORTMAPPING (1)
|
||||
#define NATPMP_RESPTYPE_TCPPORTMAPPING (2)
|
||||
|
||||
/* Values to pass to sendnewportmappingrequest() */
|
||||
#define NATPMP_PROTOCOL_UDP (1)
|
||||
#define NATPMP_PROTOCOL_TCP (2)
|
||||
|
||||
/* return values */
|
||||
/* NATPMP_ERR_INVALIDARGS : invalid arguments passed to the function */
|
||||
#define NATPMP_ERR_INVALIDARGS (-1)
|
||||
/* NATPMP_ERR_SOCKETERROR : socket() failed. check errno for details */
|
||||
#define NATPMP_ERR_SOCKETERROR (-2)
|
||||
/* NATPMP_ERR_CANNOTGETGATEWAY : can't get default gateway IP */
|
||||
#define NATPMP_ERR_CANNOTGETGATEWAY (-3)
|
||||
/* NATPMP_ERR_CLOSEERR : close() failed. check errno for details */
|
||||
#define NATPMP_ERR_CLOSEERR (-4)
|
||||
/* NATPMP_ERR_RECVFROM : recvfrom() failed. check errno for details */
|
||||
#define NATPMP_ERR_RECVFROM (-5)
|
||||
/* NATPMP_ERR_NOPENDINGREQ : readnatpmpresponseorretry() called while
|
||||
* no NAT-PMP request was pending */
|
||||
#define NATPMP_ERR_NOPENDINGREQ (-6)
|
||||
/* NATPMP_ERR_NOGATEWAYSUPPORT : the gateway does not support NAT-PMP */
|
||||
#define NATPMP_ERR_NOGATEWAYSUPPORT (-7)
|
||||
/* NATPMP_ERR_CONNECTERR : connect() failed. check errno for details */
|
||||
#define NATPMP_ERR_CONNECTERR (-8)
|
||||
/* NATPMP_ERR_WRONGPACKETSOURCE : packet not received from the network gateway */
|
||||
#define NATPMP_ERR_WRONGPACKETSOURCE (-9)
|
||||
/* NATPMP_ERR_SENDERR : send() failed. check errno for details */
|
||||
#define NATPMP_ERR_SENDERR (-10)
|
||||
/* NATPMP_ERR_FCNTLERROR : fcntl() failed. check errno for details */
|
||||
#define NATPMP_ERR_FCNTLERROR (-11)
|
||||
/* NATPMP_ERR_GETTIMEOFDAYERR : gettimeofday() failed. check errno for details */
|
||||
#define NATPMP_ERR_GETTIMEOFDAYERR (-12)
|
||||
|
||||
/* */
|
||||
#define NATPMP_ERR_UNSUPPORTEDVERSION (-14)
|
||||
#define NATPMP_ERR_UNSUPPORTEDOPCODE (-15)
|
||||
|
||||
/* Errors from the server : */
|
||||
#define NATPMP_ERR_UNDEFINEDERROR (-49)
|
||||
#define NATPMP_ERR_NOTAUTHORIZED (-51)
|
||||
#define NATPMP_ERR_NETWORKFAILURE (-52)
|
||||
#define NATPMP_ERR_OUTOFRESOURCES (-53)
|
||||
|
||||
/* NATPMP_TRYAGAIN : no data available for the moment. try again later */
|
||||
#define NATPMP_TRYAGAIN (-100)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* initnatpmp()
|
||||
* initialize a natpmp_t object
|
||||
* With forcegw=1 the gateway is not detected automaticaly.
|
||||
* Return values :
|
||||
* 0 = OK
|
||||
* NATPMP_ERR_INVALIDARGS
|
||||
* NATPMP_ERR_SOCKETERROR
|
||||
* NATPMP_ERR_FCNTLERROR
|
||||
* NATPMP_ERR_CANNOTGETGATEWAY
|
||||
* NATPMP_ERR_CONNECTERR */
|
||||
LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw);
|
||||
|
||||
/* closenatpmp()
|
||||
* close resources associated with a natpmp_t object
|
||||
* Return values :
|
||||
* 0 = OK
|
||||
* NATPMP_ERR_INVALIDARGS
|
||||
* NATPMP_ERR_CLOSEERR */
|
||||
LIBSPEC int closenatpmp(natpmp_t * p);
|
||||
|
||||
/* sendpublicaddressrequest()
|
||||
* send a public address NAT-PMP request to the network gateway
|
||||
* Return values :
|
||||
* 2 = OK (size of the request)
|
||||
* NATPMP_ERR_INVALIDARGS
|
||||
* NATPMP_ERR_SENDERR */
|
||||
LIBSPEC int sendpublicaddressrequest(natpmp_t * p);
|
||||
|
||||
/* sendnewportmappingrequest()
|
||||
* send a new port mapping NAT-PMP request to the network gateway
|
||||
* Arguments :
|
||||
* protocol is either NATPMP_PROTOCOL_TCP or NATPMP_PROTOCOL_UDP,
|
||||
* lifetime is in seconds.
|
||||
* To remove a port mapping, set lifetime to zero.
|
||||
* To remove all port mappings to the host, set lifetime and both ports
|
||||
* to zero.
|
||||
* Return values :
|
||||
* 12 = OK (size of the request)
|
||||
* NATPMP_ERR_INVALIDARGS
|
||||
* NATPMP_ERR_SENDERR */
|
||||
LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol,
|
||||
uint16_t privateport, uint16_t publicport,
|
||||
uint32_t lifetime);
|
||||
|
||||
/* getnatpmprequesttimeout()
|
||||
* fills the timeval structure with the timeout duration of the
|
||||
* currently pending NAT-PMP request.
|
||||
* Return values :
|
||||
* 0 = OK
|
||||
* NATPMP_ERR_INVALIDARGS
|
||||
* NATPMP_ERR_GETTIMEOFDAYERR
|
||||
* NATPMP_ERR_NOPENDINGREQ */
|
||||
LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout);
|
||||
|
||||
/* readnatpmpresponseorretry()
|
||||
* fills the natpmpresp_t structure if possible
|
||||
* Return values :
|
||||
* 0 = OK
|
||||
* NATPMP_TRYAGAIN
|
||||
* NATPMP_ERR_INVALIDARGS
|
||||
* NATPMP_ERR_NOPENDINGREQ
|
||||
* NATPMP_ERR_NOGATEWAYSUPPORT
|
||||
* NATPMP_ERR_RECVFROM
|
||||
* NATPMP_ERR_WRONGPACKETSOURCE
|
||||
* NATPMP_ERR_UNSUPPORTEDVERSION
|
||||
* NATPMP_ERR_UNSUPPORTEDOPCODE
|
||||
* NATPMP_ERR_NOTAUTHORIZED
|
||||
* NATPMP_ERR_NETWORKFAILURE
|
||||
* NATPMP_ERR_OUTOFRESOURCES
|
||||
* NATPMP_ERR_UNSUPPORTEDOPCODE
|
||||
* NATPMP_ERR_UNDEFINEDERROR */
|
||||
LIBSPEC int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response);
|
||||
|
||||
#ifdef ENABLE_STRNATPMPERR
|
||||
LIBSPEC const char * strnatpmperr(int t);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
19
ext-deps/libnatpmp-20150609/natpmpc.1
Normal file
19
ext-deps/libnatpmp-20150609/natpmpc.1
Normal file
@@ -0,0 +1,19 @@
|
||||
.TH natpmpc 1
|
||||
|
||||
.SH NAME
|
||||
natpmpc \- NAT\-PMP library test client and mapping setter.
|
||||
|
||||
.SH "SYNOPSIS"
|
||||
Display the public IP address:
|
||||
.br
|
||||
\fBnatpmpc\fP
|
||||
|
||||
Add a port mapping:
|
||||
.br
|
||||
\fBnatpmpc\fP \-a <public port> <private port> <protocol> [lifetime]
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
In order to remove a mapping, set it with a lifetime of 0 seconds.
|
||||
To remove all mappings for your machine, use 0 as private port and
|
||||
lifetime.
|
||||
244
ext-deps/libnatpmp-20150609/natpmpc.c
Normal file
244
ext-deps/libnatpmp-20150609/natpmpc.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/* $Id: natpmpc.c,v 1.13 2012/08/21 17:23:38 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-2011, 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 <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#if defined(_MSC_VER)
|
||||
#if _MSC_VER >= 1400
|
||||
#define strcasecmp _stricmp
|
||||
#else
|
||||
#define strcasecmp stricmp
|
||||
#endif
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include "natpmp.h"
|
||||
|
||||
void usage(FILE * out, const char * argv0)
|
||||
{
|
||||
fprintf(out, "Usage :\n");
|
||||
fprintf(out, " %s [options]\n", argv0);
|
||||
fprintf(out, "\tdisplay the public IP address.\n");
|
||||
fprintf(out, " %s -h\n", argv0);
|
||||
fprintf(out, "\tdisplay this help screen.\n");
|
||||
fprintf(out, " %s [options] -a <public port> <private port> <protocol> [lifetime]\n", argv0);
|
||||
fprintf(out, "\tadd a port mapping.\n");
|
||||
fprintf(out, "\nOption available :\n");
|
||||
fprintf(out, " -g ipv4address\n");
|
||||
fprintf(out, "\tforce the gateway to be used as destination for NAT-PMP commands.\n");
|
||||
fprintf(out, "\n In order to remove a mapping, set it with a lifetime of 0 seconds.\n");
|
||||
fprintf(out, " To remove all mappings for your machine, use 0 as private port and lifetime.\n");
|
||||
}
|
||||
|
||||
/* sample code for using libnatpmp */
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
natpmp_t natpmp;
|
||||
natpmpresp_t response;
|
||||
int r;
|
||||
int sav_errno;
|
||||
struct timeval timeout;
|
||||
fd_set fds;
|
||||
int i;
|
||||
int protocol = 0;
|
||||
uint16_t privateport = 0;
|
||||
uint16_t publicport = 0;
|
||||
uint32_t lifetime = 3600;
|
||||
int command = 0;
|
||||
int forcegw = 0;
|
||||
in_addr_t gateway = 0;
|
||||
struct in_addr gateway_in_use;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsaData;
|
||||
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
if(nResult != NO_ERROR)
|
||||
{
|
||||
fprintf(stderr, "WSAStartup() failed.\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* argument parsing */
|
||||
for(i=1; i<argc; i++) {
|
||||
if(argv[i][0] == '-') {
|
||||
switch(argv[i][1]) {
|
||||
case 'h':
|
||||
usage(stdout, argv[0]);
|
||||
return 0;
|
||||
case 'g':
|
||||
forcegw = 1;
|
||||
if(argc < i + 1) {
|
||||
fprintf(stderr, "Not enough arguments for option -%c\n", argv[i][1]);
|
||||
return 1;
|
||||
}
|
||||
gateway = inet_addr(argv[++i]);
|
||||
break;
|
||||
case 'a':
|
||||
command = 'a';
|
||||
if(argc < i + 4) {
|
||||
fprintf(stderr, "Not enough arguments for option -%c\n", argv[i][1]);
|
||||
return 1;
|
||||
}
|
||||
i++;
|
||||
if(1 != sscanf(argv[i], "%hu", &publicport)) {
|
||||
fprintf(stderr, "%s is not a correct 16bits unsigned integer\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
i++;
|
||||
if(1 != sscanf(argv[i], "%hu", &privateport)) {
|
||||
fprintf(stderr, "%s is not a correct 16bits unsigned integer\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
i++;
|
||||
if(0 == strcasecmp(argv[i], "tcp"))
|
||||
protocol = NATPMP_PROTOCOL_TCP;
|
||||
else if(0 == strcasecmp(argv[i], "udp"))
|
||||
protocol = NATPMP_PROTOCOL_UDP;
|
||||
else {
|
||||
fprintf(stderr, "%s is not a valid protocol\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
if(argc > i + 1) {
|
||||
if(1 != sscanf(argv[i+1], "%u", &lifetime)) {
|
||||
fprintf(stderr, "%s is not a correct 32bits unsigned integer\n", argv[i]);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown option %s\n", argv[i]);
|
||||
usage(stderr, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unknown option %s\n", argv[i]);
|
||||
usage(stderr, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* initnatpmp() */
|
||||
r = initnatpmp(&natpmp, forcegw, gateway);
|
||||
printf("initnatpmp() returned %d (%s)\n", r, r?"FAILED":"SUCCESS");
|
||||
if(r<0)
|
||||
return 1;
|
||||
|
||||
gateway_in_use.s_addr = natpmp.gateway;
|
||||
printf("using gateway : %s\n", inet_ntoa(gateway_in_use));
|
||||
|
||||
/* sendpublicaddressrequest() */
|
||||
r = sendpublicaddressrequest(&natpmp);
|
||||
printf("sendpublicaddressrequest returned %d (%s)\n",
|
||||
r, r==2?"SUCCESS":"FAILED");
|
||||
if(r<0)
|
||||
return 1;
|
||||
|
||||
do {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(natpmp.s, &fds);
|
||||
getnatpmprequesttimeout(&natpmp, &timeout);
|
||||
r = select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
|
||||
if(r<0) {
|
||||
fprintf(stderr, "select()");
|
||||
return 1;
|
||||
}
|
||||
r = readnatpmpresponseorretry(&natpmp, &response);
|
||||
sav_errno = errno;
|
||||
printf("readnatpmpresponseorretry returned %d (%s)\n",
|
||||
r, r==0?"OK":(r==NATPMP_TRYAGAIN?"TRY AGAIN":"FAILED"));
|
||||
if(r<0 && r!=NATPMP_TRYAGAIN) {
|
||||
#ifdef ENABLE_STRNATPMPERR
|
||||
fprintf(stderr, "readnatpmpresponseorretry() failed : %s\n",
|
||||
strnatpmperr(r));
|
||||
#endif
|
||||
fprintf(stderr, " errno=%d '%s'\n",
|
||||
sav_errno, strerror(sav_errno));
|
||||
}
|
||||
} while(r==NATPMP_TRYAGAIN);
|
||||
if(r<0)
|
||||
return 1;
|
||||
|
||||
/* TODO : check that response.type == 0 */
|
||||
printf("Public IP address : %s\n", inet_ntoa(response.pnu.publicaddress.addr));
|
||||
printf("epoch = %u\n", response.epoch);
|
||||
|
||||
if(command == 'a') {
|
||||
/* sendnewportmappingrequest() */
|
||||
r = sendnewportmappingrequest(&natpmp, protocol,
|
||||
privateport, publicport,
|
||||
lifetime);
|
||||
printf("sendnewportmappingrequest returned %d (%s)\n",
|
||||
r, r==12?"SUCCESS":"FAILED");
|
||||
if(r < 0)
|
||||
return 1;
|
||||
|
||||
do {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(natpmp.s, &fds);
|
||||
getnatpmprequesttimeout(&natpmp, &timeout);
|
||||
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
|
||||
r = readnatpmpresponseorretry(&natpmp, &response);
|
||||
printf("readnatpmpresponseorretry returned %d (%s)\n",
|
||||
r, r==0?"OK":(r==NATPMP_TRYAGAIN?"TRY AGAIN":"FAILED"));
|
||||
} while(r==NATPMP_TRYAGAIN);
|
||||
if(r<0) {
|
||||
#ifdef ENABLE_STRNATPMPERR
|
||||
fprintf(stderr, "readnatpmpresponseorretry() failed : %s\n",
|
||||
strnatpmperr(r));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Mapped public port %hu protocol %s to local port %hu "
|
||||
"liftime %u\n",
|
||||
response.pnu.newportmapping.mappedpublicport,
|
||||
response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" :
|
||||
(response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" :
|
||||
"UNKNOWN"),
|
||||
response.pnu.newportmapping.privateport,
|
||||
response.pnu.newportmapping.lifetime);
|
||||
printf("epoch = %u\n", response.epoch);
|
||||
}
|
||||
|
||||
r = closenatpmp(&natpmp);
|
||||
printf("closenatpmp() returned %d (%s)\n", r, r==0?"SUCCESS":"FAILED");
|
||||
if(r<0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
18
ext-deps/libnatpmp-20150609/setup.py
Normal file
18
ext-deps/libnatpmp-20150609/setup.py
Normal file
@@ -0,0 +1,18 @@
|
||||
#! /usr/bin/python
|
||||
# $Id: setup.py,v 1.3 2012/03/05 04:54:01 nanard Exp $
|
||||
#
|
||||
# python script to build the libnatpmp module under unix
|
||||
#
|
||||
# replace libnatpmp.a by libnatpmp.so for shared library usage
|
||||
from distutils.core import setup, Extension
|
||||
from distutils import sysconfig
|
||||
sysconfig.get_config_vars()["OPT"] = ''
|
||||
sysconfig.get_config_vars()["CFLAGS"] = ''
|
||||
setup(name="libnatpmp", version="1.0",
|
||||
ext_modules=[
|
||||
Extension(name="libnatpmp", sources=["libnatpmpmodule.c"],
|
||||
extra_objects=["libnatpmp.a"],
|
||||
define_macros=[('ENABLE_STRNATPMPERR', None)]
|
||||
)]
|
||||
)
|
||||
|
||||
17
ext-deps/libnatpmp-20150609/setupmingw32.py
Normal file
17
ext-deps/libnatpmp-20150609/setupmingw32.py
Normal file
@@ -0,0 +1,17 @@
|
||||
#! /usr/bin/python
|
||||
# $Id: setupmingw32.py,v 1.3 2012/03/05 04:54:01 nanard Exp $
|
||||
# python script to build the miniupnpc module under windows
|
||||
#
|
||||
from distutils.core import setup, Extension
|
||||
from distutils import sysconfig
|
||||
sysconfig.get_config_vars()["OPT"] = ''
|
||||
sysconfig.get_config_vars()["CFLAGS"] = ''
|
||||
setup(name="libnatpmp", version="1.0",
|
||||
ext_modules=[
|
||||
Extension(name="libnatpmp", sources=["libnatpmpmodule.c"],
|
||||
libraries=["ws2_32"],
|
||||
extra_objects=["libnatpmp.a"],
|
||||
define_macros=[('ENABLE_STRNATPMPERR', None)]
|
||||
)]
|
||||
)
|
||||
|
||||
57
ext-deps/libnatpmp-20150609/testgetgateway.c
Normal file
57
ext-deps/libnatpmp-20150609/testgetgateway.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/* $Id: testgetgateway.c,v 1.7 2012/08/21 17:13:31 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-2011, 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 <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include "getgateway.h"
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
struct in_addr gatewayaddr;
|
||||
int r;
|
||||
#ifdef WIN32
|
||||
uint32_t temp = 0;
|
||||
r = getdefaultgateway(&temp);
|
||||
gatewayaddr.S_un.S_addr = temp;
|
||||
#else
|
||||
r = getdefaultgateway(&(gatewayaddr.s_addr));
|
||||
#endif
|
||||
if(r>=0)
|
||||
printf("default gateway : %s\n", inet_ntoa(gatewayaddr));
|
||||
else
|
||||
fprintf(stderr, "getdefaultgateway() failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
60
ext-deps/libnatpmp-20150609/wingettimeofday.c
Normal file
60
ext-deps/libnatpmp-20150609/wingettimeofday.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/* $Id: wingettimeofday.c,v 1.6 2013/09/10 20:13:26 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-2013, 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.
|
||||
*/
|
||||
#ifdef WIN32
|
||||
#if defined(_MSC_VER)
|
||||
struct timeval {
|
||||
long tv_sec;
|
||||
long tv_usec;
|
||||
};
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
typedef struct _FILETIME {
|
||||
unsigned long dwLowDateTime;
|
||||
unsigned long dwHighDateTime;
|
||||
} FILETIME;
|
||||
|
||||
void __stdcall GetSystemTimeAsFileTime(FILETIME*);
|
||||
|
||||
int natpmp_gettimeofday(struct timeval* p, void* tz /* IGNORED */) {
|
||||
union {
|
||||
long long ns100; /*time since 1 Jan 1601 in 100ns units */
|
||||
FILETIME ft;
|
||||
} _now;
|
||||
|
||||
if(!p)
|
||||
return -1;
|
||||
GetSystemTimeAsFileTime( &(_now.ft) );
|
||||
p->tv_usec =(long)((_now.ns100 / 10LL) % 1000000LL );
|
||||
p->tv_sec = (long)((_now.ns100-(116444736000000000LL))/10000000LL);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
39
ext-deps/libnatpmp-20150609/wingettimeofday.h
Normal file
39
ext-deps/libnatpmp-20150609/wingettimeofday.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* $Id: wingettimeofday.h,v 1.5 2013/09/11 07:22:25 nanard Exp $ */
|
||||
/* libnatpmp
|
||||
Copyright (c) 2007-2013, 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.
|
||||
*/
|
||||
#ifndef __WINGETTIMEOFDAY_H__
|
||||
#define __WINGETTIMEOFDAY_H__
|
||||
#ifdef WIN32
|
||||
#if defined(_MSC_VER)
|
||||
#include <time.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
int natpmp_gettimeofday(struct timeval* p, void* tz /* IGNORED */);
|
||||
#endif
|
||||
#endif
|
||||
2
gpujpeg
2
gpujpeg
Submodule gpujpeg updated: d277a02f51...3d3731f30c
@@ -28,14 +28,14 @@ const char * const sdiAudioCards[] = {
|
||||
"decklink",
|
||||
"aja",
|
||||
"dvs",
|
||||
"deltacast"
|
||||
"deltacast",
|
||||
"ndi",
|
||||
};
|
||||
|
||||
const char * const sdiAudio[] = {
|
||||
"analog",
|
||||
"AESEBU",
|
||||
"embedded",
|
||||
"decklink"
|
||||
};
|
||||
|
||||
static std::vector<std::vector<ConditionItem>> getSdiCond(const std::string &opt){
|
||||
|
||||
@@ -40,7 +40,8 @@ static bool conditionsSatisfied(
|
||||
for(const auto &condClause : conds){
|
||||
bool orRes = false;
|
||||
for(const auto &condItem : condClause){
|
||||
bool val = condItem.value.val == settings->getOption(condItem.value.opt).getValue();
|
||||
//Check if condItem.value.val is the prefix of the currently set value
|
||||
bool val = settings->getOption(condItem.value.opt).getValue().rfind(condItem.value.val, 0) == 0;
|
||||
|
||||
//negate result if negation is true
|
||||
val = val != condItem.negation;
|
||||
|
||||
@@ -214,6 +214,15 @@ const static struct{
|
||||
{"preview", Option::BoolOpt, "", "t", true, "", ""},
|
||||
{"vuMeter", Option::BoolOpt, "", "t", true, "", ""},
|
||||
{"errors_fatal", Option::BoolOpt, " --param errors-fatal", "t", true, "", ""},
|
||||
{"aja.device", Option::StringOpt, ":", "", false, "video.source", "aja"},
|
||||
{"bluefish444.device", Option::StringOpt, ":", "", false, "video.source", "bluefish444"},
|
||||
{"deltacast.device", Option::StringOpt, ":", "", false, "video.source", "deltacast"},
|
||||
{"deltacast-dv.device", Option::StringOpt, ":", "", false, "video.source", "deltacast-dv"},
|
||||
{"dvs.device", Option::StringOpt, ":", "", false, "video.source", "dvs"},
|
||||
{"ndi.device", Option::StringOpt, ":", "", false, "video.source", "ndi"},
|
||||
{"spout.device", Option::StringOpt, ":", "", false, "video.source", "spout"},
|
||||
{"syphon.device", Option::StringOpt, ":", "", false, "video.source", "syphon"},
|
||||
{"ximea.device", Option::StringOpt, ":", "", false, "video.source", "ximea"},
|
||||
};
|
||||
|
||||
const struct {
|
||||
@@ -275,7 +284,11 @@ std::string Settings::getLaunchParams() const{
|
||||
out += getOption("audio.source").getLaunchOption();
|
||||
out += getOption("audio.source.channels").getLaunchOption();
|
||||
out += getOption("audio.compress").getLaunchOption();
|
||||
out += getOption("audio.playback").getLaunchOption();
|
||||
std::string audioPlay = getOption("audio.playback").getLaunchOption();
|
||||
if(audioPlay.empty() && getOption("preview").isEnabled()){
|
||||
audioPlay = " -r dummy";
|
||||
}
|
||||
out += audioPlay;
|
||||
out += getOption("network.fec").getLaunchOption();
|
||||
out += getOption("network.port").getLaunchOption();
|
||||
out += getOption("network.control_port").getLaunchOption();
|
||||
@@ -371,4 +384,4 @@ void Settings::changedAll(){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* vim: set noexpandtab: */
|
||||
|
||||
@@ -6,11 +6,7 @@
|
||||
|
||||
std::vector<SettingItem> getVideoSrc(AvailableSettings *availSettings){
|
||||
const char * const whiteList[] = {
|
||||
"aja",
|
||||
"dvs",
|
||||
"bitflow",
|
||||
"spout",
|
||||
"syphon"
|
||||
};
|
||||
const std::string optStr = "video.source";
|
||||
|
||||
|
||||
@@ -282,16 +282,13 @@ void UltragridWindow::showSettings(){
|
||||
|
||||
void UltragridWindow::saveSettings(){
|
||||
const auto &optMap = settings.getOptionMap();
|
||||
QFileDialog fileDialog(this);
|
||||
fileDialog.setFileMode(QFileDialog::AnyFile);
|
||||
fileDialog.setNameFilter(tr("Json (*.json)"));
|
||||
fileDialog.setDefaultSuffix("json");
|
||||
|
||||
QStringList fileNames;
|
||||
if (fileDialog.exec())
|
||||
fileNames = fileDialog.selectedFiles();
|
||||
QString filename = QFileDialog::getSaveFileName(this, "Save Settings", "", "Json (*.json)");
|
||||
if(!filename.endsWith(QString(".json"))){
|
||||
filename.append(QString(".json"));
|
||||
}
|
||||
|
||||
QFile outFile(fileNames.first());
|
||||
QFile outFile(filename);
|
||||
|
||||
if (!outFile.open(QIODevice::WriteOnly)) {
|
||||
qWarning("Couldn't open save file.");
|
||||
@@ -344,6 +341,9 @@ void UltragridWindow::loadSettings(){
|
||||
if (fileDialog.exec())
|
||||
fileNames = fileDialog.selectedFiles();
|
||||
|
||||
if(fileNames.empty())
|
||||
return;
|
||||
|
||||
loadSettingsFile(fileNames.first());
|
||||
|
||||
}
|
||||
|
||||
@@ -45,21 +45,22 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "host.h"
|
||||
|
||||
#include "audio/audio.h"
|
||||
#include "audio/audio_playback.h"
|
||||
#include "audio/playback/sdi.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "host.h"
|
||||
#include "lib_common.h"
|
||||
|
||||
#include "tv.h"
|
||||
#include "video_display.h" /* flags */
|
||||
|
||||
struct state_audio_playback {
|
||||
char name[128];
|
||||
const struct audio_playback_info *funcs;
|
||||
void *state;
|
||||
|
||||
struct timeval t0;
|
||||
long long int samples_played;
|
||||
};
|
||||
|
||||
void audio_playback_help(bool full)
|
||||
@@ -73,6 +74,7 @@ int audio_playback_init(const char *device, const char *cfg, struct state_audio_
|
||||
struct state_audio_playback *s;
|
||||
|
||||
s = calloc(1, sizeof(struct state_audio_playback));
|
||||
gettimeofday(&s->t0, NULL);
|
||||
s->funcs = load_library(device, LIBRARY_CLASS_AUDIO_PLAYBACK, AUDIO_PLAYBACK_ABI_VERSION);
|
||||
|
||||
if (s->funcs == NULL) {
|
||||
@@ -111,10 +113,21 @@ struct state_audio_playback *audio_playback_init_null_device(void)
|
||||
|
||||
void audio_playback_done(struct state_audio_playback *s)
|
||||
{
|
||||
if(s) {
|
||||
s->funcs->done(s->state);
|
||||
free(s);
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->samples_played > 0) {
|
||||
struct timeval t1;
|
||||
gettimeofday(&t1, NULL);
|
||||
|
||||
log_msg(LOG_LEVEL_INFO, "Played %lld audio samples in %f seconds (%f samples per second).\n",
|
||||
s->samples_played, tv_diff(t1, s->t0),
|
||||
s->samples_played / tv_diff(t1, s->t0));
|
||||
}
|
||||
|
||||
s->funcs->done(s->state);
|
||||
free(s);
|
||||
}
|
||||
|
||||
unsigned int audio_playback_get_display_flags(struct state_audio_playback *s)
|
||||
@@ -135,6 +148,7 @@ unsigned int audio_playback_get_display_flags(struct state_audio_playback *s)
|
||||
|
||||
void audio_playback_put_frame(struct state_audio_playback *s, struct audio_frame *frame)
|
||||
{
|
||||
s->samples_played += frame->data_len / frame->ch_count / frame->bps;
|
||||
s->funcs->write(s->state, frame);
|
||||
}
|
||||
|
||||
|
||||
@@ -164,9 +164,7 @@ ADD_TO_PARAM("audioenc-frame-duration", "* audioenc-frame-duration=<ms>\n"
|
||||
static void *libavcodec_init(audio_codec_t audio_codec, audio_codec_direction_t direction, bool silent,
|
||||
int bitrate)
|
||||
{
|
||||
if (log_level >= LOG_LEVEL_VERBOSE) {
|
||||
av_log_set_level(AV_LOG_VERBOSE);
|
||||
}
|
||||
av_log_set_level((log_level - 1) * 8);
|
||||
|
||||
enum AVCodecID codec_id = AV_CODEC_ID_NONE;
|
||||
|
||||
|
||||
@@ -103,9 +103,6 @@ struct state_alsa_playback {
|
||||
snd_pcm_t *handle;
|
||||
struct audio_desc desc;
|
||||
|
||||
struct timeval start_time;
|
||||
long long int played_samples;
|
||||
|
||||
/* Local configuration with handle_underrun workaround set for PulseAudio
|
||||
ALSA plugin. Will be NULL if the PA ALSA plugin is not in use or the
|
||||
workaround is not required. */
|
||||
@@ -834,8 +831,6 @@ static void * audio_play_alsa_init(const char *cfg)
|
||||
log_msg(LOG_LEVEL_WARNING, MOD_NAME "Async API is experimental, in case of problems use either \"thread\" or \"sync\" API\n");
|
||||
}
|
||||
|
||||
gettimeofday(&s->start_time, NULL);
|
||||
|
||||
if(cfg && strlen(cfg) > 0) {
|
||||
if(strcmp(cfg, "help") == 0) {
|
||||
printf("Usage\n");
|
||||
@@ -964,8 +959,6 @@ static void audio_play_alsa_write_frame(void *state, struct audio_frame *frame)
|
||||
signed2unsigned(frame->data, frame->data, frame->data_len);
|
||||
}
|
||||
|
||||
s->played_samples += frame->data_len / frame->bps / frame->ch_count;
|
||||
|
||||
int frames = frame->data_len / (frame->bps * frame->ch_count);
|
||||
rc = write_samples(s->handle, frame, frames, s->non_interleaved, s->playback_mode);
|
||||
if (rc == -EPIPE) {
|
||||
@@ -1038,8 +1031,6 @@ static void audio_play_alsa_done(void *state)
|
||||
{
|
||||
struct state_alsa_playback *s = (struct state_alsa_playback *) state;
|
||||
|
||||
struct timeval t;
|
||||
|
||||
if (s->playback_mode == THREAD && s->thread_started) {
|
||||
pthread_mutex_lock(&s->lock);
|
||||
s->should_exit_thread = true;
|
||||
@@ -1051,11 +1042,6 @@ static void audio_play_alsa_done(void *state)
|
||||
snd_async_del_handler(s->pcm_callback);
|
||||
}
|
||||
|
||||
gettimeofday(&t, NULL);
|
||||
log_msg(LOG_LEVEL_INFO, MOD_NAME "Played %lld samples in %f seconds (%f samples per second).\n",
|
||||
s->played_samples, tv_diff(t, s->start_time),
|
||||
s->played_samples / tv_diff(t, s->start_time));
|
||||
|
||||
snd_pcm_drain(s->handle);
|
||||
snd_pcm_close(s->handle);
|
||||
if (s->local_config) {
|
||||
|
||||
@@ -61,7 +61,7 @@ static int read_fmt_chunk(FILE *wav_file, struct wav_metadata *metadata)
|
||||
|
||||
uint16_t ch_count;
|
||||
READ_N(&ch_count, 2);
|
||||
if (ch_count > 100) {
|
||||
if (ch_count > 128) {
|
||||
return WAV_HDR_PARSE_INVALID_PARAM;
|
||||
}
|
||||
metadata->ch_count = ch_count;
|
||||
|
||||
@@ -42,11 +42,24 @@
|
||||
#include "config_win32.h"
|
||||
|
||||
#include "compat/platform_pipe.h"
|
||||
#include "rtp/net_udp.h" // socket_error
|
||||
|
||||
#include <thread>
|
||||
|
||||
using std::thread;
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DECLARE_TIMEOUT(name, init_val_s) DWORD name = init_val_s * 1000
|
||||
typedef char *sockopt_t;
|
||||
#else
|
||||
#define DECLARE_TIMEOUT(name, init_val_s) struct timeval name = { init_val_s, 0 }
|
||||
typedef void *sockopt_t;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_CONFIG_H // compiled outside of UltraGrid
|
||||
#define socket_error(...) fprintf(stderr, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
static fd_t open_socket(int *port)
|
||||
{
|
||||
fd_t sock;
|
||||
@@ -90,12 +103,26 @@ static fd_t connect_to_socket(int local_port)
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
int ret;
|
||||
|
||||
DECLARE_TIMEOUT(timeout, 1);
|
||||
DECLARE_TIMEOUT(old_timeout, 0);
|
||||
socklen_t old_timeout_len = sizeof old_timeout;
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<sockopt_t>(&old_timeout), &old_timeout_len) != 0) {
|
||||
socket_error("pipe getsockopt");
|
||||
}
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<sockopt_t>(&timeout), sizeof timeout) != 0) {
|
||||
socket_error("pipe setsockopt");
|
||||
}
|
||||
ret = connect(fd, (struct sockaddr *) &s_in,
|
||||
sizeof(s_in));
|
||||
if (ret != 0) {
|
||||
socket_error("pipe connect");
|
||||
CLOSESOCKET(fd);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<sockopt_t>(&old_timeout), old_timeout_len) != 0) {
|
||||
socket_error("pipe setsockopt");
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
@@ -113,6 +140,17 @@ static void * worker(void *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// @brief return regular pipe if available if our implementation fails
|
||||
static int system_pipe(fd_t p[2])
|
||||
{
|
||||
#ifdef _WIN32
|
||||
(void) p;
|
||||
return -1;
|
||||
#else
|
||||
fprintf(stderr, "Using native pipe instead of custom implementaton.\n");
|
||||
return pipe(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
int platform_pipe_init(fd_t p[2])
|
||||
{
|
||||
@@ -149,23 +187,37 @@ int platform_pipe_init(fd_t p[2])
|
||||
fd_t sock = open_socket(&par.port);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
perror("open_socket");
|
||||
return -1;
|
||||
return system_pipe(p);
|
||||
}
|
||||
|
||||
DECLARE_TIMEOUT(timeout, 1);
|
||||
DECLARE_TIMEOUT(old_timeout, 0);
|
||||
socklen_t old_timeout_len = sizeof old_timeout;
|
||||
if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<sockopt_t>(&old_timeout), &old_timeout_len) != 0) {
|
||||
socket_error("pipe getsockopt");
|
||||
}
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<sockopt_t>(&timeout), sizeof timeout) != 0) {
|
||||
socket_error("pipe setsockopt");
|
||||
}
|
||||
|
||||
thread thr(worker, &par);
|
||||
|
||||
p[0] = accept(sock, NULL, NULL);
|
||||
if (p[0] == INVALID_SOCKET) {
|
||||
perror("accept");
|
||||
perror("pipe accept");
|
||||
thr.join();
|
||||
CLOSESOCKET(sock);
|
||||
return -1;
|
||||
return system_pipe(p);
|
||||
}
|
||||
thr.join();
|
||||
if (setsockopt(p[0], SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<sockopt_t>(&old_timeout), old_timeout_len) != 0) {
|
||||
socket_error("pipe setsockopt");
|
||||
}
|
||||
p[1] = par.sock;
|
||||
if (p[1] == INVALID_SOCKET) {
|
||||
CLOSESOCKET(sock);
|
||||
perror("accept");
|
||||
return -1;
|
||||
return system_pipe(p);
|
||||
}
|
||||
CLOSESOCKET(sock);
|
||||
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
#ifndef platform_pipe_h
|
||||
#define platform_pipe_h
|
||||
|
||||
#include "config_unix.h"
|
||||
#include "config_win32.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
@@ -45,8 +48,23 @@ extern "C" {
|
||||
int platform_pipe_init(fd_t pipe[2]);
|
||||
void platform_pipe_close(fd_t pipe);
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PLATFORM_PIPE_READ(fd, buf, len) recv(fd, buf, len, 0)
|
||||
#define PLATFORM_PIPE_WRITE(fd, buf, len) send(fd, buf, len, 0)
|
||||
#else
|
||||
// the fallback implementation of platform_pipe is a plain pipe for which
|
||||
// doesn't work send()/recv(). read() and write(), however, works for both
|
||||
// socket and pipe (but doesn't so in Windows, therefore there is used
|
||||
// send()/recv()).
|
||||
//
|
||||
// PLATFORM_PIPE_READ()/PLATFORM_PIPE_WRITE() can be also safely be used if
|
||||
// unsure if underlying fd is a socket or a pipe.
|
||||
#define PLATFORM_PIPE_READ read
|
||||
#define PLATFORM_PIPE_WRITE write
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif /* _PLATFORM_SEMAPHORE_H */
|
||||
#endif /* defined platform_pipe_h */
|
||||
|
||||
@@ -806,8 +806,8 @@ static void * control_thread(void *args)
|
||||
|
||||
while(cur) {
|
||||
if(FD_ISSET(cur->fd, &fds)) {
|
||||
ssize_t ret = recv(cur->fd, cur->buff + cur->buff_len,
|
||||
sizeof(cur->buff) - cur->buff_len, 0);
|
||||
ssize_t ret = PLATFORM_PIPE_READ(cur->fd, cur->buff + cur->buff_len,
|
||||
sizeof(cur->buff) - cur->buff_len);
|
||||
if(ret == -1) {
|
||||
fprintf(stderr, "Error reading socket, closing!!!\n");
|
||||
}
|
||||
|
||||
@@ -179,3 +179,84 @@ void debug_dump(void *lp, int len)
|
||||
start = i; /* next line starting byte */
|
||||
}
|
||||
}
|
||||
|
||||
bool set_log_level(const char *optarg, bool *logger_repeat_msgs) {
|
||||
assert(optarg != nullptr);
|
||||
assert(logger_repeat_msgs != nullptr);
|
||||
|
||||
using namespace std::string_literals;
|
||||
using std::clog;
|
||||
using std::cout;
|
||||
|
||||
static const struct { const char *name; int level; } mapping[] = {
|
||||
{ "quiet", LOG_LEVEL_QUIET },
|
||||
{ "fatal", LOG_LEVEL_FATAL },
|
||||
{ "error", LOG_LEVEL_ERROR },
|
||||
{ "warning", LOG_LEVEL_WARNING},
|
||||
{ "notice", LOG_LEVEL_NOTICE},
|
||||
{ "info", LOG_LEVEL_INFO },
|
||||
{ "verbose", LOG_LEVEL_VERBOSE},
|
||||
{ "debug", LOG_LEVEL_DEBUG },
|
||||
{ "debug2", LOG_LEVEL_DEBUG2 },
|
||||
};
|
||||
|
||||
if ("help"s == optarg) {
|
||||
cout << "log level: [0-" << LOG_LEVEL_MAX;
|
||||
for (auto m : mapping) {
|
||||
cout << "|" << m.name;
|
||||
}
|
||||
cout << "][+repeat]\n";
|
||||
cout << "\trepeat - print repeating log messages\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strstr(optarg, "+repeat") != nullptr) {
|
||||
*logger_repeat_msgs = true;
|
||||
}
|
||||
|
||||
if (optarg[0] == '+') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isdigit(optarg[0])) {
|
||||
long val = strtol(optarg, nullptr, 0);
|
||||
if (val < 0 || val > LOG_LEVEL_MAX) {
|
||||
clog << "Log: wrong value: " << log_level << "\n";
|
||||
return false;
|
||||
}
|
||||
log_level = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto m : mapping) {
|
||||
if (strstr(optarg, m.name) == optarg) {
|
||||
log_level = m.level;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(LOG_LEVEL_ERROR) << "Wrong log level specification: " << optarg << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
void Logger::preinit(bool skip_repeated)
|
||||
{
|
||||
Logger::skip_repeated = skip_repeated;
|
||||
if (rang::rang_implementation::supportsColor()
|
||||
&& rang::rang_implementation::isTerminal(std::cout.rdbuf())
|
||||
&& rang::rang_implementation::isTerminal(std::cerr.rdbuf())) {
|
||||
// force ANSI sequences even when written to ostringstream
|
||||
rang::setControlMode(rang::control::Force);
|
||||
#ifdef _WIN32
|
||||
// ANSI control sequences need to be explicitly set in Windows
|
||||
if (rang::rang_implementation::setWinTermAnsiColors(std::cout.rdbuf()) &&
|
||||
rang::rang_implementation::setWinTermAnsiColors(std::cerr.rdbuf())) {
|
||||
rang::setWinTermMode(rang::winTerm::Ansi);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
std::atomic<Logger::last_message *> Logger::last_msg{};
|
||||
std::atomic<bool> Logger::skip_repeated{true};
|
||||
|
||||
|
||||
61
src/debug.h
61
src/debug.h
@@ -40,6 +40,10 @@
|
||||
#ifndef _RAT_DEBUG_H
|
||||
#define _RAT_DEBUG_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif // ! defined __cplusplus
|
||||
|
||||
#define UNUSED(x) (x=x)
|
||||
|
||||
#define LOG_LEVEL_QUIET 0 ///< suppress all logging
|
||||
@@ -74,48 +78,83 @@ void debug_dump(void*lp, int len);
|
||||
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, __VA_ARGS__)
|
||||
void log_msg(int log_level, const char *format, ...) ATTRIBUTE(format (printf, 2, 3));
|
||||
|
||||
bool set_log_level(const char *optarg, bool *logger_repeat_msgs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <atomic>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "compat/platform_time.h"
|
||||
#include "rang.hpp"
|
||||
|
||||
class keyboard_control; // friend
|
||||
|
||||
// Log, version 0.1: a simple logging class
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
static void preinit(bool skip_repeated);
|
||||
inline Logger(int l) : level(l) {}
|
||||
inline ~Logger() {
|
||||
std::cerr << rang::style::reset << rang::fg::reset;
|
||||
}
|
||||
inline std::ostream& Get() {
|
||||
rang::fg color = rang::fg::reset;
|
||||
rang::style style = rang::style::reset;
|
||||
|
||||
std::string msg = oss.str();
|
||||
|
||||
if (skip_repeated && rang::rang_implementation::isTerminal(std::clog.rdbuf())) {
|
||||
auto last = last_msg.exchange(nullptr);
|
||||
if (last != nullptr && last->msg == msg) {
|
||||
int count = last->count += 1;
|
||||
auto current = last_msg.exchange(last);
|
||||
delete current;
|
||||
std::clog << " Last message repeated " << count << " times\r";
|
||||
return;
|
||||
}
|
||||
if (last != nullptr && last->count > 0) {
|
||||
std::clog << "\n";
|
||||
delete last;
|
||||
}
|
||||
}
|
||||
|
||||
switch (level) {
|
||||
case LOG_LEVEL_FATAL: color = rang::fg::red; style = rang::style::bold; break;
|
||||
case LOG_LEVEL_ERROR: color = rang::fg::red; break;
|
||||
case LOG_LEVEL_WARNING: color = rang::fg::yellow; break;
|
||||
case LOG_LEVEL_NOTICE: color = rang::fg::green; break;
|
||||
}
|
||||
std::cerr << style << color;
|
||||
|
||||
std::ostringstream timestamp;
|
||||
if (log_level >= LOG_LEVEL_VERBOSE) {
|
||||
unsigned long long time_ms = time_since_epoch_in_ms();
|
||||
auto flags = std::cerr.flags();
|
||||
auto precision = std::cerr.precision();
|
||||
std::cerr << "[" << std::fixed << std::setprecision(3) << time_ms / 1000.0 << "] ";
|
||||
std::cerr.precision(precision);
|
||||
std::cerr.flags(flags);
|
||||
auto time_ms = time_since_epoch_in_ms();
|
||||
timestamp << "[" << std::fixed << std::setprecision(3) << time_ms / 1000.0 << "] ";
|
||||
}
|
||||
|
||||
return std::cerr;
|
||||
std::clog << style << color << timestamp.str() << msg << rang::style::reset << rang::fg::reset;
|
||||
|
||||
auto *lmsg = new last_message{std::move(msg)};
|
||||
auto current = last_msg.exchange(lmsg);
|
||||
delete current;
|
||||
}
|
||||
inline std::ostream& Get() {
|
||||
return oss;
|
||||
}
|
||||
private:
|
||||
int level;
|
||||
std::ostringstream oss;
|
||||
|
||||
static std::atomic<bool> skip_repeated;
|
||||
struct last_message {
|
||||
std::string msg;
|
||||
int count{0};
|
||||
};
|
||||
static std::atomic<last_message *> last_msg; // leaks last message upon exit
|
||||
|
||||
friend class keyboard_control;
|
||||
};
|
||||
|
||||
#define LOG(level) \
|
||||
|
||||
@@ -696,7 +696,7 @@ int main(int argc, char **argv)
|
||||
int i;
|
||||
struct cmdline_parameters params;
|
||||
|
||||
if ((init = common_preinit(argc, argv)) == nullptr) {
|
||||
if ((init = common_preinit(argc, argv, nullptr)) == nullptr) {
|
||||
EXIT(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
11
src/host.cpp
11
src/host.cpp
@@ -44,6 +44,8 @@
|
||||
#include "config_win32.h"
|
||||
#endif
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include "host.h"
|
||||
|
||||
#include "audio/audio_capture.h"
|
||||
@@ -184,13 +186,20 @@ static int x11_error_handler(Display *d, XErrorEvent *e) {
|
||||
}
|
||||
#endif
|
||||
|
||||
struct init_data *common_preinit(int argc, char *argv[])
|
||||
struct init_data *common_preinit(int argc, char *argv[], const char *log_opt)
|
||||
{
|
||||
struct init_data *init;
|
||||
bool logger_repeat_msgs = false;
|
||||
|
||||
uv_argc = argc;
|
||||
uv_argv = argv;
|
||||
|
||||
if (log_opt != nullptr && !set_log_level(log_opt, &logger_repeat_msgs)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Logger::preinit(!logger_repeat_msgs);
|
||||
|
||||
#ifdef HAVE_X
|
||||
void *handle = dlopen(X11_LIB_NAME, RTLD_NOW);
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ void set_audio_delay(int val);
|
||||
#define RATE_FLAG_FIXED_RATE (1ll<<62ll) ///< use the bitrate as fixed, not capped
|
||||
|
||||
struct init_data;
|
||||
struct init_data *common_preinit(int argc, char *argv[]);
|
||||
struct init_data *common_preinit(int argc, char *argv[], const char *log_opt);
|
||||
void common_cleanup(struct init_data *init_data);
|
||||
|
||||
/**
|
||||
|
||||
@@ -121,7 +121,7 @@ keyboard_control::keyboard_control(struct module *parent) :
|
||||
m_should_exit(false),
|
||||
m_started(false),
|
||||
m_locked_against_changes(true),
|
||||
guarded_keys { '*', '/', '9', '0', 'c', 'C', 'm', 'M', '>', '<', 'e', 's', 'S', 'v', 'V' }
|
||||
guarded_keys { '*', '/', '9', '0', 'c', 'C', 'm', 'M', '>', '<', 'e', 's', 'S', 'v', 'V', 'r' }
|
||||
{
|
||||
m_start_time = time(NULL);
|
||||
|
||||
@@ -540,6 +540,10 @@ void keyboard_control::run()
|
||||
cout << "Log level: " << log_level << "\n";
|
||||
break;
|
||||
}
|
||||
case 'r':
|
||||
Logger::skip_repeated = !Logger::skip_repeated;
|
||||
cout << "Skip repeated messages: " << std::boolalpha << Logger::skip_repeated << std::noboolalpha << "\n";
|
||||
break;
|
||||
case 's':
|
||||
if (saved_log_level == -1) {
|
||||
saved_log_level = log_level;
|
||||
@@ -672,6 +676,7 @@ void keyboard_control::usage()
|
||||
BOLD("\t M ") << "- mute/unmute sender" << G('M') << "\n" <<
|
||||
BOLD("\t v ") << "- increase verbosity level" << G('v') << "\n" <<
|
||||
BOLD("\t V ") << "- decrease verbosity level" << G('V') << "\n" <<
|
||||
BOLD("\t r ") << "- skip repeated messages (toggle) " << G('r') << "\n" <<
|
||||
BOLD("\t e ") << "- record captured content (toggle)" << G('e') << "\n" <<
|
||||
BOLD("\t h ") << "- show help" << G('h') << "\n" <<
|
||||
BOLD("\t i ") << "- show various information" << G('i') << "\n" <<
|
||||
|
||||
41
src/main.cpp
41
src/main.cpp
@@ -89,6 +89,7 @@
|
||||
#include "ug_runtime_error.hpp"
|
||||
#include "utils/color_out.h"
|
||||
#include "utils/misc.h"
|
||||
#include "utils/nat.h"
|
||||
#include "utils/net.h"
|
||||
#include "utils/thread.h"
|
||||
#include "utils/wait_obj.h"
|
||||
@@ -133,7 +134,6 @@ static constexpr const char *DEFAULT_AUDIO_CODEC = "PCM";
|
||||
#define OPT_PIX_FMTS (('P' << 8) | 'F')
|
||||
#define OPT_PROTOCOL (('P' << 8) | 'R')
|
||||
#define OPT_START_PAUSED (('S' << 8) | 'P')
|
||||
#define OPT_VERBOSE (('V' << 8) | 'E')
|
||||
#define OPT_VIDEO_CODECS (('V' << 8) | 'C')
|
||||
#define OPT_VIDEO_PROTOCOL (('V' << 8) | 'P')
|
||||
#define OPT_WINDOW_TITLE (('W' << 8) | 'T')
|
||||
@@ -173,7 +173,9 @@ struct state_uv {
|
||||
static void should_exit_watcher(state_uv *s) {
|
||||
set_thread_name(__func__);
|
||||
char c;
|
||||
while (recv(s->should_exit_pipe[0], &c, 1, 0) != 1) perror("recv");
|
||||
while (PLATFORM_PIPE_READ(s->should_exit_pipe[0], &c, 1) != 1) {
|
||||
perror("PLATFORM_PIPE_READ");
|
||||
}
|
||||
unique_lock<mutex> lk(s->lock);
|
||||
for (auto c : s->should_exit_callbacks) {
|
||||
get<0>(c)(get<1>(c));
|
||||
@@ -186,7 +188,9 @@ struct state_uv {
|
||||
return;
|
||||
}
|
||||
should_exit_thread_notified = true;
|
||||
while (send(should_exit_pipe[1], &c, 1, 0) != 1) perror("send");
|
||||
while (PLATFORM_PIPE_WRITE(should_exit_pipe[1], &c, 1) != 1) {
|
||||
perror("PLATFORM_PIPE_WRITE");
|
||||
}
|
||||
}
|
||||
static void new_message(struct module *mod)
|
||||
{
|
||||
@@ -374,6 +378,7 @@ static void usage(const char *exec_path, bool full = false)
|
||||
print_help_item("-M <video_mode>", {"received video mode (eg tiled-4K, 3D,",
|
||||
"dual-link)"});
|
||||
print_help_item("-p <postprocess> | help", {"postprocess module"});
|
||||
print_help_item("-N|--nat-traverse"s, {"try to deploy NAT traversal techniques"s});
|
||||
}
|
||||
print_help_item("-f [A:|V:]<settings>", {"FEC settings (audio or video) - use",
|
||||
"\"none\", \"mult:<nr>\",", "\"ldgm:<max_expected_loss>%%\" or", "\"ldgm:<k>:<m>:<c>\"",
|
||||
@@ -716,7 +721,7 @@ int main(int argc, char *argv[])
|
||||
{"capture-filter", required_argument, 0, OPT_CAPTURE_FILTER},
|
||||
{"control-port", required_argument, 0, OPT_CONTROL_PORT},
|
||||
{"encryption", required_argument, 0, OPT_ENCRYPTION},
|
||||
{"verbose", optional_argument, 0, OPT_VERBOSE},
|
||||
{"verbose", optional_argument, nullptr, 'V'},
|
||||
{"window-title", required_argument, 0, OPT_WINDOW_TITLE},
|
||||
{"capabilities", no_argument, 0, OPT_CAPABILITIES},
|
||||
{"audio-delay", required_argument, 0, OPT_AUDIO_DELAY},
|
||||
@@ -729,9 +734,10 @@ int main(int argc, char *argv[])
|
||||
{"param", required_argument, 0, OPT_PARAM},
|
||||
{"pix-fmts", no_argument, 0, OPT_PIX_FMTS},
|
||||
{"video-codecs", no_argument, 0, OPT_VIDEO_CODECS},
|
||||
{"nat-traverse", no_argument, nullptr, 'N'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
const char optstring[] = "d:t:m:r:s:v46c:hM:p:f:P:l:A:";
|
||||
const char *optstring = "d:t:m:r:s:v46c:hM:Np:f:P:l:A:V";
|
||||
|
||||
const char *audio_protocol = "ultragrid_rtp";
|
||||
const char *audio_protocol_opts = "";
|
||||
@@ -739,17 +745,21 @@ int main(int argc, char *argv[])
|
||||
const char *video_protocol = "ultragrid_rtp";
|
||||
const char *video_protocol_opts = "";
|
||||
|
||||
const char *log_opt = nullptr;
|
||||
bool setup_nat_traverse = false;
|
||||
struct ug_nat_traverse *nat_traverse = nullptr;
|
||||
|
||||
// First we need to set verbosity level prior to everything else.
|
||||
// common_preinit() uses the verbosity level.
|
||||
while ((ch =
|
||||
getopt_long(argc, argv, optstring, getopt_options,
|
||||
NULL)) != -1) {
|
||||
switch (ch) {
|
||||
case OPT_VERBOSE:
|
||||
case 'V':
|
||||
if (optarg) {
|
||||
log_level = atoi(optarg);
|
||||
log_opt = optarg;
|
||||
} else {
|
||||
log_level = LOG_LEVEL_VERBOSE;
|
||||
log_level += 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -758,7 +768,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
optind = 1;
|
||||
|
||||
if ((init = common_preinit(argc, argv)) == nullptr) {
|
||||
if ((init = common_preinit(argc, argv, log_opt)) == nullptr) {
|
||||
log_msg(LOG_LEVEL_FATAL, "common_preinit() failed!\n");
|
||||
EXIT(EXIT_FAILURE);
|
||||
}
|
||||
@@ -1057,7 +1067,7 @@ int main(int argc, char *argv[])
|
||||
connection_type = 0;
|
||||
}
|
||||
break;
|
||||
case OPT_VERBOSE:
|
||||
case 'V':
|
||||
break; // already handled earlier
|
||||
case OPT_WINDOW_TITLE:
|
||||
log_msg(LOG_LEVEL_WARNING, "Deprecated option used, please use "
|
||||
@@ -1087,6 +1097,9 @@ int main(int argc, char *argv[])
|
||||
case OPT_VIDEO_CODECS:
|
||||
print_video_codecs();
|
||||
EXIT(EXIT_SUCCESS);
|
||||
case 'N':
|
||||
setup_nat_traverse = true;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage(uv_argv[0]);
|
||||
@@ -1126,7 +1139,7 @@ int main(int argc, char *argv[])
|
||||
audio_codec = "OPUS:sample_rate=48000";
|
||||
}
|
||||
if (requested_compression == nullptr) {
|
||||
requested_compression = "none"; // will be set later
|
||||
requested_compression = "none"; // will be set later by h264_sdp_video_rxtx::send_frame()
|
||||
}
|
||||
if (force_ip_version == 0 && strcasecmp(video_protocol, "rtsp") == 0) {
|
||||
force_ip_version = 4;
|
||||
@@ -1236,6 +1249,10 @@ int main(int argc, char *argv[])
|
||||
EXIT(EXIT_FAIL_CONTROL_SOCK);
|
||||
}
|
||||
|
||||
if (setup_nat_traverse) {
|
||||
nat_traverse = start_nat_traverse(video_rx_port, audio_rx_port);
|
||||
}
|
||||
|
||||
uv.audio = audio_cfg_init (&uv.root_module, audio_host, audio_rx_port,
|
||||
audio_tx_port, audio_send, audio_recv,
|
||||
audio_protocol, audio_protocol_opts,
|
||||
@@ -1502,6 +1519,8 @@ cleanup:
|
||||
if (uv.display_device)
|
||||
display_done(uv.display_device);
|
||||
|
||||
stop_nat_traverse(nat_traverse);
|
||||
|
||||
kc.stop();
|
||||
control_done(control);
|
||||
|
||||
|
||||
@@ -174,9 +174,9 @@ namespace rang_implementation {
|
||||
{
|
||||
// Dynamic load for binary compability with old Windows
|
||||
const auto ptrGetFileInformationByHandleEx
|
||||
= reinterpret_cast<decltype(&GetFileInformationByHandleEx)>(
|
||||
= reinterpret_cast<decltype(&GetFileInformationByHandleEx)>(reinterpret_cast<void *>(
|
||||
GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetFileInformationByHandleEx"));
|
||||
"GetFileInformationByHandleEx")));
|
||||
if (!ptrGetFileInformationByHandleEx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -967,7 +967,7 @@ void udp_exit(socket_udp * s)
|
||||
if (!s->local_is_slave) {
|
||||
if (s->local->multithreaded) {
|
||||
char c = 0;
|
||||
int ret = send(s->local->should_exit_fd[1], &c, 1, 0);
|
||||
int ret = PLATFORM_PIPE_WRITE(s->local->should_exit_fd[1], &c, 1);
|
||||
assert (ret == 1);
|
||||
s->local->should_exit = true;
|
||||
s->local->reader_cv.notify_one();
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* @file spout_receiver.cpp
|
||||
* @author Martin Pulec <martin.pulec@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2018 CESNET, z. s. p. o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. 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.
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED 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 AUTHORS 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 "SpoutSDK/Spout.h"
|
||||
|
||||
#include "spout_receiver.h"
|
||||
|
||||
void *spout_create_receiver(char *name, unsigned int *width, unsigned int *height) {
|
||||
SpoutReceiver *receiver = new SpoutReceiver;
|
||||
receiver->CreateReceiver(name, *width, *height);
|
||||
bool connected;
|
||||
receiver->CheckReceiver(name, *width, *height, connected);
|
||||
if (!connected) {
|
||||
fprintf(stderr, "[SPOUT] Not connected to server '%s'. Is it running?\n", name);
|
||||
receiver->ReleaseReceiver();
|
||||
delete receiver;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return receiver;
|
||||
}
|
||||
|
||||
bool spout_receiver_recvframe(void *s, char *sender_name, unsigned int width, unsigned int height, char *data, GLenum glFormat) {
|
||||
return ((SpoutReceiver *)s)->ReceiveImage(sender_name, width, height, (unsigned char *) data, glFormat);
|
||||
}
|
||||
|
||||
void spout_receiver_delete(void *s) {
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
((SpoutReceiver *)s)->ReleaseReceiver();
|
||||
delete s;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "SpoutSDK/Spout.h"
|
||||
#include <SpoutSDK/Spout.h>
|
||||
|
||||
#include "spout_sender.h"
|
||||
|
||||
|
||||
@@ -44,19 +44,9 @@
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#if defined _MSC_VER || defined __MINGW32__
|
||||
#ifdef EXPORT_DLL_SYMBOLS
|
||||
#define SPOUT_SENDER_DLL_API __declspec(dllexport)
|
||||
#else
|
||||
#define SPOUT_SENDER_DLL_API __declspec(dllimport)
|
||||
#endif
|
||||
#else // other platforms
|
||||
#define SPOUT_SENDER_DLL_API
|
||||
#endif
|
||||
|
||||
SPOUT_SENDER_DLL_API void *spout_sender_register(const char *name, int width, int height);
|
||||
SPOUT_SENDER_DLL_API void spout_sender_sendframe(void *s, int width, int height, unsigned int id);
|
||||
SPOUT_SENDER_DLL_API void spout_sender_unregister(void *s);
|
||||
void *spout_sender_register(const char *name, int width, int height);
|
||||
void spout_sender_sendframe(void *s, int width, int height, unsigned int id);
|
||||
void spout_sender_unregister(void *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ static bool set_fec(struct tx *tx, const char *fec_const)
|
||||
}
|
||||
} else if(strcasecmp(fec, "RS") == 0) {
|
||||
if(tx->media_type == TX_MEDIA_AUDIO) {
|
||||
fprintf(stderr, "LDGM is not currently supported for audio!\n");
|
||||
fprintf(stderr, "Reed–Solomon is not currently supported for audio!\n");
|
||||
ret = false;
|
||||
} else {
|
||||
snprintf(msg->fec_cfg, sizeof(msg->fec_cfg), "RS cfg %s",
|
||||
@@ -651,7 +651,7 @@ tx_send_base(struct tx *tx, struct video_frame *frame, struct rtp *rtp_session,
|
||||
if (tx->bitrate == RATE_AUTO) { // adaptive (spread packets to 75% frame time)
|
||||
packet_rate = packet_rate_auto;
|
||||
} else { // bitrate given manually
|
||||
long long int bitrate = tx->bitrate | RATE_FLAG_FIXED_RATE;
|
||||
long long int bitrate = tx->bitrate & ~RATE_FLAG_FIXED_RATE;
|
||||
int avg_packet_size = tile->data_len / packet_count;
|
||||
packet_rate = 1000ll * 1000 * 1000 * avg_packet_size * 8 / bitrate; // fixed rate
|
||||
if ((tx->bitrate & RATE_FLAG_FIXED_RATE) == 0) { // adaptive capped rate
|
||||
@@ -772,26 +772,22 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, const audio_frame2 *
|
||||
int mult_pos[FEC_MAX_MULT];
|
||||
int mult_index = 0;
|
||||
int mult_first_sent = 0;
|
||||
int rtp_hdr_len;
|
||||
|
||||
fec_check_messages(tx);
|
||||
|
||||
timestamp = get_local_mediatime();
|
||||
perf_record(UVP_SEND, timestamp);
|
||||
|
||||
if(tx->encryption) {
|
||||
rtp_hdr_len = sizeof(crypto_payload_hdr_t) + sizeof(audio_payload_hdr_t);
|
||||
int rtp_hdr_len = sizeof(audio_payload_hdr_t);
|
||||
int hdrs_len = (rtp_is_ipv6(rtp_session) ? 40 : 20) + 8 + 12 + sizeof(audio_payload_hdr_t); // MTU - IP hdr - UDP hdr - RTP hdr - payload_hdr
|
||||
if (tx->encryption) {
|
||||
hdrs_len += sizeof(crypto_payload_hdr_t) + tx->enc_funcs->get_overhead(tx->encryption);
|
||||
rtp_hdr_len += sizeof(crypto_payload_hdr_t);
|
||||
pt = PT_ENCRYPT_AUDIO;
|
||||
} else {
|
||||
rtp_hdr_len = sizeof(audio_payload_hdr_t);
|
||||
pt = PT_AUDIO; /* PT set for audio in our packet format */
|
||||
}
|
||||
|
||||
int hdrs_len = (rtp_is_ipv6(rtp_session) ? 40 : 20) + 8 + 12 + sizeof(audio_payload_hdr_t); // MTU - IP hdr - UDP hdr - RTP hdr - payload_hdr
|
||||
if(tx->encryption) {
|
||||
hdrs_len += sizeof(crypto_payload_hdr_t);
|
||||
}
|
||||
|
||||
for(channel = 0; channel < buffer->get_channel_count(); ++channel)
|
||||
{
|
||||
chan_data = buffer->get_data(channel);
|
||||
|
||||
106
src/utils/misc.c
106
src/utils/misc.c
@@ -183,3 +183,109 @@ void replace_all(char *in, const char *from, const char *to) {
|
||||
}
|
||||
}
|
||||
|
||||
int urlencode_html5_eval(int c)
|
||||
{
|
||||
return isalnum(c) || c == '*' || c == '-' || c == '.' || c == '_';
|
||||
}
|
||||
|
||||
int urlencode_rfc3986_eval(int c)
|
||||
{
|
||||
return isalnum(c) || c == '~' || c == '-' || c == '.' || c == '_';
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all occurences where eval() evaluates to true with %-encoding
|
||||
* @param in input
|
||||
* @param out output array
|
||||
* @param max_len maximal lenght to be written (including terminating NUL)
|
||||
* @param eval_pass predictor if an input character should be kept (functions
|
||||
* from ctype.h may be used)
|
||||
* @param space_plus_replace replace spaces (' ') with ASCII plus sign -
|
||||
* should be true for HTML5 URL encoding, false for RFC 3986
|
||||
* @returns bytes written to out
|
||||
*
|
||||
* @note
|
||||
* Symbol ' ' is not treated specially (unlike in classic URL encoding which
|
||||
* translates it to '+'.
|
||||
* @todo
|
||||
* There may be a LUT as in https://rosettacode.org/wiki/URL_encoding#C
|
||||
*/
|
||||
size_t urlencode(char *out, size_t max_len, const char *in, int (*eval_pass)(int c),
|
||||
bool space_plus_replace)
|
||||
{
|
||||
if (max_len == 0 || max_len >= INT_MAX) { // prevent overflow
|
||||
return 0;
|
||||
}
|
||||
size_t len = 0;
|
||||
while (*in && len < max_len - 1) {
|
||||
if (*in == ' ' && space_plus_replace) {
|
||||
*out++ = '+';
|
||||
in++;
|
||||
} else if (eval_pass(*in) != 0) {
|
||||
*out++ = *in++;
|
||||
len++;
|
||||
} else {
|
||||
if ((int) len < (int) max_len - 3 - 1) {
|
||||
int ret = sprintf(out, "%%%02X", *in++);
|
||||
out += ret;
|
||||
len += ret;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*out = '\0';
|
||||
len++;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline int ishex(int x)
|
||||
{
|
||||
return (x >= '0' && x <= '9') ||
|
||||
(x >= 'a' && x <= 'f') ||
|
||||
(x >= 'A' && x <= 'F');
|
||||
}
|
||||
|
||||
/**
|
||||
* URL decodes input string (replaces all "%XX" sequences with ASCII representation of 0xXX)
|
||||
* @param in input
|
||||
* @param out output array
|
||||
* @param max_len maximal lenght to be written (including terminating NUL)
|
||||
* @returns bytes written, 0 on error
|
||||
*
|
||||
* @note
|
||||
* Symbol '+' is not treated specially (unlike in classic URL decoding which
|
||||
* translates it to ' '.
|
||||
*/
|
||||
size_t urldecode(char *out, size_t max_len, const char *in)
|
||||
{
|
||||
if (max_len == 0) { // avoid (uint) -1 cast
|
||||
return 0;
|
||||
}
|
||||
size_t len = 0;
|
||||
while (*in && len < max_len - 1) {
|
||||
if (*in == '+') {
|
||||
*out++ = ' ';
|
||||
in++;
|
||||
} else if (*in != '%') {
|
||||
*out++ = *in++;
|
||||
} else {
|
||||
in++; // skip '%'
|
||||
if (!ishex(in[0]) || !ishex(in[1])) {
|
||||
return 0;
|
||||
}
|
||||
unsigned int c = 0;
|
||||
if (sscanf(in, "%2x", &c) != 1) {
|
||||
return 0;
|
||||
}
|
||||
*out++ = c;
|
||||
in += 2;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
*out = '\0';
|
||||
len++;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,12 @@
|
||||
#ifndef UTILS_MISC_H_
|
||||
#define UTILS_MISC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstddef>
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -53,6 +58,11 @@ int get_framerate_d(double framerate);
|
||||
#define ESCAPED_COLON "\\:"
|
||||
void replace_all(char *in, const char *from, const char *to);
|
||||
|
||||
int urlencode_html5_eval(int c);
|
||||
int urlencode_rfc3986_eval(int c);
|
||||
size_t urlencode(char *out, size_t max_len, const char *in, int (*eval_pass)(int c), bool space_plus_replace);
|
||||
size_t urldecode(char *out, size_t max_len, const char *in);
|
||||
|
||||
/**
|
||||
* @brief Creates FourCC word
|
||||
*
|
||||
|
||||
204
src/utils/nat.c
Normal file
204
src/utils/nat.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* @file utils/nat.c
|
||||
* @author Martin Pulec <pulec@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2020 CESNET z.s.p.o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. 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.
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED 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 AUTHORS 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "config_unix.h"
|
||||
#include "config_win32.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "utils/nat.h"
|
||||
|
||||
#define ENABLE_STRNATPMPERR 1
|
||||
#define STATICLIB 1
|
||||
#include "ext-deps/libnatpmp-20150609/natpmp.h"
|
||||
|
||||
#define ALLOCATION_TIMEOUT (4 * 3600)
|
||||
|
||||
struct ug_nat_traverse {
|
||||
enum {
|
||||
UG_NAT_TRAVERSE_NONE,
|
||||
UG_NAT_TRAVERSE_NAT_PMP,
|
||||
} traverse;
|
||||
int audio_rx_port;
|
||||
int video_rx_port;
|
||||
};
|
||||
|
||||
static bool nat_pmp_add_mapping(natpmp_t *natpmp, int privateport, int publicport, int lifetime)
|
||||
{
|
||||
if (privateport == 0 && publicport == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int r = 0;
|
||||
/* sendnewportmappingrequest() */
|
||||
r = sendnewportmappingrequest(natpmp, NATPMP_PROTOCOL_UDP,
|
||||
privateport, publicport,
|
||||
lifetime);
|
||||
log_msg(r < 0 ? LOG_LEVEL_ERROR : LOG_LEVEL_VERBOSE,
|
||||
"[NAT PMP] sendnewportmappingrequest returned %d (%s)\n",
|
||||
r, r == 12 ? "SUCCESS" : "FAILED");
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
natpmpresp_t response;
|
||||
do {
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(natpmp->s, &fds);
|
||||
getnatpmprequesttimeout(natpmp, &timeout);
|
||||
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
|
||||
r = readnatpmpresponseorretry(natpmp, &response);
|
||||
log_msg(LOG_LEVEL_VERBOSE, "[NAT PMP] readnatpmpresponseorretry returned %d (%s)\n",
|
||||
r, r == 0 ? "OK" : (r == NATPMP_TRYAGAIN ? "TRY AGAIN" : "FAILED"));
|
||||
} while(r==NATPMP_TRYAGAIN);
|
||||
if(r<0) {
|
||||
log_msg(LOG_LEVEL_ERROR, "[NAT PMP] readnatpmpresponseorretry() failed : %s\n",
|
||||
strnatpmperr(r));
|
||||
return false;
|
||||
}
|
||||
|
||||
log_msg(LOG_LEVEL_INFO, "[NAT PMP] Mapped public port %hu protocol %s to local port %hu "
|
||||
"liftime %u\n",
|
||||
response.pnu.newportmapping.mappedpublicport,
|
||||
response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" :
|
||||
(response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" :
|
||||
"UNKNOWN"),
|
||||
response.pnu.newportmapping.privateport,
|
||||
response.pnu.newportmapping.lifetime);
|
||||
log_msg(LOG_LEVEL_DEBUG, "[NAT PMP] epoch = %u\n", response.epoch);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool setup_nat_pmp(int video_rx_port, int audio_rx_port, int lifetime)
|
||||
{
|
||||
struct in_addr gateway_in_use = { 0 };
|
||||
natpmp_t natpmp;
|
||||
int r = 0;
|
||||
r = initnatpmp(&natpmp, 0, 0);
|
||||
log_msg(r < 0 ? LOG_LEVEL_ERROR : LOG_LEVEL_VERBOSE, "[NAT PMP] initnatpmp returned %d (%s)\n", r,
|
||||
r ? "FAILED" : "SUCCESS");
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
gateway_in_use.s_addr = natpmp.gateway;
|
||||
log_msg(LOG_LEVEL_NOTICE, "[NAT PMP] using gateway: %s\n", inet_ntoa(gateway_in_use));
|
||||
|
||||
/* sendpublicaddressrequest() */
|
||||
r = sendpublicaddressrequest(&natpmp);
|
||||
log_msg(r < 0 ? LOG_LEVEL_ERROR : LOG_LEVEL_VERBOSE, "[NAT PMP] sendpublicaddressrequest returned %d (%s)\n",
|
||||
r, r == 2 ? "SUCCESS" : "FAILED");
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
natpmpresp_t response;
|
||||
do {
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(natpmp.s, &fds);
|
||||
getnatpmprequesttimeout(&natpmp, &timeout);
|
||||
r = select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
|
||||
if(r<0) {
|
||||
log_msg(LOG_LEVEL_ERROR, "[NAT PMP] select()\n");
|
||||
return false;
|
||||
}
|
||||
r = readnatpmpresponseorretry(&natpmp, &response);
|
||||
int sav_errno = errno;
|
||||
log_msg(r < 0 ? LOG_LEVEL_ERROR : LOG_LEVEL_VERBOSE, "[NAT PMP] readnatpmpresponseorretry returned %d (%s)\n",
|
||||
r, r == 0 ? "OK" : ( r== NATPMP_TRYAGAIN ? "TRY AGAIN" : "FAILED"));
|
||||
if (r < 0 && r != NATPMP_TRYAGAIN) {
|
||||
log_msg(LOG_LEVEL_ERROR, "[NAT_PMP] readnatpmpresponseorretry() failed : %s\n",
|
||||
strnatpmperr(r));
|
||||
log_msg(LOG_LEVEL_ERROR, "[NAT PMP] errno=%d '%s'\n",
|
||||
sav_errno, strerror(sav_errno));
|
||||
}
|
||||
} while(r==NATPMP_TRYAGAIN);
|
||||
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
log_msg(LOG_LEVEL_NOTICE, "[NAT PMP] Public IP address: %s\n", inet_ntoa(response.pnu.publicaddress.addr));
|
||||
log_msg(LOG_LEVEL_DEBUG, "[NAT PMP] epoch = %u\n", response.epoch);
|
||||
|
||||
if (!nat_pmp_add_mapping(&natpmp, video_rx_port, video_rx_port, lifetime) ||
|
||||
!nat_pmp_add_mapping(&natpmp, audio_rx_port, audio_rx_port, lifetime)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r = closenatpmp(&natpmp);
|
||||
log_msg(LOG_LEVEL_VERBOSE, "[NAT PMP] closenatpmp() returned %d (%s)\n", r, r==0?"SUCCESS":"FAILED");
|
||||
return r >= 0;
|
||||
}
|
||||
|
||||
struct ug_nat_traverse *start_nat_traverse(int video_rx_port, int audio_rx_port)
|
||||
{
|
||||
assert(video_rx_port >= 0 && video_rx_port <= 65535 && audio_rx_port >= 0 && audio_rx_port <= 65535);
|
||||
struct ug_nat_traverse s = { .audio_rx_port = audio_rx_port, .video_rx_port = video_rx_port };
|
||||
if (setup_nat_pmp(video_rx_port, audio_rx_port, ALLOCATION_TIMEOUT)) {
|
||||
log_msg(LOG_LEVEL_NOTICE, "Successfully set NAT traversal with NAT PMP. Sender can send to external IP address.\n");
|
||||
s.traverse = UG_NAT_TRAVERSE_NAT_PMP;
|
||||
return memcpy(malloc(sizeof s), &s, sizeof s);
|
||||
}
|
||||
// other techniques may follow
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void stop_nat_traverse(struct ug_nat_traverse *s)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (s->traverse) {
|
||||
case UG_NAT_TRAVERSE_NAT_PMP:
|
||||
setup_nat_pmp(s->video_rx_port, s->audio_rx_port, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
free(s);
|
||||
}
|
||||
|
||||
/* vim: set expandtab sw=8: */
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* @file spout_receiver.h
|
||||
* @author Martin Pulec <martin.pulec@cesnet.cz>
|
||||
* @file utils/nat.h
|
||||
* @author Martin Pulec <pulec@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2018 CESNET, z. s. p. o.
|
||||
* Copyright (c) 2020 CESNET z.s.p.o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -35,34 +35,26 @@
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SPOUT_RECEIVER_H_
|
||||
#define SPOUT_RECEIVER_H_
|
||||
#ifndef UTILS_NAT_H_AC13CDA9_2B22_4441_A81A_9858C87CE0AA
|
||||
#define UTILS_NAT_H_AC13CDA9_2B22_4441_A81A_9858C87CE0AA
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <stddef.h>
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif // ! defined __cplusplus
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#if defined _MSC_VER || defined __MINGW32__
|
||||
#ifdef EXPORT_DLL_SYMBOLS
|
||||
#define SPOUT_RECEIVER_DLL_API __declspec(dllexport)
|
||||
#else
|
||||
#define SPOUT_RECEIVER_DLL_API __declspec(dllimport)
|
||||
#endif
|
||||
#else // other platforms
|
||||
#define SPOUT_RECEIVER_DLL_API
|
||||
#endif
|
||||
|
||||
SPOUT_RECEIVER_DLL_API void *spout_create_receiver(char *name, unsigned int *width, unsigned int *height);
|
||||
SPOUT_RECEIVER_DLL_API bool spout_receiver_recvframe(void *s, char *sender_name, unsigned int width, unsigned int height, char *data, GLenum glFormat);
|
||||
SPOUT_RECEIVER_DLL_API void spout_receiver_delete(void *s);
|
||||
struct ug_nat_traverse;
|
||||
|
||||
struct ug_nat_traverse *start_nat_traverse(int video_rx_port, int audio_rx_port);
|
||||
void stop_nat_traverse(struct ug_nat_traverse *);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif
|
||||
|
||||
#endif // SPOUT_RECEIVER_H_
|
||||
#endif // defined UTILS_NAT_H_AC13CDA9_2B22_4441_A81A_9858C87CE0AA
|
||||
|
||||
@@ -106,7 +106,7 @@ struct sdp {
|
||||
};
|
||||
|
||||
struct sdp *new_sdp(int ip_version, const char *receiver) {
|
||||
assert(ip_version == 0 || ip_version == 4 || ip_version == 6);
|
||||
assert(ip_version == 4 || ip_version == 6);
|
||||
struct sdp *sdp;
|
||||
sdp = calloc(1, sizeof(struct sdp));
|
||||
assert(sdp != NULL);
|
||||
@@ -137,9 +137,9 @@ struct sdp *new_sdp(int ip_version, const char *receiver) {
|
||||
connection_address = receiver;
|
||||
}
|
||||
strncpy(sdp->version, "v=0\n", STR_LENGTH - 1);
|
||||
snprintf(sdp->origin, STR_LENGTH, "o=- 0 0 IN IP%d %s\n", ip_version == 0 ? 4 : 6, origin_address);
|
||||
snprintf(sdp->origin, STR_LENGTH, "o=- 0 0 IN IP%d %s\n", ip_version, origin_address);
|
||||
strncpy(sdp->session_name, "s=Ultragrid streams\n", STR_LENGTH - 1);
|
||||
snprintf(sdp->connection, STR_LENGTH, "c=IN IP%d %s\n", ip_version == 0 ? 4 : 6, connection_address);
|
||||
snprintf(sdp->connection, STR_LENGTH, "c=IN IP%d %s\n", ip_version, connection_address);
|
||||
strncpy(sdp->times, "t=0 0\n", STR_LENGTH - 1);
|
||||
|
||||
return sdp;
|
||||
|
||||
@@ -112,6 +112,9 @@ void print_available_capturers()
|
||||
|
||||
void (*deleter)(void *) = nullptr;
|
||||
struct vidcap_type *vt = vci->probe(true, &deleter);
|
||||
if (vt == nullptr) {
|
||||
continue;
|
||||
}
|
||||
printf("[cap][capture] %s\n", item.first.c_str());
|
||||
for (int i = 0; i < vt->card_count; ++i) {
|
||||
printf("[capability][device][v2] {"
|
||||
|
||||
@@ -167,6 +167,12 @@ public:
|
||||
(char *) buffer + (s->desc.height - i - 1) * linesize,
|
||||
linesize);
|
||||
}
|
||||
} else if (s->desc.color_spec == RGBA) { // convert from ABGR and bottom-to-top
|
||||
for(unsigned int i = 0; i < s->desc.height; ++i) {
|
||||
vc_copylineRGBA(s->grabBuffer + i * linesize,
|
||||
buffer + (s->desc.height - i - 1) * linesize,
|
||||
linesize, 16, 8, 0);
|
||||
}
|
||||
} else {
|
||||
memcpy((char *) s->grabBuffer, (char *) buffer, len);
|
||||
}
|
||||
@@ -1317,7 +1323,8 @@ static struct video_frame * vidcap_dshow_grab(void *state, struct audio_frame **
|
||||
s->frame->tiles[0].data = (char *) s->returnBuffer;
|
||||
//fprintf(stderr, "[dshow] s: %p\n", s);
|
||||
//s->tile->data_len = s->width * s->height * 3;
|
||||
s->frame->tiles[0].data_len = s->returnBufferLen;
|
||||
s->frame->tiles[0].data_len = is_codec_opaque(s->frame->color_spec) ? s->returnBufferLen :
|
||||
vc_get_datalen(s->frame->tiles[0].width, s->frame->tiles[0].height, s->frame->color_spec);
|
||||
|
||||
/*
|
||||
fprintf(stderr, "[dshow] s5: %p\n", s);
|
||||
|
||||
@@ -351,24 +351,29 @@ vidcap_bluefish444_probe(bool verbose, void (**deleter)(void *))
|
||||
*deleter = free;
|
||||
|
||||
vt = (struct vidcap_type *) calloc(1, sizeof(struct vidcap_type));
|
||||
if (vt != NULL) {
|
||||
vt->name = "bluefish444";
|
||||
vt->description = "Bluefish444 video capture";
|
||||
|
||||
if (verbose) {
|
||||
BLUE_S32 iDevices;
|
||||
BLUEVELVETC_HANDLE pSDK = bfcFactory();
|
||||
bfcEnumerate(pSDK, &iDevices);
|
||||
bfcDestroy(pSDK);
|
||||
|
||||
vt->card_count = iDevices;
|
||||
vt->cards = (struct device_info *) calloc(iDevices, sizeof(struct device_info));
|
||||
for (int i = 0; i < iDevices; ++i) {
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "%d", i + 1);
|
||||
snprintf(vt->cards[i].name, sizeof vt->cards[i].name, "Bluefish444 card #%d", i);
|
||||
}
|
||||
}
|
||||
if (vt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vt->name = "bluefish444";
|
||||
vt->description = "Bluefish444 video capture";
|
||||
|
||||
if (!verbose) {
|
||||
return vt;
|
||||
}
|
||||
|
||||
BLUE_S32 iDevices;
|
||||
BLUEVELVETC_HANDLE pSDK = bfcFactory();
|
||||
bfcEnumerate(pSDK, &iDevices);
|
||||
bfcDestroy(pSDK);
|
||||
|
||||
vt->card_count = iDevices;
|
||||
vt->cards = (struct device_info *) calloc(iDevices, sizeof(struct device_info));
|
||||
for (int i = 0; i < iDevices; ++i) {
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "%d", i + 1);
|
||||
snprintf(vt->cards[i].name, sizeof vt->cards[i].name, "Bluefish444 card #%d", i);
|
||||
}
|
||||
|
||||
return vt;
|
||||
}
|
||||
|
||||
|
||||
@@ -825,10 +825,11 @@ static struct vidcap_type *vidcap_decklink_probe(bool verbose, void (**deleter)(
|
||||
}
|
||||
list<tuple<int, string, string, string>> modes = get_input_modes (deckLink);
|
||||
int i = 0;
|
||||
const int mode_count = sizeof vt->cards[vt->card_count - 1].modes /
|
||||
sizeof vt->cards[vt->card_count - 1].modes[0];
|
||||
for (auto &m : modes) {
|
||||
for (auto &c : connections) {
|
||||
if (i >= (int) (sizeof vt->cards[vt->card_count - 1].modes /
|
||||
sizeof vt->cards[vt->card_count - 1].modes[0])) { // no space
|
||||
if (i >= mode_count) { // no space
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -843,14 +844,27 @@ static struct vidcap_type *vidcap_decklink_probe(bool verbose, void (**deleter)(
|
||||
}
|
||||
}
|
||||
|
||||
if (i < (int) (sizeof vt->cards[vt->card_count - 1].modes /
|
||||
sizeof vt->cards[vt->card_count - 1].modes[0])) {
|
||||
for (auto &c : connections) {
|
||||
if (i >= mode_count) {
|
||||
break;
|
||||
}
|
||||
snprintf(vt->cards[vt->card_count - 1].modes[i].id,
|
||||
sizeof vt->cards[vt->card_count - 1].modes[i].id,
|
||||
"{\"modeOpt\":\"detect-format\"}");
|
||||
"{\"modeOpt\":\"connection=%s\"}",
|
||||
c.c_str());
|
||||
snprintf(vt->cards[vt->card_count - 1].modes[i].name,
|
||||
sizeof vt->cards[vt->card_count - 1].modes[i].name,
|
||||
"UltraGrid auto-detect");
|
||||
"Decklink Auto (%s)", c.c_str());
|
||||
if (++i >= mode_count) {
|
||||
break;
|
||||
}
|
||||
snprintf(vt->cards[vt->card_count - 1].modes[i].id,
|
||||
sizeof vt->cards[vt->card_count - 1].modes[i].id,
|
||||
"{\"modeOpt\":\"detect-format:connection=%s\"}",
|
||||
c.c_str());
|
||||
snprintf(vt->cards[vt->card_count - 1].modes[i].name,
|
||||
sizeof vt->cards[vt->card_count - 1].modes[i].name,
|
||||
"UltraGrid auto-detect (%s)", c.c_str());
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,21 +122,25 @@ vidcap_deltacast_probe(bool verbose, void (**deleter)(void *))
|
||||
*deleter = free;
|
||||
|
||||
vt = (struct vidcap_type *) calloc(1, sizeof(struct vidcap_type));
|
||||
if (vt != NULL) {
|
||||
vt->name = "deltacast";
|
||||
vt->description = "DELTACAST card";
|
||||
if (vt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
ULONG Result,DllVersion,NbBoards;
|
||||
Result = VHD_GetApiInfo(&DllVersion,&NbBoards);
|
||||
if (Result == VHDERR_NOERROR) {
|
||||
vt->cards = (struct device_info *) calloc(NbBoards, sizeof(struct device_info));
|
||||
vt->card_count = NbBoards;
|
||||
for (ULONG i = 0; i < NbBoards; ++i) {
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "device=%" PRIu32, i);
|
||||
snprintf(vt->cards[i].name, sizeof vt->cards[i].name, "DELTACAST SDI board %" PRIu32, i);
|
||||
}
|
||||
}
|
||||
vt->name = "deltacast";
|
||||
vt->description = "DELTACAST card";
|
||||
|
||||
if (!verbose) {
|
||||
return vt;
|
||||
}
|
||||
|
||||
ULONG Result,DllVersion,NbBoards;
|
||||
Result = VHD_GetApiInfo(&DllVersion,&NbBoards);
|
||||
if (Result == VHDERR_NOERROR) {
|
||||
vt->cards = (struct device_info *) calloc(NbBoards, sizeof(struct device_info));
|
||||
vt->card_count = NbBoards;
|
||||
for (ULONG i = 0; i < NbBoards; ++i) {
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "device=%" PRIu32, i);
|
||||
snprintf(vt->cards[i].name, sizeof vt->cards[i].name, "DELTACAST SDI board %" PRIu32, i);
|
||||
}
|
||||
}
|
||||
return vt;
|
||||
|
||||
@@ -165,38 +165,44 @@ vidcap_deltacast_dvi_probe(bool verbose, void (**deleter)(void *))
|
||||
*deleter = free;
|
||||
|
||||
vt = (struct vidcap_type *) calloc(1, sizeof(struct vidcap_type));
|
||||
if (vt != NULL) {
|
||||
vt->name = "deltacast-dv";
|
||||
vt->description = "DELTACAST DVI/HDMI card";
|
||||
if (vt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
ULONG Result,DllVersion,NbBoards;
|
||||
Result = VHD_GetApiInfo(&DllVersion,&NbBoards);
|
||||
if (Result == VHDERR_NOERROR) {
|
||||
vt->cards = (struct device_info *) calloc(NbBoards, sizeof(struct device_info));
|
||||
vt->card_count = NbBoards;
|
||||
for (ULONG i = 0; i < NbBoards; ++i) {
|
||||
string board{"Unknown board type"};
|
||||
ULONG BoardType;
|
||||
HANDLE BoardHandle = NULL;
|
||||
Result = VHD_OpenBoardHandle(i, &BoardHandle, NULL, 0);
|
||||
VHD_GetBoardProperty(BoardHandle, VHD_CORE_BP_BOARD_TYPE, &BoardType);
|
||||
if (Result == VHDERR_NOERROR)
|
||||
{
|
||||
auto it = board_type_map.find(BoardType);
|
||||
if (it != board_type_map.end()) {
|
||||
board = it->second;
|
||||
}
|
||||
}
|
||||
VHD_CloseBoardHandle(BoardHandle);
|
||||
vt->name = "deltacast-dv";
|
||||
vt->description = "DELTACAST DVI/HDMI card";
|
||||
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "device=%" PRIu32, i);
|
||||
snprintf(vt->cards[i].name, sizeof vt->cards[i].name, "DELTACAST %s #%" PRIu32,
|
||||
board.c_str(), i);
|
||||
}
|
||||
if (!verbose) {
|
||||
return vt;
|
||||
}
|
||||
|
||||
ULONG Result,DllVersion,NbBoards;
|
||||
Result = VHD_GetApiInfo(&DllVersion,&NbBoards);
|
||||
if (Result != VHDERR_NOERROR) {
|
||||
return vt;
|
||||
}
|
||||
|
||||
vt->cards = (struct device_info *) calloc(NbBoards, sizeof(struct device_info));
|
||||
vt->card_count = NbBoards;
|
||||
for (ULONG i = 0; i < NbBoards; ++i) {
|
||||
string board{"Unknown board type"};
|
||||
ULONG BoardType;
|
||||
HANDLE BoardHandle = NULL;
|
||||
Result = VHD_OpenBoardHandle(i, &BoardHandle, NULL, 0);
|
||||
VHD_GetBoardProperty(BoardHandle, VHD_CORE_BP_BOARD_TYPE, &BoardType);
|
||||
if (Result == VHDERR_NOERROR)
|
||||
{
|
||||
auto it = board_type_map.find(BoardType);
|
||||
if (it != board_type_map.end()) {
|
||||
board = it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
VHD_CloseBoardHandle(BoardHandle);
|
||||
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "device=%" PRIu32, i);
|
||||
snprintf(vt->cards[i].name, sizeof vt->cards[i].name, "DELTACAST %s #%" PRIu32,
|
||||
board.c_str(), i);
|
||||
}
|
||||
return vt;
|
||||
}
|
||||
|
||||
|
||||
@@ -650,31 +650,33 @@ static struct vidcap_type *vidcap_dvs_probe(bool verbose, void (**deleter)(void
|
||||
*deleter = free;
|
||||
|
||||
vt = (struct vidcap_type *) calloc(1, sizeof(struct vidcap_type));
|
||||
if (vt != NULL) {
|
||||
vt->name = "dvs";
|
||||
vt->description = "DVS (SMPTE 274M/25i)";
|
||||
if (vt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
vt->name = "dvs";
|
||||
vt->description = "DVS (SMPTE 274M/25i)";
|
||||
|
||||
if (verbose) {
|
||||
int card_idx = 0;
|
||||
sv_handle *sv;
|
||||
char name[128];
|
||||
int res;
|
||||
snprintf(name, 128, "PCI,card:%d", card_idx);
|
||||
res = sv_openex(&sv, name, SV_OPENPROGRAM_DEFAULT, SV_OPENTYPE_DEFAULT, 0, 0);
|
||||
while (res == SV_OK) {
|
||||
vt->card_count = card_idx + 1;
|
||||
vt->cards = realloc(vt->cards, vt->card_count * sizeof(struct device_info));
|
||||
memset(&vt->cards[card_idx], 0, sizeof(struct device_info));
|
||||
strncpy(vt->cards[card_idx].id, name, sizeof vt->cards[card_idx].id - 1);
|
||||
snprintf(vt->cards[card_idx].name, sizeof vt->cards[card_idx].name,
|
||||
"DVS card #%d", card_idx);
|
||||
if (!verbose) {
|
||||
return vt;
|
||||
}
|
||||
int card_idx = 0;
|
||||
sv_handle *sv;
|
||||
char name[128];
|
||||
int res;
|
||||
snprintf(name, 128, "PCI,card:%d", card_idx);
|
||||
res = sv_openex(&sv, name, SV_OPENPROGRAM_DEFAULT, SV_OPENTYPE_DEFAULT, 0, 0);
|
||||
while (res == SV_OK) {
|
||||
vt->card_count = card_idx + 1;
|
||||
vt->cards = realloc(vt->cards, vt->card_count * sizeof(struct device_info));
|
||||
memset(&vt->cards[card_idx], 0, sizeof(struct device_info));
|
||||
strncpy(vt->cards[card_idx].id, name, sizeof vt->cards[card_idx].id - 1);
|
||||
snprintf(vt->cards[card_idx].name, sizeof vt->cards[card_idx].name,
|
||||
"DVS card #%d", card_idx);
|
||||
|
||||
sv_close(sv);
|
||||
card_idx++;
|
||||
snprintf(name, 128, "PCI,card:%d", card_idx);
|
||||
res = sv_openex(&sv, name, SV_OPENPROGRAM_DEFAULT, SV_OPENTYPE_DEFAULT, 0, 0);
|
||||
}
|
||||
}
|
||||
sv_close(sv);
|
||||
card_idx++;
|
||||
snprintf(name, 128, "PCI,card:%d", card_idx);
|
||||
res = sv_openex(&sv, name, SV_OPENPROGRAM_DEFAULT, SV_OPENTYPE_DEFAULT, 0, 0);
|
||||
}
|
||||
return vt;
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ static void show_help() {
|
||||
cout << "\t\t" << p_sources[i].p_ndi_name << " - " << p_sources[i].p_url_address << "\n";
|
||||
}
|
||||
cout << "\n";
|
||||
NDIlib_find_destroy(pNDI_find);
|
||||
}
|
||||
|
||||
static int vidcap_ndi_init(struct vidcap_params *params, void **state)
|
||||
@@ -416,34 +417,39 @@ static struct vidcap_type *vidcap_ndi_probe(bool verbose, void (**deleter)(void
|
||||
vt->name = "ndi";
|
||||
vt->description = "NDI source";
|
||||
|
||||
if (verbose) {
|
||||
auto pNDI_find = NDIlib_find_create_v2();
|
||||
if (pNDI_find == nullptr) {
|
||||
LOG(LOG_LEVEL_ERROR) << "[NDI] Cannot create finder object!\n";
|
||||
return vt;
|
||||
}
|
||||
|
||||
uint32_t nr_sources = 0;
|
||||
const NDIlib_source_t* p_sources = nullptr;
|
||||
// Give sources some time to occur
|
||||
usleep(100 * 1000);
|
||||
// we do not usea NDIlib_find_wait_for_sources() here because: 1) if there is
|
||||
// no source, it will still wait requested amount of time and 2) if there are
|
||||
// more sources, it will continue after first source found while there can be more
|
||||
p_sources = NDIlib_find_get_current_sources(pNDI_find, &nr_sources);
|
||||
|
||||
vt->cards = (struct device_info *) malloc(nr_sources * sizeof(struct device_info));
|
||||
if (vt->cards == nullptr) {
|
||||
return vt;
|
||||
}
|
||||
vt->card_count = nr_sources;
|
||||
for (int i = 0; i < static_cast<int>(nr_sources); ++i) {
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "ndi:url=%s", p_sources[i].p_url_address);
|
||||
snprintf(vt->cards[i].name, sizeof vt->cards[i].name, "%s", p_sources[i].p_ndi_name);
|
||||
vt->cards[i].repeatable = true;
|
||||
}
|
||||
if (!verbose) {
|
||||
return vt;
|
||||
}
|
||||
|
||||
auto pNDI_find = NDIlib_find_create_v2();
|
||||
if (pNDI_find == nullptr) {
|
||||
LOG(LOG_LEVEL_ERROR) << "[NDI] Cannot create finder object!\n";
|
||||
return vt;
|
||||
}
|
||||
|
||||
uint32_t nr_sources = 0;
|
||||
const NDIlib_source_t* p_sources = nullptr;
|
||||
// Give sources some time to occur
|
||||
usleep(100 * 1000);
|
||||
// we do not usea NDIlib_find_wait_for_sources() here because: 1) if there is
|
||||
// no source, it will still wait requested amount of time and 2) if there are
|
||||
// more sources, it will continue after first source found while there can be more
|
||||
p_sources = NDIlib_find_get_current_sources(pNDI_find, &nr_sources);
|
||||
|
||||
vt->cards = (struct device_info *) calloc(nr_sources, sizeof(struct device_info));
|
||||
if (vt->cards == nullptr) {
|
||||
NDIlib_find_destroy(pNDI_find);
|
||||
return vt;
|
||||
}
|
||||
vt->card_count = nr_sources;
|
||||
for (int i = 0; i < static_cast<int>(nr_sources); ++i) {
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "url=%s", p_sources[i].p_url_address);
|
||||
snprintf(vt->cards[i].name, sizeof vt->cards[i].name, "%s", p_sources[i].p_ndi_name);
|
||||
vt->cards[i].repeatable = true;
|
||||
}
|
||||
|
||||
NDIlib_find_destroy(pNDI_find);
|
||||
|
||||
return vt;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,6 @@ static struct vidcap_type * vidcap_screen_win_probe(bool verbose, void (**delete
|
||||
vt->card_count = 1;
|
||||
vt->cards = calloc(vt->card_count, sizeof(struct device_info));
|
||||
// vt->cards[0].id can be "" since screen cap. doesn't require parameters
|
||||
snprintf(vt->cards[0].id, sizeof vt->cards[0].id, "screen");
|
||||
snprintf(vt->cards[0].name, sizeof vt->cards[0].name, "Screen capture");
|
||||
|
||||
return vt;
|
||||
|
||||
@@ -41,25 +41,40 @@
|
||||
#include "config_win32.h"
|
||||
#endif
|
||||
|
||||
#include "gl_context.h" // it looks like it needs to be included prior to Spout.h
|
||||
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <SpoutSDK/Spout.h>
|
||||
#include <string>
|
||||
|
||||
#include "debug.h"
|
||||
#include "gl_context.h"
|
||||
#include "host.h"
|
||||
#include "lib_common.h"
|
||||
#include "spout_receiver.h"
|
||||
#include "utils/color_out.h"
|
||||
#include "utils/misc.h" // urlencode, urldecode
|
||||
#include "video.h"
|
||||
#include "video_capture.h"
|
||||
|
||||
#define DEFAULT_FPS 60.0
|
||||
#define DEFAULT_CODEC RGB
|
||||
|
||||
static constexpr const char *MOD_NAME = "[SPOUT] ";
|
||||
|
||||
using std::array;
|
||||
using std::cout;
|
||||
using std::shared_ptr;
|
||||
using std::stoi;
|
||||
using std::string;
|
||||
|
||||
/**
|
||||
* Class state_vidcap_spout must be value-initialized
|
||||
*/
|
||||
struct state_vidcap_spout {
|
||||
struct video_desc desc;
|
||||
void *spout_state;
|
||||
shared_ptr<SpoutReceiver> spout_state;
|
||||
struct gl_context glc;
|
||||
GLenum gl_format;
|
||||
|
||||
@@ -72,17 +87,59 @@ struct state_vidcap_spout {
|
||||
|
||||
static void usage()
|
||||
{
|
||||
printf("\t-t spout[:name=<server_name>][:fps=<fps>][:codec=<codec>]\n");
|
||||
printf("\n");
|
||||
printf("\tname\n\t\tSPOUT server name\n");
|
||||
printf("\tfps\n\t\tFPS count (default: %.2lf)\n", DEFAULT_FPS);
|
||||
printf("\tcodec\n\t\tvideo codec (default: %s)\n", get_codec_name(DEFAULT_CODEC));
|
||||
cout << "Usage:\n";
|
||||
cout << "\t" << BOLD(RED("-t spout") << "[:name=<server_name>|device=<idx>][:fps=<fps>][:codec=<codec>]") << "\n";
|
||||
cout << "where\n";
|
||||
cout << "\t" << BOLD("name") << "\n\t\tSPOUT server name\n";
|
||||
cout << "\t" << BOLD("fps") << "\n\t\tFPS count (default: " << DEFAULT_FPS << ")\n";
|
||||
cout << "\t" << BOLD("codec") << "\n\t\tvideo codec (default: " << get_codec_name(DEFAULT_CODEC) << ")\n";
|
||||
cout << "\nServers:\n";
|
||||
auto receiver = shared_ptr<SpoutReceiver>(new SpoutReceiver);
|
||||
int count = receiver->GetSenderCount();
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
array<char, 256> name{};
|
||||
if (!receiver->GetSenderName(i, name.data(), name.size())) {
|
||||
LOG(LOG_LEVEL_ERROR) << "Cannot get name for server #" << i << "\n";
|
||||
continue;
|
||||
}
|
||||
unsigned int width = 0;
|
||||
unsigned int height = 0;
|
||||
HANDLE dxShareHandle = 0;
|
||||
DWORD dwFormat = 0;
|
||||
if (!receiver->GetSenderInfo(name.data(), width, height, dxShareHandle, dwFormat)) {
|
||||
LOG(LOG_LEVEL_ERROR) << "Cannot get server " << name.data() << "details\n";
|
||||
}
|
||||
cout << "\t" << i << ") " << BOLD(name.data()) << " - width: " << width << ", height: " << height << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
static string vidcap_spout_get_device_name(int idx)
|
||||
{
|
||||
if (idx < 0) {
|
||||
LOG(LOG_LEVEL_ERROR) << MOD_NAME << "Negative indices not allowed, given: " << idx << "\n";
|
||||
return {};
|
||||
}
|
||||
auto receiver = shared_ptr<SpoutReceiver>(new SpoutReceiver);
|
||||
int count = receiver->GetSenderCount();
|
||||
if (idx >= count) {
|
||||
LOG(LOG_LEVEL_ERROR) << MOD_NAME << "Cannot find server #" << idx << " (total count " << count << ")!\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
array<char, 256> name{};
|
||||
if (!receiver->GetSenderName(idx, name.data(), name.size())) {
|
||||
LOG(LOG_LEVEL_ERROR) << "Cannot get name for server #" << idx << "\n";
|
||||
return {};
|
||||
}
|
||||
return name.data();
|
||||
}
|
||||
|
||||
static int vidcap_spout_init(struct vidcap_params *params, void **state)
|
||||
{
|
||||
state_vidcap_spout *s = new state_vidcap_spout();
|
||||
|
||||
int device_idx = 0;
|
||||
double fps = DEFAULT_FPS;
|
||||
codec_t codec = DEFAULT_CODEC;
|
||||
|
||||
@@ -96,8 +153,19 @@ static int vidcap_spout_init(struct vidcap_params *params, void **state)
|
||||
usage();
|
||||
ret = VIDCAP_INIT_NOERR;
|
||||
break;
|
||||
} else if (strstr(item, "device=") == item) {
|
||||
device_idx = stoi(item + strlen("device="));
|
||||
} else if (strstr(item, "name=") == item) {
|
||||
strncpy(s->server_name, item + strlen("name="), sizeof(s->server_name) - 1);
|
||||
char *name = item + strlen("name=");
|
||||
if (strstr(name, "urlencoded=") == name) {
|
||||
name += strlen("urlencoded=");
|
||||
if (urldecode(s->server_name, sizeof s->server_name, name) == 0) {
|
||||
LOG(LOG_LEVEL_WARNING) << MOD_NAME << "Improperly formatted name: " << item + strlen("name=") << "\n";
|
||||
ret = VIDCAP_INIT_FAIL;
|
||||
}
|
||||
} else {
|
||||
strncpy(s->server_name, item + strlen("name="), sizeof(s->server_name) - 1);
|
||||
}
|
||||
} else if (strstr(item, "fps=") == item) {
|
||||
fps = atof(item + strlen("fps="));
|
||||
} else if (strstr(item, "codec=") == item) {
|
||||
@@ -130,6 +198,15 @@ static int vidcap_spout_init(struct vidcap_params *params, void **state)
|
||||
return VIDCAP_INIT_FAIL;
|
||||
}
|
||||
|
||||
if (strlen(s->server_name) == 0) {
|
||||
const string &name = vidcap_spout_get_device_name(device_idx);
|
||||
if (name.empty()) {
|
||||
delete s;
|
||||
return VIDCAP_INIT_FAIL;
|
||||
}
|
||||
strncpy(s->server_name, name.c_str(), sizeof s->server_name - 1);
|
||||
}
|
||||
|
||||
if (!init_gl_context(&s->glc, GL_CONTEXT_ANY)) {
|
||||
LOG(LOG_LEVEL_ERROR) << "[SPOUT] Unable to initialize GL context!\n";
|
||||
delete s;
|
||||
@@ -139,14 +216,17 @@ static int vidcap_spout_init(struct vidcap_params *params, void **state)
|
||||
|
||||
unsigned int width = 0, height = 0;
|
||||
|
||||
s->spout_state = spout_create_receiver(s->server_name, &width, &height);
|
||||
if (!s->spout_state) {
|
||||
LOG(LOG_LEVEL_ERROR) << "[SPOUT] Unable to initialize SPOUT state!\n";
|
||||
s->spout_state = shared_ptr<SpoutReceiver>(new SpoutReceiver);
|
||||
s->spout_state->CreateReceiver(s->server_name, width, height);
|
||||
bool connected;
|
||||
s->spout_state->CheckReceiver(s->server_name, width, height, connected);
|
||||
if (!connected) {
|
||||
LOG(LOG_LEVEL_ERROR) << "[SPOUT] Not connected to server '" << s->server_name << "'. Is it running?\n";
|
||||
s->spout_state->ReleaseReceiver();
|
||||
delete s;
|
||||
return VIDCAP_INIT_FAIL;
|
||||
} else {
|
||||
LOG(LOG_LEVEL_NOTICE) << "[SPOUT] Initialized successfully - server name: " << s->server_name << ", width: " << width << ", height: " << height << ", fps: " << fps << ", codec: " << get_codec_name_long(codec) << "\n";
|
||||
}
|
||||
LOG(LOG_LEVEL_NOTICE) << "[SPOUT] Initialized successfully - server name: " << s->server_name << ", width: " << width << ", height: " << height << ", fps: " << fps << ", codec: " << get_codec_name_long(codec) << "\n";
|
||||
|
||||
s->desc = video_desc{width, height, codec, fps, PROGRESSIVE, 1};
|
||||
|
||||
@@ -162,7 +242,7 @@ static void vidcap_spout_done(void *state)
|
||||
state_vidcap_spout *s = (state_vidcap_spout *) state;
|
||||
|
||||
gl_context_make_current(&s->glc);
|
||||
spout_receiver_delete(s->spout_state);
|
||||
s->spout_state->ReleaseReceiver();
|
||||
destroy_gl_context(&s->glc);
|
||||
|
||||
delete s;
|
||||
@@ -175,12 +255,11 @@ static struct video_frame *vidcap_spout_grab(void *state, struct audio_frame **a
|
||||
struct video_frame *out = vf_alloc_desc_data(s->desc);
|
||||
out->callbacks.dispose = vf_free;
|
||||
|
||||
bool ret;
|
||||
unsigned int width, height;
|
||||
width = s->desc.width;
|
||||
height = s->desc.height;
|
||||
gl_context_make_current(&s->glc);
|
||||
ret = spout_receiver_recvframe(s->spout_state, s->server_name, width, height, out->tiles[0].data, s->gl_format);
|
||||
bool ret = s->spout_state->ReceiveImage(s->server_name, width, height, (unsigned char *) out->tiles[0].data, s->gl_format);
|
||||
gl_context_make_current(NULL);
|
||||
if (ret) {
|
||||
// statistics
|
||||
@@ -220,6 +299,35 @@ static struct vidcap_type *vidcap_spout_probe(bool verbose, void (**deleter)(voi
|
||||
vt->name = "spout";
|
||||
vt->description = "SPOUT capture client";
|
||||
}
|
||||
|
||||
if (!verbose) {
|
||||
return vt;
|
||||
}
|
||||
|
||||
auto receiver = shared_ptr<SpoutReceiver>(new SpoutReceiver);
|
||||
int count = receiver->GetSenderCount();
|
||||
|
||||
vt->cards = (struct device_info *) calloc(count, sizeof(struct device_info));
|
||||
if (vt->cards == nullptr) {
|
||||
return vt;
|
||||
}
|
||||
vt->card_count = count;
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
array<char, 256> name{};
|
||||
if (!receiver->GetSenderName(i, name.data(), name.size())) {
|
||||
LOG(LOG_LEVEL_VERBOSE) << MOD_NAME << "Cannot get name for server #" << i << "\n";
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "device=%d", i);
|
||||
snprintf(vt->cards[i].name, sizeof vt->cards[i].name, "SPOUT #%d", i);
|
||||
} else {
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "name=urlencoded=");
|
||||
urlencode(vt->cards[i].id + strlen(vt->cards[i].id),
|
||||
sizeof vt->cards[i].id - strlen(vt->cards[i].id),
|
||||
name.data(), urlencode_rfc3986_eval, false);
|
||||
snprintf(vt->cards[i].name, sizeof vt->cards[i].name, "SPOUT %s", name.data());
|
||||
}
|
||||
vt->cards[i].repeatable = true;
|
||||
}
|
||||
return vt;
|
||||
}
|
||||
|
||||
|
||||
@@ -816,59 +816,60 @@ static struct vidcap_type *vidcap_testcard_probe(bool verbose, void (**deleter)(
|
||||
*deleter = free;
|
||||
|
||||
vt = (struct vidcap_type *) calloc(1, sizeof(struct vidcap_type));
|
||||
if (vt != NULL) {
|
||||
vt->name = "testcard";
|
||||
vt->description = "Video testcard";
|
||||
if (vt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
vt->card_count = 1;
|
||||
vt->cards = (struct device_info *) calloc(vt->card_count, sizeof(struct device_info));
|
||||
vt->cards[0].id[0] = '\0';
|
||||
snprintf(vt->cards[0].name, sizeof vt->cards[0].name, "Testing signal");
|
||||
vt->name = "testcard";
|
||||
vt->description = "Video testcard";
|
||||
|
||||
struct {
|
||||
int width;
|
||||
int height;
|
||||
} sizes[] = {
|
||||
{1280, 720},
|
||||
{1920, 1080},
|
||||
{3840, 2160},
|
||||
};
|
||||
int framerates[] = {24, 30, 60};
|
||||
const char * const pix_fmts[] = {"UYVY", "RGB"};
|
||||
if (!verbose) {
|
||||
return vt;
|
||||
}
|
||||
|
||||
snprintf(vt->cards[0].modes[0].name,
|
||||
sizeof vt->cards[0].name, "Default");
|
||||
snprintf(vt->cards[0].modes[0].id,
|
||||
sizeof vt->cards[0].id,
|
||||
"{\"width\":\"\", "
|
||||
"\"height\":\"\", "
|
||||
"\"format\":\"\", "
|
||||
"\"fps\":\"\"}");
|
||||
vt->card_count = 1;
|
||||
vt->cards = (struct device_info *) calloc(vt->card_count, sizeof(struct device_info));
|
||||
snprintf(vt->cards[0].name, sizeof vt->cards[0].name, "Testing signal");
|
||||
|
||||
int i = 1;
|
||||
for(const auto &pix_fmt : pix_fmts){
|
||||
for(const auto &size : sizes){
|
||||
for(const auto &fps : framerates){
|
||||
snprintf(vt->cards[0].modes[i].name,
|
||||
sizeof vt->cards[0].name,
|
||||
"%dx%d@%d %s",
|
||||
size.width, size.height,
|
||||
fps, pix_fmt);
|
||||
snprintf(vt->cards[0].modes[i].id,
|
||||
sizeof vt->cards[0].id,
|
||||
"{\"width\":\"%d\", "
|
||||
"\"height\":\"%d\", "
|
||||
"\"format\":\"%s\", "
|
||||
"\"fps\":\"%d\"}",
|
||||
size.width, size.height,
|
||||
pix_fmt, fps);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
struct {
|
||||
int width;
|
||||
int height;
|
||||
} sizes[] = {
|
||||
{1280, 720},
|
||||
{1920, 1080},
|
||||
{3840, 2160},
|
||||
};
|
||||
int framerates[] = {24, 30, 60};
|
||||
const char * const pix_fmts[] = {"UYVY", "RGB"};
|
||||
|
||||
snprintf(vt->cards[0].modes[0].name,
|
||||
sizeof vt->cards[0].name, "Default");
|
||||
snprintf(vt->cards[0].modes[0].id,
|
||||
sizeof vt->cards[0].id,
|
||||
"{\"width\":\"\", "
|
||||
"\"height\":\"\", "
|
||||
"\"format\":\"\", "
|
||||
"\"fps\":\"\"}");
|
||||
|
||||
int i = 1;
|
||||
for(const auto &pix_fmt : pix_fmts){
|
||||
for(const auto &size : sizes){
|
||||
for(const auto &fps : framerates){
|
||||
snprintf(vt->cards[0].modes[i].name,
|
||||
sizeof vt->cards[0].name,
|
||||
"%dx%d@%d %s",
|
||||
size.width, size.height,
|
||||
fps, pix_fmt);
|
||||
snprintf(vt->cards[0].modes[i].id,
|
||||
sizeof vt->cards[0].id,
|
||||
"{\"width\":\"%d\", "
|
||||
"\"height\":\"%d\", "
|
||||
"\"format\":\"%s\", "
|
||||
"\"fps\":\"%d\"}",
|
||||
size.width, size.height,
|
||||
pix_fmt, fps);
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return vt;
|
||||
|
||||
@@ -351,9 +351,8 @@ static struct vidcap_type *vidcap_ximea_probe(bool verbose, void (**deleter)(voi
|
||||
|
||||
vt->cards = calloc(count, sizeof(struct device_info));
|
||||
for (DWORD i = 0; i < count; ++i) {
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "ximea:device=%d", (int) i);
|
||||
snprintf(vt->cards[i].id, sizeof vt->cards[i].id, "device=%d", (int) i);
|
||||
char name[256];
|
||||
color_out(COLOR_OUT_BOLD, "%d) ", (int) i);
|
||||
if (funcs.xiGetDeviceInfoString(i, XI_PRM_DEVICE_NAME, name, sizeof name) == XI_OK) {
|
||||
strncpy(vt->cards[i].name, name, sizeof vt->cards[i].name);
|
||||
}
|
||||
|
||||
@@ -501,9 +501,7 @@ struct module * libavcodec_compress_init(struct module *parent, const char *opts
|
||||
|
||||
s = new state_video_compress_libav();
|
||||
s->lavcd_global_lock = rm_acquire_shared_lock(LAVCD_LOCK_NAME);
|
||||
if (log_level >= LOG_LEVEL_VERBOSE) {
|
||||
av_log_set_level(AV_LOG_VERBOSE);
|
||||
}
|
||||
av_log_set_level((log_level - 1) * 8);
|
||||
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(58, 9, 100)
|
||||
/* register all the codecs (you can also register only the codec
|
||||
* you wish to have smaller code */
|
||||
@@ -675,29 +673,26 @@ bool set_codec_ctx_params(struct state_video_compress_libav *s, AVPixelFormat pi
|
||||
|
||||
// set bitrate
|
||||
if ((s->requested_bitrate > 0 || s->requested_bpp > 0.0)
|
||||
|| !is_x264_x265) {
|
||||
|| (!is_x264_x265 && s->requested_crf == -1 && s->requested_cqp == -1)) {
|
||||
s->codec_ctx->bit_rate = bitrate;
|
||||
s->codec_ctx->bit_rate_tolerance = bitrate / desc.fps * 6;
|
||||
LOG(LOG_LEVEL_INFO) << MOD_NAME << "Setting bitrate to " << bitrate << " bps.\n";
|
||||
}
|
||||
|
||||
if (is_x264_x265) {
|
||||
} else {
|
||||
// set CRF unless explicitly specified CQP or ABR (bitrate)
|
||||
if (s->requested_crf >= 0.0 || (s->requested_bitrate == 0 && s->requested_bpp == 0.0 && s->requested_cqp == -1)) {
|
||||
double crf = s->requested_crf >= 0.0 ? s->requested_crf : DEFAULT_X264_X265_CRF;
|
||||
av_opt_set_double(s->codec_ctx->priv_data, "crf", crf, 0);
|
||||
log_msg(LOG_LEVEL_INFO, "[lavc] Setting CRF to %.2f.\n", crf);
|
||||
if (int rc = av_opt_set_double(s->codec_ctx->priv_data, "crf", crf, 0)) {
|
||||
print_libav_error(LOG_LEVEL_WARNING, MOD_NAME "Warning: Unable to set CRF", rc);
|
||||
} else {
|
||||
log_msg(LOG_LEVEL_INFO, "[lavc] Setting CRF to %.2f.\n", crf);
|
||||
}
|
||||
}
|
||||
if (s->requested_cqp >= 0) {
|
||||
av_opt_set_int(s->codec_ctx->priv_data, "qp", s->requested_cqp, 0);
|
||||
log_msg(LOG_LEVEL_INFO, "[lavc] Setting CQP to %d.\n", s->requested_cqp);
|
||||
}
|
||||
} else {
|
||||
if (s->requested_crf >= 0.0) {
|
||||
log_msg(LOG_LEVEL_WARNING, "[lavc] Unable to set CRF! Not supported for this encoder, ignored.\n");
|
||||
}
|
||||
if (s->requested_cqp >= 0.0) {
|
||||
log_msg(LOG_LEVEL_WARNING, "[lavc] Unable to set CQP! Not supported for this encoder, ignored.\n");
|
||||
if (int rc = av_opt_set_int(s->codec_ctx->priv_data, "qp", s->requested_cqp, 0)) {
|
||||
print_libav_error(LOG_LEVEL_WARNING, MOD_NAME "Warning: Unable to set CQP", rc);
|
||||
} else {
|
||||
log_msg(LOG_LEVEL_INFO, "[lavc] Setting CQP to %d.\n", s->requested_cqp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -375,9 +375,7 @@ static void * libavcodec_decompress_init(void)
|
||||
calloc(1, sizeof(struct state_libavcodec_decompress));
|
||||
|
||||
s->global_lavcd_lock = rm_acquire_shared_lock(LAVCD_LOCK_NAME);
|
||||
if (log_level >= LOG_LEVEL_VERBOSE) {
|
||||
av_log_set_level(AV_LOG_VERBOSE);
|
||||
}
|
||||
av_log_set_level((log_level - 1) * 8);
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(58, 9, 100)
|
||||
/* register all the codecs (you can also register only the codec
|
||||
|
||||
@@ -259,7 +259,7 @@ static int display_ndi_get_property(void *state, int property, void *val, size_t
|
||||
{
|
||||
assert(*len == sizeof(struct audio_desc));
|
||||
struct audio_desc *desc = (struct audio_desc *) val;
|
||||
desc->bps = 4;
|
||||
desc->bps = desc->bps <= 2 ? 2 : 4;
|
||||
desc->codec = AC_PCM;
|
||||
}
|
||||
break;
|
||||
@@ -269,22 +269,28 @@ static int display_ndi_get_property(void *state, int property, void *val, size_t
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define NDI_SEND_AUDIO(frame, bit_depth) do { \
|
||||
assert((frame)->bps * 8 == (bit_depth)); \
|
||||
NDIlib_audio_frame_interleaved_ ## bit_depth ## s_t NDI_audio_frame = { 0 }; \
|
||||
NDI_audio_frame.sample_rate = (frame)->sample_rate; \
|
||||
NDI_audio_frame.no_channels = (frame)->ch_count; \
|
||||
NDI_audio_frame.timecode = NDIlib_send_timecode_synthesize; \
|
||||
NDI_audio_frame.p_data = (int ## bit_depth ## _t *) (frame)->data; \
|
||||
NDI_audio_frame.no_samples = (frame)->data_len / (frame)->ch_count / ((bit_depth) / 8); \
|
||||
\
|
||||
NDIlib_util_send_send_audio_interleaved_ ## bit_depth ## s(s->pNDI_send, &NDI_audio_frame); \
|
||||
} while(0)
|
||||
|
||||
static void display_ndi_put_audio_frame(void *state, struct audio_frame *frame)
|
||||
{
|
||||
struct display_ndi *s = (struct display_ndi *) state;
|
||||
assert(frame->bps == 4);
|
||||
float *tmp = malloc(frame->data_len);
|
||||
NDIlib_audio_frame_v2_t NDI_audio_frame = { 0 };
|
||||
NDI_audio_frame.sample_rate = frame->sample_rate;
|
||||
NDI_audio_frame.no_channels = frame->ch_count;
|
||||
NDI_audio_frame.timecode = NDIlib_send_timecode_synthesize;
|
||||
NDI_audio_frame.p_data = tmp;
|
||||
NDI_audio_frame.channel_stride_in_bytes = frame->data_len / frame->ch_count;
|
||||
NDI_audio_frame.no_samples = frame->data_len / frame->ch_count / sizeof(float);
|
||||
int2float((char *) tmp, frame->data, frame->data_len);
|
||||
|
||||
NDIlib_send_send_audio_v2(s->pNDI_send, &NDI_audio_frame);
|
||||
free(tmp);
|
||||
switch (frame->bps * 8) {
|
||||
#define HANDLE_CASE(b) case b: NDI_SEND_AUDIO(frame, b); break;
|
||||
HANDLE_CASE(16)
|
||||
HANDLE_CASE(32)
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static int display_ndi_reconfigure_audio(void *state, int quant_samples, int channels,
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "config_unix.h"
|
||||
#include "config_win32.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
|
||||
@@ -50,6 +51,7 @@
|
||||
#include "video_display.h"
|
||||
#include "video_display/pipe.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::list;
|
||||
using std::mutex;
|
||||
using std::lock_guard;
|
||||
@@ -57,9 +59,10 @@ using std::lock_guard;
|
||||
struct state_pipe {
|
||||
struct module *parent;
|
||||
frame_recv_delegate *delegate;
|
||||
struct video_desc desc;
|
||||
list<struct audio_frame *> audio_frames;
|
||||
mutex audio_lock;
|
||||
codec_t decode_to;
|
||||
struct video_desc desc{};
|
||||
list<struct audio_frame *> audio_frames{};
|
||||
mutex audio_lock{};
|
||||
};
|
||||
|
||||
static struct display *display_pipe_fork(void *state)
|
||||
@@ -74,6 +77,11 @@ static struct display *display_pipe_fork(void *state)
|
||||
if (rc == 0) return out; else return NULL;
|
||||
}
|
||||
|
||||
static void display_pipe_usage() {
|
||||
cout << "Usage:\n"
|
||||
"\t-d pipe:<ptr>[:codec=<c>]\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @note
|
||||
* Audio is always received regardless if enabled in flags.
|
||||
@@ -81,16 +89,34 @@ static struct display *display_pipe_fork(void *state)
|
||||
static void *display_pipe_init(struct module *parent, const char *fmt, unsigned int flags)
|
||||
{
|
||||
UNUSED(flags);
|
||||
codec_t decode_to = UYVY;
|
||||
frame_recv_delegate *delegate;
|
||||
|
||||
if (!fmt || strlen(fmt) == 0 || strcmp(fmt, "help") == 0) {
|
||||
fprintf(stderr, "Pipe dummy video driver. For internal usage - please do not use.\n");
|
||||
if (fmt != nullptr && strcmp(fmt, "help") == 0) {
|
||||
display_pipe_usage();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sscanf(fmt, "%p", &delegate);
|
||||
if (strchr(fmt, ':') != nullptr) {
|
||||
fmt = strchr(fmt, ':') + 1;
|
||||
if (strstr(fmt, "codec=") == fmt) {
|
||||
const char *codec_name = fmt + strlen("codec=");
|
||||
decode_to = get_codec_from_name(codec_name);
|
||||
if (decode_to == VIDEO_CODEC_NONE) {
|
||||
LOG(LOG_LEVEL_ERROR) << "Wrong codec name: " << codec_name << "\n";
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
display_pipe_usage();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
struct state_pipe *s = new state_pipe{parent, delegate, video_desc(), {}, {}};
|
||||
auto *s = new state_pipe{parent, delegate, decode_to};
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -180,20 +206,17 @@ static void display_pipe_run(void *state)
|
||||
|
||||
static int display_pipe_get_property(void *state, int property, void *val, size_t *len)
|
||||
{
|
||||
UNUSED(state);
|
||||
codec_t codecs[] = {UYVY};
|
||||
auto *s = static_cast<struct state_pipe *>(state);
|
||||
enum interlacing_t supported_il_modes[] = {PROGRESSIVE, INTERLACED_MERGED, SEGMENTED_FRAME};
|
||||
int rgb_shift[] = {0, 8, 16};
|
||||
|
||||
switch (property) {
|
||||
case DISPLAY_PROPERTY_CODECS:
|
||||
if(sizeof(codecs) <= *len) {
|
||||
memcpy(val, codecs, sizeof(codecs));
|
||||
} else {
|
||||
if(sizeof(codec_t) > *len) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*len = sizeof(codecs);
|
||||
memcpy(val, &s->decode_to, sizeof(s->decode_to));
|
||||
*len = sizeof s->decode_to;
|
||||
break;
|
||||
case DISPLAY_PROPERTY_RGB_SHIFT:
|
||||
if(sizeof(rgb_shift) > *len) {
|
||||
|
||||
@@ -744,6 +744,16 @@ static void display_sdl2_new_message(struct module *mod)
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
static void display_sdl2_put_audio_frame([[maybe_unused]] void *state, [[maybe_unused]] struct audio_frame *frame)
|
||||
{
|
||||
}
|
||||
|
||||
static int display_sdl2_reconfigure_audio([[maybe_unused]] void *state, [[maybe_unused]] int quant_samples,
|
||||
[[maybe_unused]] int channels, [[maybe_unused]] int sample_rate)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static const struct video_display_info display_sdl2_info = {
|
||||
[](struct device_info **available_cards, int *count, void (**deleter)(void *)) {
|
||||
UNUSED(deleter);
|
||||
@@ -760,8 +770,8 @@ static const struct video_display_info display_sdl2_info = {
|
||||
display_sdl2_putf,
|
||||
display_sdl2_reconfigure,
|
||||
display_sdl2_get_property,
|
||||
NULL,
|
||||
NULL,
|
||||
display_sdl2_put_audio_frame,
|
||||
display_sdl2_reconfigure_audio,
|
||||
DISPLAY_NEEDS_MAINLOOP,
|
||||
};
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ h264_sdp_video_rxtx::h264_sdp_video_rxtx(std::map<std::string, param_u> const &p
|
||||
}
|
||||
|
||||
LOG(LOG_LEVEL_WARNING) << "Warning: SDP support is experimental only. Things may be broken - feel free to report them but the support may be limited.\n";
|
||||
m_sdp = new_sdp(params.at("force_ip_version").i, m_requested_receiver.c_str());
|
||||
m_sdp = new_sdp(rtp_is_ipv6(m_network_devices[0]) ? 6 : 4 , m_requested_receiver.c_str());
|
||||
m_saved_addr = m_requested_receiver;
|
||||
if (m_sdp == nullptr) {
|
||||
throw string("[SDP] SDP creation failed\n");
|
||||
@@ -162,6 +162,12 @@ void h264_sdp_video_rxtx::sdp_add_video(codec_t codec)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @note
|
||||
* This function sets compression just after first frame is received. The delayed initialization is to allow devices
|
||||
* producing H.264/JPEG natively (eg. v4l2) to be passed untouched to transport. Fallback H.264 is applied when uncompressed
|
||||
* stream is detected.
|
||||
*/
|
||||
void h264_sdp_video_rxtx::send_frame(shared_ptr<video_frame> tx_frame)
|
||||
{
|
||||
if (!is_codec_opaque(tx_frame->color_spec)) {
|
||||
|
||||
@@ -272,7 +272,7 @@ void rtp_video_rxtx::display_buf_increase_warning(int size)
|
||||
log_msg(LOG_LEVEL_VERBOSE, "\n***\n"
|
||||
"Unable to set buffer size to %d B.\n"
|
||||
#if defined WIN32
|
||||
"See https://github.com/CESNET/UltraGrid/wiki/Extending-Network-Buffers-%28Windows%29 for details.\n",
|
||||
"See https://github.com/CESNET/UltraGrid/wiki/Extending-Network-Buffers-%%28Windows%%29 for details.\n",
|
||||
#else
|
||||
"Please set net.core.rmem_max value to %d or greater. (see also\n"
|
||||
"https://github.com/CESNET/UltraGrid/wiki/OS-Setup-UltraGrid)\n"
|
||||
|
||||
@@ -144,7 +144,7 @@ static bool run_unit_tests()
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct init_data *init = nullptr;
|
||||
if ((init = common_preinit(argc, argv)) == nullptr) {
|
||||
if ((init = common_preinit(argc, argv, nullptr)) == nullptr) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user