mirror of
				https://github.com/DigitalDevices/pvr.octonet.git
				synced 2025-03-01 10:53:09 +00:00 
			
		
		
		
	Compare commits
	
		
			5 Commits
		
	
	
		
			4.0.0-1-Ma
			...
			Krypton
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d4077a142c | ||
| 
						 | 
					6ee28476fa | ||
| 
						 | 
					de0a0f9a81 | ||
| 
						 | 
					1b0c31654a | ||
| 
						 | 
					f260cb07e9 | 
@@ -1,88 +0,0 @@
 | 
				
			|||||||
---
 | 
					 | 
				
			||||||
# BasedOnStyle:  LLVM
 | 
					 | 
				
			||||||
AccessModifierOffset: -2
 | 
					 | 
				
			||||||
AlignAfterOpenBracket: Align
 | 
					 | 
				
			||||||
AlignConsecutiveAssignments: false
 | 
					 | 
				
			||||||
AlignConsecutiveDeclarations: false
 | 
					 | 
				
			||||||
AlignEscapedNewlines: DontAlign
 | 
					 | 
				
			||||||
AlignOperands:   true
 | 
					 | 
				
			||||||
AlignTrailingComments: false
 | 
					 | 
				
			||||||
AllowAllParametersOfDeclarationOnNextLine: true
 | 
					 | 
				
			||||||
AllowShortBlocksOnASingleLine: false
 | 
					 | 
				
			||||||
AllowShortCaseLabelsOnASingleLine: false
 | 
					 | 
				
			||||||
AllowShortFunctionsOnASingleLine: InlineOnly
 | 
					 | 
				
			||||||
AllowShortIfStatementsOnASingleLine: false
 | 
					 | 
				
			||||||
AllowShortLoopsOnASingleLine: false
 | 
					 | 
				
			||||||
AlwaysBreakAfterDefinitionReturnType: None
 | 
					 | 
				
			||||||
AlwaysBreakAfterReturnType: None
 | 
					 | 
				
			||||||
AlwaysBreakBeforeMultilineStrings: false
 | 
					 | 
				
			||||||
AlwaysBreakTemplateDeclarations: true
 | 
					 | 
				
			||||||
BinPackArguments: true
 | 
					 | 
				
			||||||
BinPackParameters: false
 | 
					 | 
				
			||||||
BreakBeforeBinaryOperators: None
 | 
					 | 
				
			||||||
BreakBeforeBraces: Allman
 | 
					 | 
				
			||||||
BreakBeforeTernaryOperators: true
 | 
					 | 
				
			||||||
BreakConstructorInitializersBeforeComma: false
 | 
					 | 
				
			||||||
BreakConstructorInitializers: BeforeColon
 | 
					 | 
				
			||||||
BreakAfterJavaFieldAnnotations: false
 | 
					 | 
				
			||||||
BreakStringLiterals: true
 | 
					 | 
				
			||||||
ColumnLimit:     100
 | 
					 | 
				
			||||||
CommentPragmas:  '^ IWYU pragma:'
 | 
					 | 
				
			||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
 | 
					 | 
				
			||||||
ConstructorInitializerIndentWidth: 2
 | 
					 | 
				
			||||||
ContinuationIndentWidth: 4
 | 
					 | 
				
			||||||
Cpp11BracedListStyle: true
 | 
					 | 
				
			||||||
DerivePointerAlignment: false
 | 
					 | 
				
			||||||
DisableFormat:   false
 | 
					 | 
				
			||||||
ExperimentalAutoDetectBinPacking: false
 | 
					 | 
				
			||||||
ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
 | 
					 | 
				
			||||||
IncludeBlocks: Regroup
 | 
					 | 
				
			||||||
IncludeCategories:
 | 
					 | 
				
			||||||
  - Regex:           '^<[a-z0-9_]+>$'
 | 
					 | 
				
			||||||
    Priority:        3
 | 
					 | 
				
			||||||
  - Regex:           '^<(assert|complex|ctype|errno|fenv|float|inttypes|iso646|limits|locale|math|setjmp|signal|stdalign|stdarg|stdatomic|stdbool|stddef|stdint|stdio|stdlib|stdnoreturn|string|tgmath|threads|time|uchar|wchar|wctype)\.h>$'
 | 
					 | 
				
			||||||
    Priority:        3
 | 
					 | 
				
			||||||
  - Regex:           '^<'
 | 
					 | 
				
			||||||
    Priority:        3
 | 
					 | 
				
			||||||
  - Regex:           '^["<](kodi|p8-platform)\/.*\.h[">]$'
 | 
					 | 
				
			||||||
    Priority:        2
 | 
					 | 
				
			||||||
  - Regex:           '.*'
 | 
					 | 
				
			||||||
    Priority:        1
 | 
					 | 
				
			||||||
IncludeIsMainRegex: '$'
 | 
					 | 
				
			||||||
IndentCaseLabels: true
 | 
					 | 
				
			||||||
IndentWidth:     2
 | 
					 | 
				
			||||||
IndentWrappedFunctionNames: false
 | 
					 | 
				
			||||||
JavaScriptQuotes: Leave
 | 
					 | 
				
			||||||
JavaScriptWrapImports: true
 | 
					 | 
				
			||||||
KeepEmptyLinesAtTheStartOfBlocks: true
 | 
					 | 
				
			||||||
MacroBlockBegin: ''
 | 
					 | 
				
			||||||
MacroBlockEnd:   ''
 | 
					 | 
				
			||||||
MaxEmptyLinesToKeep: 2
 | 
					 | 
				
			||||||
NamespaceIndentation: None
 | 
					 | 
				
			||||||
ObjCBlockIndentWidth: 2
 | 
					 | 
				
			||||||
ObjCSpaceAfterProperty: false
 | 
					 | 
				
			||||||
ObjCSpaceBeforeProtocolList: true
 | 
					 | 
				
			||||||
PenaltyBreakBeforeFirstCallParameter: 19
 | 
					 | 
				
			||||||
PenaltyBreakComment: 300
 | 
					 | 
				
			||||||
PenaltyBreakFirstLessLess: 120
 | 
					 | 
				
			||||||
PenaltyBreakString: 1000
 | 
					 | 
				
			||||||
PenaltyExcessCharacter: 1000000
 | 
					 | 
				
			||||||
PenaltyReturnTypeOnItsOwnLine: 60000
 | 
					 | 
				
			||||||
PointerAlignment: Left
 | 
					 | 
				
			||||||
ReflowComments:  false
 | 
					 | 
				
			||||||
SortIncludes:    true
 | 
					 | 
				
			||||||
SpaceAfterCStyleCast: false
 | 
					 | 
				
			||||||
SpaceAfterTemplateKeyword: false
 | 
					 | 
				
			||||||
SpaceBeforeAssignmentOperators: true
 | 
					 | 
				
			||||||
SpaceBeforeParens: ControlStatements
 | 
					 | 
				
			||||||
SpaceInEmptyParentheses: false
 | 
					 | 
				
			||||||
SpacesBeforeTrailingComments: 1
 | 
					 | 
				
			||||||
SpacesInAngles:  false
 | 
					 | 
				
			||||||
SpacesInContainerLiterals: true
 | 
					 | 
				
			||||||
SpacesInCStyleCastParentheses: false
 | 
					 | 
				
			||||||
SpacesInParentheses: false
 | 
					 | 
				
			||||||
SpacesInSquareBrackets: false
 | 
					 | 
				
			||||||
Standard:        Cpp11
 | 
					 | 
				
			||||||
TabWidth:        8
 | 
					 | 
				
			||||||
UseTab:          Never
 | 
					 | 
				
			||||||
...
 | 
					 | 
				
			||||||
							
								
								
									
										51
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										51
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,50 +1 @@
 | 
				
			|||||||
# build artifacts
 | 
					/build
 | 
				
			||||||
build/
 | 
					 | 
				
			||||||
pvr.*/addon.xml
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Debian build files
 | 
					 | 
				
			||||||
debian/changelog
 | 
					 | 
				
			||||||
debian/files
 | 
					 | 
				
			||||||
debian/*.log
 | 
					 | 
				
			||||||
debian/*.substvars
 | 
					 | 
				
			||||||
debian/.debhelper/
 | 
					 | 
				
			||||||
debian/tmp/
 | 
					 | 
				
			||||||
debian/kodi-pvr-*/
 | 
					 | 
				
			||||||
obj-x86_64-linux-gnu/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# commonly used editors
 | 
					 | 
				
			||||||
# vim
 | 
					 | 
				
			||||||
*.swp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Eclipse
 | 
					 | 
				
			||||||
*.project
 | 
					 | 
				
			||||||
*.cproject
 | 
					 | 
				
			||||||
.classpath
 | 
					 | 
				
			||||||
*.sublime-*
 | 
					 | 
				
			||||||
.settings/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# KDevelop 4
 | 
					 | 
				
			||||||
*.kdev4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# gedit
 | 
					 | 
				
			||||||
*~
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# CLion
 | 
					 | 
				
			||||||
/.idea
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# clion
 | 
					 | 
				
			||||||
.idea/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# to prevent add after a "git format-patch VALUE" and "git add ." call
 | 
					 | 
				
			||||||
/*.patch
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Visual Studio Code
 | 
					 | 
				
			||||||
.vscode
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# to prevent add if project code opened by Visual Studio over CMake file
 | 
					 | 
				
			||||||
.vs/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# General MacOS
 | 
					 | 
				
			||||||
.DS_Store
 | 
					 | 
				
			||||||
.AppleDouble
 | 
					 | 
				
			||||||
.LSOverride
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										55
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -1,54 +1,45 @@
 | 
				
			|||||||
language: cpp
 | 
					language: cpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Define the builds to get up to date versions of cmake and gcc
 | 
					# Define the build matrix
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Travis defaults to building on Ubuntu Precise when building on
 | 
				
			||||||
 | 
					# Linux. We need Trusty in order to get up to date versions of
 | 
				
			||||||
 | 
					# cmake and g++.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
env:
 | 
					 | 
				
			||||||
  global:
 | 
					 | 
				
			||||||
    - app_id=pvr.octonet
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
matrix:
 | 
					matrix:
 | 
				
			||||||
  include:
 | 
					  include:
 | 
				
			||||||
    - os: linux
 | 
					    - os: linux
 | 
				
			||||||
      dist: bionic
 | 
					      dist: trusty
 | 
				
			||||||
      sudo: required
 | 
					      sudo: required
 | 
				
			||||||
      compiler: gcc
 | 
					      compiler: gcc
 | 
				
			||||||
    - os: linux
 | 
					    - os: linux
 | 
				
			||||||
      dist: bionic
 | 
					      dist: trusty
 | 
				
			||||||
      sudo: required
 | 
					      sudo: required
 | 
				
			||||||
      compiler: clang
 | 
					      compiler: clang
 | 
				
			||||||
    - os: linux
 | 
					 | 
				
			||||||
      dist: bionic
 | 
					 | 
				
			||||||
      sudo: required
 | 
					 | 
				
			||||||
      compiler: gcc
 | 
					 | 
				
			||||||
      env: DEBIAN_BUILD=true
 | 
					 | 
				
			||||||
    - os: linux
 | 
					 | 
				
			||||||
      dist: focal
 | 
					 | 
				
			||||||
      sudo: required
 | 
					 | 
				
			||||||
      compiler: gcc
 | 
					 | 
				
			||||||
      env: DEBIAN_BUILD=true
 | 
					 | 
				
			||||||
    - os: osx
 | 
					    - os: osx
 | 
				
			||||||
      osx_image: xcode10.2
 | 
					      osx_image: xcode7.3
 | 
				
			||||||
 | 
					    - os: osx
 | 
				
			||||||
 | 
					      osx_image: xcode6.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Some of the OS X images don't have cmake, contrary to what people
 | 
				
			||||||
 | 
					# on the Internet say
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
before_install:
 | 
					before_install:
 | 
				
			||||||
  - if [[ $DEBIAN_BUILD == true ]]; then sudo add-apt-repository -y ppa:team-xbmc/xbmc-nightly; fi
 | 
					  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then which cmake || brew update        ; fi
 | 
				
			||||||
  - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get update; fi
 | 
					  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then which cmake || brew install cmake ; fi
 | 
				
			||||||
  - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get install fakeroot; fi
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# The addon source is automatically checked out in $TRAVIS_BUILD_DIR,
 | 
					# The addon source is automatically checked out in $TRAVIS_BUILD_DIR,
 | 
				
			||||||
# we'll put the Kodi source on the same level
 | 
					# we'll put the Kodi source on the same level
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
before_script:
 | 
					before_script:
 | 
				
			||||||
  - if [[ $DEBIAN_BUILD != true ]]; then cd $TRAVIS_BUILD_DIR/..; fi
 | 
					  - cd $TRAVIS_BUILD_DIR/..
 | 
				
			||||||
  - if [[ $DEBIAN_BUILD != true ]]; then git clone --branch master --depth=1 https://github.com/xbmc/xbmc.git; fi
 | 
					  - git clone --depth=1 https://github.com/xbmc/xbmc.git -b Krypton
 | 
				
			||||||
  - if [[ $DEBIAN_BUILD != true ]]; then cd ${app_id} && mkdir build && cd build; fi
 | 
					  - mkdir -p xbmc/project/cmake/addons/addons/pvr.octonet
 | 
				
			||||||
  - if [[ $DEBIAN_BUILD != true ]]; then mkdir -p definition/${app_id}; fi
 | 
					  - echo "pvr.octonet https://github.com/DigitalDevices/pvr.octonet master" > xbmc/project/cmake/addons/addons/pvr.octonet/pvr.octonet.txt
 | 
				
			||||||
  - if [[ $DEBIAN_BUILD != true ]]; then echo ${app_id} $TRAVIS_BUILD_DIR $TRAVIS_COMMIT > definition/${app_id}/${app_id}.txt; fi
 | 
					  - cd $TRAVIS_BUILD_DIR && mkdir build && cd build
 | 
				
			||||||
  - if [[ $DEBIAN_BUILD != true ]]; then cmake -DADDONS_TO_BUILD=${app_id} -DADDON_SRC_PREFIX=$TRAVIS_BUILD_DIR/.. -DADDONS_DEFINITION_DIR=$TRAVIS_BUILD_DIR/build/definition -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/../xbmc/addons -DPACKAGE_ZIP=1 $TRAVIS_BUILD_DIR/../xbmc/cmake/addons; fi
 | 
					  - cmake -DADDONS_TO_BUILD=pvr.octonet -DADDON_SRC_PREFIX=$TRAVIS_BUILD_DIR/.. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/../xbmc/addons -DPACKAGE_ZIP=1 $TRAVIS_BUILD_DIR/../xbmc/project/cmake/addons
 | 
				
			||||||
  - if [[ $DEBIAN_BUILD == true ]]; then wget https://raw.githubusercontent.com/xbmc/xbmc/master/xbmc/addons/kodi-dev-kit/tools/debian-addon-package-test.sh && chmod +x ./debian-addon-package-test.sh; fi
 | 
					 | 
				
			||||||
  - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get build-dep $TRAVIS_BUILD_DIR; fi
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
script: 
 | 
					script: make
 | 
				
			||||||
  - if [[ $DEBIAN_BUILD != true ]]; then make; fi
 | 
					 | 
				
			||||||
  - if [[ $DEBIAN_BUILD == true ]]; then ./debian-addon-package-test.sh $TRAVIS_BUILD_DIR; fi
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,37 +1,35 @@
 | 
				
			|||||||
cmake_minimum_required(VERSION 3.5)
 | 
					 | 
				
			||||||
project(pvr.octonet)
 | 
					project(pvr.octonet)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cmake_minimum_required(VERSION 2.6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
 | 
					list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
 | 
				
			||||||
 | 
					enable_language(CXX)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
find_package(Kodi REQUIRED)
 | 
					find_package(Kodi REQUIRED)
 | 
				
			||||||
 | 
					find_package(kodiplatform REQUIRED)
 | 
				
			||||||
 | 
					find_package(p8-platform REQUIRED)
 | 
				
			||||||
find_package(JsonCpp REQUIRED)
 | 
					find_package(JsonCpp REQUIRED)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include_directories(${KODI_INCLUDE_DIR}/.. # Hack way with "/..", need bigger Kodi cmake rework to match right include ways
 | 
					include_directories(
 | 
				
			||||||
                    ${JSONCPP_INCLUDE_DIRS})
 | 
						${kodiplatform_INCLUDE_DIRS}
 | 
				
			||||||
 | 
						${p8-platform_INCLUDE_DIRS}
 | 
				
			||||||
 | 
						${KODI_INCLUDE_DIR}
 | 
				
			||||||
 | 
						${JSONCPP_INCLUDE_DIRS})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(DEPLIBS ${JSONCPP_LIBRARIES})
 | 
					set(DEPLIBS
 | 
				
			||||||
 | 
						${p8-platform_LIBRARIES}
 | 
				
			||||||
 | 
						${JSONCPP_LIBRARIES})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(OCTONET_SOURCES src/addon.cpp
 | 
					set(OCTONET_SOURCES
 | 
				
			||||||
                    src/OctonetData.cpp
 | 
						src/OctonetData.cpp
 | 
				
			||||||
                    src/Socket.cpp
 | 
						src/client.cpp
 | 
				
			||||||
                    src/rtsp_client.cpp)
 | 
						src/Socket.cpp
 | 
				
			||||||
 | 
						src/rtsp_client.cpp)
 | 
				
			||||||
set(OCTONET_HEADERS src/addon.h
 | 
					 | 
				
			||||||
                    src/OctonetData.h
 | 
					 | 
				
			||||||
                    src/Socket.h
 | 
					 | 
				
			||||||
                    src/rtsp_client.hpp)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
addon_version(pvr.octonet OCTONET)
 | 
					 | 
				
			||||||
add_definitions(-DOCTONET_VERSION=${OCTONET_VERSION})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
build_addon(pvr.octonet OCTONET DEPLIBS)
 | 
					build_addon(pvr.octonet OCTONET DEPLIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(WIN32)
 | 
					if(WIN32)
 | 
				
			||||||
  if(NOT CMAKE_SYSTEM_NAME STREQUAL WindowsStore)
 | 
						target_link_libraries(pvr.octonet wsock32 ws2_32)
 | 
				
			||||||
    target_link_libraries(pvr.octonet wsock32 ws2_32)
 | 
					 | 
				
			||||||
  else()
 | 
					 | 
				
			||||||
    target_link_libraries(pvr.octonet ws2_32)
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include(CPack)
 | 
					include(CPack)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								Jenkinsfile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								Jenkinsfile
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
				
			|||||||
buildPlugin(version: "Matrix")
 | 
					 | 
				
			||||||
							
								
								
									
										264
									
								
								LICENSE.md
									
									
									
									
									
								
							
							
						
						
									
										264
									
								
								LICENSE.md
									
									
									
									
									
								
							@@ -1,264 +0,0 @@
 | 
				
			|||||||
The GNU General Public License, Version 2, June 1991 (GPLv2)
 | 
					 | 
				
			||||||
============================================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
> Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 | 
					 | 
				
			||||||
> 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Everyone is permitted to copy and distribute verbatim copies of this license
 | 
					 | 
				
			||||||
document, but changing it is not allowed.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Preamble
 | 
					 | 
				
			||||||
--------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The licenses for most software are designed to take away your freedom to share
 | 
					 | 
				
			||||||
and change it. By contrast, the GNU General Public License is intended to
 | 
					 | 
				
			||||||
guarantee your freedom to share and change free software--to make sure the
 | 
					 | 
				
			||||||
software is free for all its users. This General Public License applies to most
 | 
					 | 
				
			||||||
of the Free Software Foundation's software and to any other program whose
 | 
					 | 
				
			||||||
authors commit to using it. (Some other Free Software Foundation software is
 | 
					 | 
				
			||||||
covered by the GNU Lesser General Public License instead.) You can apply it to
 | 
					 | 
				
			||||||
your programs, too.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
When we speak of free software, we are referring to freedom, not price. Our
 | 
					 | 
				
			||||||
General Public Licenses are designed to make sure that you have the freedom to
 | 
					 | 
				
			||||||
distribute copies of free software (and charge for this service if you wish),
 | 
					 | 
				
			||||||
that you receive source code or can get it if you want it, that you can change
 | 
					 | 
				
			||||||
the software or use pieces of it in new free programs; and that you know you can
 | 
					 | 
				
			||||||
do these things.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
To protect your rights, we need to make restrictions that forbid anyone to deny
 | 
					 | 
				
			||||||
you these rights or to ask you to surrender the rights. These restrictions
 | 
					 | 
				
			||||||
translate to certain responsibilities for you if you distribute copies of the
 | 
					 | 
				
			||||||
software, or if you modify it.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
For example, if you distribute copies of such a program, whether gratis or for a
 | 
					 | 
				
			||||||
fee, you must give the recipients all the rights that you have. You must make
 | 
					 | 
				
			||||||
sure that they, too, receive or can get the source code. And you must show them
 | 
					 | 
				
			||||||
these terms so they know their rights.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
We protect your rights with two steps: (1) copyright the software, and (2) offer
 | 
					 | 
				
			||||||
you this license which gives you legal permission to copy, distribute and/or
 | 
					 | 
				
			||||||
modify the software.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Also, for each author's protection and ours, we want to make certain that
 | 
					 | 
				
			||||||
everyone understands that there is no warranty for this free software. If the
 | 
					 | 
				
			||||||
software is modified by someone else and passed on, we want its recipients to
 | 
					 | 
				
			||||||
know that what they have is not the original, so that any problems introduced by
 | 
					 | 
				
			||||||
others will not reflect on the original authors' reputations.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Finally, any free program is threatened constantly by software patents. We wish
 | 
					 | 
				
			||||||
to avoid the danger that redistributors of a free program will individually
 | 
					 | 
				
			||||||
obtain patent licenses, in effect making the program proprietary. To prevent
 | 
					 | 
				
			||||||
this, we have made it clear that any patent must be licensed for everyone's free
 | 
					 | 
				
			||||||
use or not licensed at all.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The precise terms and conditions for copying, distribution and modification
 | 
					 | 
				
			||||||
follow.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Terms And Conditions For Copying, Distribution And Modification
 | 
					 | 
				
			||||||
---------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**0.** This License applies to any program or other work which contains a notice
 | 
					 | 
				
			||||||
placed by the copyright holder saying it may be distributed under the terms of
 | 
					 | 
				
			||||||
this General Public License. The "Program", below, refers to any such program or
 | 
					 | 
				
			||||||
work, and a "work based on the Program" means either the Program or any
 | 
					 | 
				
			||||||
derivative work under copyright law: that is to say, a work containing the
 | 
					 | 
				
			||||||
Program or a portion of it, either verbatim or with modifications and/or
 | 
					 | 
				
			||||||
translated into another language. (Hereinafter, translation is included without
 | 
					 | 
				
			||||||
limitation in the term "modification".) Each licensee is addressed as "you".
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Activities other than copying, distribution and modification are not covered by
 | 
					 | 
				
			||||||
this License; they are outside its scope. The act of running the Program is not
 | 
					 | 
				
			||||||
restricted, and the output from the Program is covered only if its contents
 | 
					 | 
				
			||||||
constitute a work based on the Program (independent of having been made by
 | 
					 | 
				
			||||||
running the Program). Whether that is true depends on what the Program does.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**1.** You may copy and distribute verbatim copies of the Program's source code
 | 
					 | 
				
			||||||
as you receive it, in any medium, provided that you conspicuously and
 | 
					 | 
				
			||||||
appropriately publish on each copy an appropriate copyright notice and
 | 
					 | 
				
			||||||
disclaimer of warranty; keep intact all the notices that refer to this License
 | 
					 | 
				
			||||||
and to the absence of any warranty; and give any other recipients of the Program
 | 
					 | 
				
			||||||
a copy of this License along with the Program.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
You may charge a fee for the physical act of transferring a copy, and you may at
 | 
					 | 
				
			||||||
your option offer warranty protection in exchange for a fee.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**2.** You may modify your copy or copies of the Program or any portion of it,
 | 
					 | 
				
			||||||
thus forming a work based on the Program, and copy and distribute such
 | 
					 | 
				
			||||||
modifications or work under the terms of Section 1 above, provided that you also
 | 
					 | 
				
			||||||
meet all of these conditions:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
*   **a)** You must cause the modified files to carry prominent notices stating
 | 
					 | 
				
			||||||
    that you changed the files and the date of any change.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
*   **b)** You must cause any work that you distribute or publish, that in whole
 | 
					 | 
				
			||||||
    or in part contains or is derived from the Program or any part thereof, to
 | 
					 | 
				
			||||||
    be licensed as a whole at no charge to all third parties under the terms of
 | 
					 | 
				
			||||||
    this License.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
*   **c)** If the modified program normally reads commands interactively when
 | 
					 | 
				
			||||||
    run, you must cause it, when started running for such interactive use in the
 | 
					 | 
				
			||||||
    most ordinary way, to print or display an announcement including an
 | 
					 | 
				
			||||||
    appropriate copyright notice and a notice that there is no warranty (or
 | 
					 | 
				
			||||||
    else, saying that you provide a warranty) and that users may redistribute
 | 
					 | 
				
			||||||
    the program under these conditions, and telling the user how to view a copy
 | 
					 | 
				
			||||||
    of this License. (Exception: if the Program itself is interactive but does
 | 
					 | 
				
			||||||
    not normally print such an announcement, your work based on the Program is
 | 
					 | 
				
			||||||
    not required to print an announcement.)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
These requirements apply to the modified work as a whole. If identifiable
 | 
					 | 
				
			||||||
sections of that work are not derived from the Program, and can be reasonably
 | 
					 | 
				
			||||||
considered independent and separate works in themselves, then this License, and
 | 
					 | 
				
			||||||
its terms, do not apply to those sections when you distribute them as separate
 | 
					 | 
				
			||||||
works. But when you distribute the same sections as part of a whole which is a
 | 
					 | 
				
			||||||
work based on the Program, the distribution of the whole must be on the terms of
 | 
					 | 
				
			||||||
this License, whose permissions for other licensees extend to the entire whole,
 | 
					 | 
				
			||||||
and thus to each and every part regardless of who wrote it.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Thus, it is not the intent of this section to claim rights or contest your
 | 
					 | 
				
			||||||
rights to work written entirely by you; rather, the intent is to exercise the
 | 
					 | 
				
			||||||
right to control the distribution of derivative or collective works based on the
 | 
					 | 
				
			||||||
Program.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
In addition, mere aggregation of another work not based on the Program with the
 | 
					 | 
				
			||||||
Program (or with a work based on the Program) on a volume of a storage or
 | 
					 | 
				
			||||||
distribution medium does not bring the other work under the scope of this
 | 
					 | 
				
			||||||
License.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**3.** You may copy and distribute the Program (or a work based on it, under
 | 
					 | 
				
			||||||
Section 2) in object code or executable form under the terms of Sections 1 and 2
 | 
					 | 
				
			||||||
above provided that you also do one of the following:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
*   **a)** Accompany it with the complete corresponding machine-readable source
 | 
					 | 
				
			||||||
    code, which must be distributed under the terms of Sections 1 and 2 above on
 | 
					 | 
				
			||||||
    a medium customarily used for software interchange; or,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
*   **b)** Accompany it with a written offer, valid for at least three years, to
 | 
					 | 
				
			||||||
    give any third party, for a charge no more than your cost of physically
 | 
					 | 
				
			||||||
    performing source distribution, a complete machine-readable copy of the
 | 
					 | 
				
			||||||
    corresponding source code, to be distributed under the terms of Sections 1
 | 
					 | 
				
			||||||
    and 2 above on a medium customarily used for software interchange; or,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
*   **c)** Accompany it with the information you received as to the offer to
 | 
					 | 
				
			||||||
    distribute corresponding source code. (This alternative is allowed only for
 | 
					 | 
				
			||||||
    noncommercial distribution and only if you received the program in object
 | 
					 | 
				
			||||||
    code or executable form with such an offer, in accord with Subsection b
 | 
					 | 
				
			||||||
    above.)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The source code for a work means the preferred form of the work for making
 | 
					 | 
				
			||||||
modifications to it. For an executable work, complete source code means all the
 | 
					 | 
				
			||||||
source code for all modules it contains, plus any associated interface
 | 
					 | 
				
			||||||
definition files, plus the scripts used to control compilation and installation
 | 
					 | 
				
			||||||
of the executable. However, as a special exception, the source code distributed
 | 
					 | 
				
			||||||
need not include anything that is normally distributed (in either source or
 | 
					 | 
				
			||||||
binary form) with the major components (compiler, kernel, and so on) of the
 | 
					 | 
				
			||||||
operating system on which the executable runs, unless that component itself
 | 
					 | 
				
			||||||
accompanies the executable.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
If distribution of executable or object code is made by offering access to copy
 | 
					 | 
				
			||||||
from a designated place, then offering equivalent access to copy the source code
 | 
					 | 
				
			||||||
from the same place counts as distribution of the source code, even though third
 | 
					 | 
				
			||||||
parties are not compelled to copy the source along with the object code.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**4.** You may not copy, modify, sublicense, or distribute the Program except as
 | 
					 | 
				
			||||||
expressly provided under this License. Any attempt otherwise to copy, modify,
 | 
					 | 
				
			||||||
sublicense or distribute the Program is void, and will automatically terminate
 | 
					 | 
				
			||||||
your rights under this License. However, parties who have received copies, or
 | 
					 | 
				
			||||||
rights, from you under this License will not have their licenses terminated so
 | 
					 | 
				
			||||||
long as such parties remain in full compliance.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**5.** You are not required to accept this License, since you have not signed
 | 
					 | 
				
			||||||
it. However, nothing else grants you permission to modify or distribute the
 | 
					 | 
				
			||||||
Program or its derivative works. These actions are prohibited by law if you do
 | 
					 | 
				
			||||||
not accept this License. Therefore, by modifying or distributing the Program (or
 | 
					 | 
				
			||||||
any work based on the Program), you indicate your acceptance of this License to
 | 
					 | 
				
			||||||
do so, and all its terms and conditions for copying, distributing or modifying
 | 
					 | 
				
			||||||
the Program or works based on it.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**6.** Each time you redistribute the Program (or any work based on the
 | 
					 | 
				
			||||||
Program), the recipient automatically receives a license from the original
 | 
					 | 
				
			||||||
licensor to copy, distribute or modify the Program subject to these terms and
 | 
					 | 
				
			||||||
conditions. You may not impose any further restrictions on the recipients'
 | 
					 | 
				
			||||||
exercise of the rights granted herein. You are not responsible for enforcing
 | 
					 | 
				
			||||||
compliance by third parties to this License.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**7.** If, as a consequence of a court judgment or allegation of patent
 | 
					 | 
				
			||||||
infringement or for any other reason (not limited to patent issues), conditions
 | 
					 | 
				
			||||||
are imposed on you (whether by court order, agreement or otherwise) that
 | 
					 | 
				
			||||||
contradict the conditions of this License, they do not excuse you from the
 | 
					 | 
				
			||||||
conditions of this License. If you cannot distribute so as to satisfy
 | 
					 | 
				
			||||||
simultaneously your obligations under this License and any other pertinent
 | 
					 | 
				
			||||||
obligations, then as a consequence you may not distribute the Program at all.
 | 
					 | 
				
			||||||
For example, if a patent license would not permit royalty-free redistribution of
 | 
					 | 
				
			||||||
the Program by all those who receive copies directly or indirectly through you,
 | 
					 | 
				
			||||||
then the only way you could satisfy both it and this License would be to refrain
 | 
					 | 
				
			||||||
entirely from distribution of the Program.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
If any portion of this section is held invalid or unenforceable under any
 | 
					 | 
				
			||||||
particular circumstance, the balance of the section is intended to apply and the
 | 
					 | 
				
			||||||
section as a whole is intended to apply in other circumstances.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
It is not the purpose of this section to induce you to infringe any patents or
 | 
					 | 
				
			||||||
other property right claims or to contest validity of any such claims; this
 | 
					 | 
				
			||||||
section has the sole purpose of protecting the integrity of the free software
 | 
					 | 
				
			||||||
distribution system, which is implemented by public license practices. Many
 | 
					 | 
				
			||||||
people have made generous contributions to the wide range of software
 | 
					 | 
				
			||||||
distributed through that system in reliance on consistent application of that
 | 
					 | 
				
			||||||
system; it is up to the author/donor to decide if he or she is willing to
 | 
					 | 
				
			||||||
distribute software through any other system and a licensee cannot impose that
 | 
					 | 
				
			||||||
choice.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This section is intended to make thoroughly clear what is believed to be a
 | 
					 | 
				
			||||||
consequence of the rest of this License.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**8.** If the distribution and/or use of the Program is restricted in certain
 | 
					 | 
				
			||||||
countries either by patents or by copyrighted interfaces, the original copyright
 | 
					 | 
				
			||||||
holder who places the Program under this License may add an explicit
 | 
					 | 
				
			||||||
geographical distribution limitation excluding those countries, so that
 | 
					 | 
				
			||||||
distribution is permitted only in or among countries not thus excluded. In such
 | 
					 | 
				
			||||||
case, this License incorporates the limitation as if written in the body of this
 | 
					 | 
				
			||||||
License.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**9.** The Free Software Foundation may publish revised and/or new versions of
 | 
					 | 
				
			||||||
the General Public License from time to time. Such new versions will be similar
 | 
					 | 
				
			||||||
in spirit to the present version, but may differ in detail to address new
 | 
					 | 
				
			||||||
problems or concerns.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Each version is given a distinguishing version number. If the Program specifies
 | 
					 | 
				
			||||||
a version number of this License which applies to it and "any later version",
 | 
					 | 
				
			||||||
you have the option of following the terms and conditions either of that version
 | 
					 | 
				
			||||||
or of any later version published by the Free Software Foundation. If the
 | 
					 | 
				
			||||||
Program does not specify a version number of this License, you may choose any
 | 
					 | 
				
			||||||
version ever published by the Free Software Foundation.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**10.** If you wish to incorporate parts of the Program into other free programs
 | 
					 | 
				
			||||||
whose distribution conditions are different, write to the author to ask for
 | 
					 | 
				
			||||||
permission. For software which is copyrighted by the Free Software Foundation,
 | 
					 | 
				
			||||||
write to the Free Software Foundation; we sometimes make exceptions for this.
 | 
					 | 
				
			||||||
Our decision will be guided by the two goals of preserving the free status of
 | 
					 | 
				
			||||||
all derivatives of our free software and of promoting the sharing and reuse of
 | 
					 | 
				
			||||||
software generally.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
No Warranty
 | 
					 | 
				
			||||||
-----------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
 | 
					 | 
				
			||||||
THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
 | 
					 | 
				
			||||||
STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
 | 
					 | 
				
			||||||
"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 | 
					 | 
				
			||||||
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 | 
					 | 
				
			||||||
PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
 | 
					 | 
				
			||||||
PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
 | 
					 | 
				
			||||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
					 | 
				
			||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
 | 
					 | 
				
			||||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
 | 
					 | 
				
			||||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
 | 
					 | 
				
			||||||
INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
 | 
					 | 
				
			||||||
BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
 | 
					 | 
				
			||||||
FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER
 | 
					 | 
				
			||||||
OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 | 
					 | 
				
			||||||
@@ -20,14 +20,17 @@ $ git clone https://github.com/DigitalDevices/pvr.octonet.git
 | 
				
			|||||||
Clone the Kodi repository:
 | 
					Clone the Kodi repository:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
$ git clone --branch master https://github.com/xbmc/xbmc.git
 | 
					$ git clone https://github.com/xbmc/xbmc.git
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you already have a local Kodi checkout, you can use that one. Just make sure it is recent enough
 | 
				
			||||||
 | 
					(Kodi 17 Beta 5 or later should work).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
$ cd pvr.octonet
 | 
					$ cd pvr.octonet
 | 
				
			||||||
$ mkdir build
 | 
					$ mkdir build
 | 
				
			||||||
$ cd build
 | 
					$ cd build
 | 
				
			||||||
$ cmake -DCMAKE_BUILD_TYPE=Release -DADDONS_TO_BUILD="pvr.octonet" -DADDON_SRC_PREFIX="path to parent of pvr.octonet" -DCMAKE_INSTALL_PREFIX="install" -DPACKAGE_ZIP=ON "path to kodi/cmake/addons"
 | 
					$ cmake -DCMAKE_BUILD_TYPE=Release -DADDONS_TO_BUILD="pvr.octonet" -DADDON_SRC_PREFIX="path to parent of pvr.octonet" -DCMAKE_INSTALL_PREFIX="install" -DPACKAGE_ZIP=ON "path to kodi/project/cmake/addons"
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
On Windows, you should add `-G "NMake Makefiles"` to the CMake invocation. Make sure that
 | 
					On Windows, you should add `-G "NMake Makefiles"` to the CMake invocation. Make sure that
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,12 +29,12 @@ artifacts:
 | 
				
			|||||||
build_script:
 | 
					build_script:
 | 
				
			||||||
  - cd ..
 | 
					  - cd ..
 | 
				
			||||||
  - set ROOT=%cd%
 | 
					  - set ROOT=%cd%
 | 
				
			||||||
  - git clone --branch master --depth=1 https://github.com/xbmc/xbmc.git
 | 
					  - git clone --depth=1 https://github.com/xbmc/xbmc.git -b Krypton
 | 
				
			||||||
  - mkdir xbmc\cmake\addons\addons\pvr.octonet
 | 
					  - mkdir xbmc\project\cmake\addons\addons\pvr.octonet
 | 
				
			||||||
  - echo pvr.octonet https://github.com/DigitalDevices/pvr.octonet master > xbmc\cmake\addons\addons\pvr.octonet\pvr.octonet.txt
 | 
					  - echo pvr.octonet https://github.com/DigitalDevices/pvr.octonet master > xbmc\project\cmake\addons\addons\pvr.octonet\pvr.octonet.txt
 | 
				
			||||||
  - cd %ADDON%
 | 
					  - cd %ADDON%
 | 
				
			||||||
  - mkdir build
 | 
					  - mkdir build
 | 
				
			||||||
  - cd build
 | 
					  - cd build
 | 
				
			||||||
  # Must use absolute path for cmake to build depends correctly
 | 
					  # Must use absolute path for cmake to build depends correctly
 | 
				
			||||||
  - cmake -G "%GENERATOR%" -DADDONS_TO_BUILD=%ADDON% -DCMAKE_BUILD_TYPE=%CONFIG% -DADDON_SRC_PREFIX=%ROOT% -DCMAKE_INSTALL_PREFIX=install -DPACKAGE_ZIP=1 %ROOT%\xbmc\cmake\addons
 | 
					  - cmake -G "%GENERATOR%" -DADDONS_TO_BUILD=%ADDON% -DCMAKE_BUILD_TYPE=%CONFIG% -DADDON_SRC_PREFIX=%ROOT% -DCMAKE_INSTALL_PREFIX=install -DPACKAGE_ZIP=1 %ROOT%\xbmc\project\cmake\addons
 | 
				
			||||||
  - cmake --build . --config %CONFIG%
 | 
					  - cmake --build . --config %CONFIG%
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -1,9 +1,9 @@
 | 
				
			|||||||
Source: kodi-pvr-octonet
 | 
					Source: kodi-pvr-octonet
 | 
				
			||||||
Priority: extra
 | 
					Priority: extra
 | 
				
			||||||
Maintainer: Julian Scheel <julian@jusst.de>
 | 
					Maintainer: Julian Scheel <julian@jusst.de>
 | 
				
			||||||
Build-Depends: debhelper (>= 9.0.0), cmake, libjsoncpp-dev,
 | 
					Build-Depends: debhelper (>= 9.0.0), cmake, libjsoncpp-dev, kodi-pvr-dev,
 | 
				
			||||||
               libp8-platform-dev, kodi-addon-dev
 | 
					               libkodiplatform-dev (>= 16.0.0), kodi-addon-dev
 | 
				
			||||||
Standards-Version: 4.1.2
 | 
					Standards-Version: 3.9.4
 | 
				
			||||||
Section: libs
 | 
					Section: libs
 | 
				
			||||||
Homepage: https://github.com/DigitalDevices/pvr.octonet
 | 
					Homepage: https://github.com/DigitalDevices/pvr.octonet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							@@ -5,7 +5,7 @@ Source: https://github.com/DigitalDevices/pvr.octonet
 | 
				
			|||||||
Files: *
 | 
					Files: *
 | 
				
			||||||
Copyright: 2015-2016 Julian Scheel
 | 
					Copyright: 2015-2016 Julian Scheel
 | 
				
			||||||
           2015-2016 jusst technologies GmbH
 | 
					           2015-2016 jusst technologies GmbH
 | 
				
			||||||
           2005-2020 Team Kodi
 | 
					           2005-2013 Team XBMC
 | 
				
			||||||
License: GPL-2+
 | 
					License: GPL-2+
 | 
				
			||||||
 This package is free software; you can redistribute it and/or modify
 | 
					 This package is free software; you can redistribute it and/or modify
 | 
				
			||||||
 it under the terms of the GNU General Public License as published by
 | 
					 it under the terms of the GNU General Public License as published by
 | 
				
			||||||
@@ -24,8 +24,7 @@ License: GPL-2+
 | 
				
			|||||||
 Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
 | 
					 Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files: debian/*
 | 
					Files: debian/*
 | 
				
			||||||
Copyright: 2020 Team Kodi
 | 
					Copyright: 2016 Julian Scheel <julian@jusst.de>
 | 
				
			||||||
           2016 Julian Scheel <julian@jusst.de>
 | 
					 | 
				
			||||||
           2015 Jean-Luc Barriere
 | 
					           2015 Jean-Luc Barriere
 | 
				
			||||||
           2015 wsnipex <wsnipex@a1.net>
 | 
					           2015 wsnipex <wsnipex@a1.net>
 | 
				
			||||||
License: GPL-2+
 | 
					License: GPL-2+
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,7 @@
 | 
				
			|||||||
cmake_minimum_required(VERSION 3.5)
 | 
					 | 
				
			||||||
project(jsoncpp)
 | 
					project(jsoncpp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SET(CMAKE_CXX_STANDARD 11)
 | 
					cmake_minimum_required(VERSION 2.6)
 | 
				
			||||||
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
 | 
					enable_language(CXX)
 | 
				
			||||||
SET(CMAKE_CXX_EXTENSIONS OFF)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(SOURCES src/lib_json/json_reader.cpp
 | 
					set(SOURCES src/lib_json/json_reader.cpp
 | 
				
			||||||
            src/lib_json/json_value.cpp
 | 
					            src/lib_json/json_value.cpp
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
3671ba6051e0f30849942cc66d1798fdf0362d089343a83f704c09ee7156604f
 | 
					 | 
				
			||||||
@@ -1 +1 @@
 | 
				
			|||||||
jsoncpp http://mirrors.kodi.tv/build-deps/sources/jsoncpp-1.8.3.tar.gz
 | 
					jsoncpp http://mirrors.kodi.tv/build-deps/sources/jsoncpp-src-0.5.0.tar.gz
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,23 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
<addon
 | 
					<addon
 | 
				
			||||||
	id="pvr.octonet"
 | 
						id="pvr.octonet"
 | 
				
			||||||
	version="4.0.0"
 | 
						version="0.3.7"
 | 
				
			||||||
	name="Digital Devices Octopus NET Client"
 | 
						name="Digital Devices Octopus NET Client"
 | 
				
			||||||
	provider-name="digitaldevices">
 | 
						provider-name="digitaldevices">
 | 
				
			||||||
	<requires>@ADDON_DEPENDS@</requires>
 | 
						<requires>
 | 
				
			||||||
 | 
							<c-pluff version="0.1" />
 | 
				
			||||||
 | 
							<import addon="xbmc.pvr" version="5.2.1" />
 | 
				
			||||||
 | 
						</requires>
 | 
				
			||||||
	<extension
 | 
						<extension
 | 
				
			||||||
		point="kodi.pvrclient"
 | 
							point="xbmc.pvrclient"
 | 
				
			||||||
		library_@PLATFORM@="@LIBRARY_FILENAME@"/>
 | 
							library_linux="pvr.octonet.so"
 | 
				
			||||||
 | 
							library_osx="pvr.octonet.dylib"
 | 
				
			||||||
 | 
							library_freebsd="pvr.octonet.so"
 | 
				
			||||||
 | 
							library_windx="pvr.octonet.dll"
 | 
				
			||||||
 | 
							library_android="libpvr.octonet.so" />
 | 
				
			||||||
	<extension point="xbmc.addon.metadata">
 | 
						<extension point="xbmc.addon.metadata">
 | 
				
			||||||
		<summary lang="de_DE">Kodi PVR Addon für Digital Devices Octopus NET Streams</summary>
 | 
							<summary lang="de_DE">Kodi PVR Addon für Digital Devices Octopus NET Streams</summary>
 | 
				
			||||||
		<summary lang="en_US">Kodi PVR Addon for Digital Devices Octopus NET Streams</summary>
 | 
							<summary lang="en_US">Kodi PVR Addon for Digital Devices Octopus NET Streams</summary>
 | 
				
			||||||
		<platform>@PLATFORM@</platform>
 | 
							<platform>all</platform>
 | 
				
			||||||
		<license>GPL-2.0-or-later</license>
 | 
					 | 
				
			||||||
		<source>https://github.com/DigitalDevices/pvr.octonet</source>
 | 
					 | 
				
			||||||
	</extension>
 | 
						</extension>
 | 
				
			||||||
</addon>
 | 
					</addon>
 | 
				
			||||||
@@ -1,18 +1,5 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
 | 
					<?xml version="1.0" encoding="utf-8" standalone="yes"?>
 | 
				
			||||||
<settings version="1">
 | 
					<settings>
 | 
				
			||||||
  <section id="pvr.octonet">
 | 
						<!-- Octonet Server Address -->
 | 
				
			||||||
    <category id="main" label="128" help="-1">
 | 
						<setting id="octonetAddress" type="text" label="30000" default="" />
 | 
				
			||||||
      <group id="1" label="-1">
 | 
					 | 
				
			||||||
        <!-- Octonet Server Address -->
 | 
					 | 
				
			||||||
        <setting id="octonetAddress" type="string" label="30000" help="-1">
 | 
					 | 
				
			||||||
          <level>0</level>
 | 
					 | 
				
			||||||
          <default></default>
 | 
					 | 
				
			||||||
          <constraints>
 | 
					 | 
				
			||||||
            <allowempty>true</allowempty>
 | 
					 | 
				
			||||||
          </constraints>
 | 
					 | 
				
			||||||
          <control type="edit" format="string" />
 | 
					 | 
				
			||||||
        </setting>
 | 
					 | 
				
			||||||
      </group>
 | 
					 | 
				
			||||||
    </category>
 | 
					 | 
				
			||||||
  </section>
 | 
					 | 
				
			||||||
</settings>
 | 
					</settings>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,458 +1,370 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Copyright (C) 2015 Julian Scheel <julian@jusst.de>
 | 
					 * Copyright (C) 2015 Julian Scheel <julian@jusst.de>
 | 
				
			||||||
 *  Copyright (C) 2015 jusst technologies GmbH
 | 
					 * Copyright (C) 2015 jusst technologies GmbH
 | 
				
			||||||
 *  Copyright (C) 2015 Digital Devices GmbH
 | 
					 * Copyright (C) 2015 Digital Devices GmbH
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  SPDX-License-Identifier: GPL-2.0-or-later
 | 
					 * This program is free software; you can redistribute it and/or
 | 
				
			||||||
 *  See LICENSE.md for more information.
 | 
					 * modify it under the terms of the GNU General Public License
 | 
				
			||||||
 | 
					 * as published by the Free Software Foundation; either version 2
 | 
				
			||||||
 | 
					 * of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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 this program; if not, write to the Free Software
 | 
				
			||||||
 | 
					 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 | 
				
			||||||
 | 
					 * USA.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "OctonetData.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "rtsp_client.hpp"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <json/json.h>
 | 
					 | 
				
			||||||
#include <kodi/Filesystem.h>
 | 
					 | 
				
			||||||
#include <kodi/General.h>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <json/json.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "OctonetData.h"
 | 
				
			||||||
 | 
					#include "p8-platform/util/StringUtils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __WINDOWS__
 | 
					#ifdef __WINDOWS__
 | 
				
			||||||
#define timegm _mkgmtime
 | 
					#define timegm _mkgmtime
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OctonetData::OctonetData(const std::string& octonetAddress,
 | 
					using namespace ADDON;
 | 
				
			||||||
                         KODI_HANDLE instance,
 | 
					
 | 
				
			||||||
                         const std::string& kodiVersion)
 | 
					OctonetData::OctonetData()
 | 
				
			||||||
  : kodi::addon::CInstancePVRClient(instance, kodiVersion)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  m_serverAddress = octonetAddress;
 | 
						serverAddress = octonetAddress;
 | 
				
			||||||
  m_channels.clear();
 | 
						channels.clear();
 | 
				
			||||||
  m_groups.clear();
 | 
						groups.clear();
 | 
				
			||||||
  m_lastEpgLoad = 0;
 | 
						lastEpgLoad = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!LoadChannelList())
 | 
						if (!loadChannelList())
 | 
				
			||||||
    kodi::QueueFormattedNotification(QUEUE_ERROR, kodi::GetLocalizedString(30001).c_str(),
 | 
							kodi->QueueNotification(QUEUE_ERROR, kodi->GetLocalizedString(30001), channels.size());
 | 
				
			||||||
                                     m_channels.size());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /*
 | 
					 | 
				
			||||||
  // Currently unused, as thread was already present before with
 | 
					 | 
				
			||||||
  // p8platform, by remove of them was it added as C++11 thread way.
 | 
					 | 
				
			||||||
  kodi::Log(ADDON_LOG_INFO, "%s Starting separate client update thread...", __func__);
 | 
					 | 
				
			||||||
  m_running = true;
 | 
					 | 
				
			||||||
  m_thread = std::thread([&] { Process(); });
 | 
					 | 
				
			||||||
  */
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OctonetData::~OctonetData(void)
 | 
					OctonetData::~OctonetData(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  /*
 | 
						channels.clear();
 | 
				
			||||||
  m_running = false;
 | 
						groups.clear();
 | 
				
			||||||
  if (m_thread.joinable())
 | 
					 | 
				
			||||||
    m_thread.join();
 | 
					 | 
				
			||||||
  */
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PVR_ERROR OctonetData::GetCapabilities(kodi::addon::PVRCapabilities& capabilities)
 | 
					int64_t OctonetData::parseID(std::string id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  capabilities.SetSupportsTV(true);
 | 
						std::hash<std::string> hash_fn;
 | 
				
			||||||
  capabilities.SetSupportsRadio(true);
 | 
						int64_t nativeId = hash_fn(id);
 | 
				
			||||||
  capabilities.SetSupportsChannelGroups(true);
 | 
					 | 
				
			||||||
  capabilities.SetSupportsEPG(true);
 | 
					 | 
				
			||||||
  capabilities.SetSupportsRecordings(false);
 | 
					 | 
				
			||||||
  capabilities.SetSupportsRecordingsRename(false);
 | 
					 | 
				
			||||||
  capabilities.SetSupportsRecordingsLifetimeChange(false);
 | 
					 | 
				
			||||||
  capabilities.SetSupportsDescrambleInfo(false);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
						return nativeId;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PVR_ERROR OctonetData::GetBackendName(std::string& name)
 | 
					bool OctonetData::loadChannelList()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  name = "Digital Devices Octopus NET Client";
 | 
						std::string jsonContent;
 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
						void *f = kodi->OpenFile(("http://" + serverAddress + "/channellist.lua?select=json").c_str(), 0);
 | 
				
			||||||
 | 
						if (!f)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char buf[1024];
 | 
				
			||||||
 | 
						while (int read = kodi->ReadFile(f, buf, 1024))
 | 
				
			||||||
 | 
							jsonContent.append(buf, read);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kodi->CloseFile(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Json::Value root;
 | 
				
			||||||
 | 
						Json::Reader reader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!reader.parse(jsonContent, root, false))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const Json::Value groupList = root["GroupList"];
 | 
				
			||||||
 | 
						for (unsigned int i = 0; i < groupList.size(); i++) {
 | 
				
			||||||
 | 
							const Json::Value channelList = groupList[i]["ChannelList"];
 | 
				
			||||||
 | 
							OctonetGroup group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							group.name = groupList[i]["Title"].asString();
 | 
				
			||||||
 | 
							group.radio = group.name.compare(0, 5, "Radio") ? false : true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (unsigned int j = 0; j < channelList.size(); j++) {
 | 
				
			||||||
 | 
								const Json::Value channel = channelList[j];
 | 
				
			||||||
 | 
								OctonetChannel chan;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								chan.name = channel["Title"].asString();
 | 
				
			||||||
 | 
								chan.url = "rtsp://" + serverAddress + "/" + channel["Request"].asString();
 | 
				
			||||||
 | 
								chan.radio = group.radio;
 | 
				
			||||||
 | 
								chan.nativeId = parseID(channel["ID"].asString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								chan.id = 1000 + channels.size();
 | 
				
			||||||
 | 
								group.members.push_back(channels.size());
 | 
				
			||||||
 | 
								channels.push_back(chan);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							groups.push_back(group);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PVR_ERROR OctonetData::GetBackendVersion(std::string& version)
 | 
					OctonetChannel* OctonetData::findChannel(int64_t nativeId)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  version = STR(OCTONET_VERSION);
 | 
						std::vector<OctonetChannel>::iterator it;
 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
						for (it = channels.begin(); it < channels.end(); ++it) {
 | 
				
			||||||
 | 
							if (it->nativeId == nativeId)
 | 
				
			||||||
 | 
								return &*it;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PVR_ERROR OctonetData::GetConnectionString(std::string& connection)
 | 
					time_t OctonetData::parseDateTime(std::string date)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  connection = "connected"; // FIXME: translate?
 | 
						struct tm timeinfo;
 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
					
 | 
				
			||||||
 | 
						memset(&timeinfo, 0, sizeof(timeinfo));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (date.length() > 8) {
 | 
				
			||||||
 | 
							sscanf(date.c_str(), "%04d-%02d-%02dT%02d:%02d:%02dZ",
 | 
				
			||||||
 | 
									&timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday,
 | 
				
			||||||
 | 
									&timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec);
 | 
				
			||||||
 | 
							timeinfo.tm_mon -= 1;
 | 
				
			||||||
 | 
							timeinfo.tm_year -= 1900;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							sscanf(date.c_str(), "%02d:%02d:%02d",
 | 
				
			||||||
 | 
									&timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec);
 | 
				
			||||||
 | 
							timeinfo.tm_year = 70; // unix timestamps start 1970
 | 
				
			||||||
 | 
							timeinfo.tm_mday = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						timeinfo.tm_isdst = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return timegm(&timeinfo);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PVR_ERROR OctonetData::GetBackendHostname(std::string& hostname)
 | 
					bool OctonetData::loadEPG(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  hostname = m_serverAddress;
 | 
						/* Reload at most every 30 seconds */
 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
						if (lastEpgLoad + 30 > time(NULL))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string jsonContent;
 | 
				
			||||||
 | 
						void *f = kodi->OpenFile(("http://" + serverAddress + "/epg.lua?;#|encoding=gzip").c_str(), 0);
 | 
				
			||||||
 | 
						if (!f)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char buf[1024];
 | 
				
			||||||
 | 
						while (int read = kodi->ReadFile(f, buf, 1024))
 | 
				
			||||||
 | 
							jsonContent.append(buf, read);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kodi->CloseFile(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Json::Value root;
 | 
				
			||||||
 | 
						Json::Reader reader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!reader.parse(jsonContent, root, false))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const Json::Value eventList = root["EventList"];
 | 
				
			||||||
 | 
						OctonetChannel *channel = NULL;
 | 
				
			||||||
 | 
						for (unsigned int i = 0; i < eventList.size(); i++) {
 | 
				
			||||||
 | 
							const Json::Value event = eventList[i];
 | 
				
			||||||
 | 
							OctonetEpgEntry entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							entry.start = parseDateTime(event["Time"].asString());
 | 
				
			||||||
 | 
							entry.end = entry.start + parseDateTime(event["Duration"].asString());
 | 
				
			||||||
 | 
							entry.title = event["Name"].asString();
 | 
				
			||||||
 | 
							entry.subtitle = event["Text"].asString();
 | 
				
			||||||
 | 
							std::string channelId = event["ID"].asString();
 | 
				
			||||||
 | 
							std::string epgId = channelId.substr(channelId.rfind(":") + 1);
 | 
				
			||||||
 | 
							channelId = channelId.substr(0, channelId.rfind(":"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							entry.channelId = parseID(channelId);
 | 
				
			||||||
 | 
							entry.id = atoi(epgId.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (channel == NULL || channel->nativeId != entry.channelId)
 | 
				
			||||||
 | 
								channel = findChannel(entry.channelId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (channel == NULL) {
 | 
				
			||||||
 | 
								kodi->Log(LOG_ERROR, "EPG for unknown channel.");
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							channel->epg.push_back(entry);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lastEpgLoad = time(NULL);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PVR_ERROR OctonetData::OnSystemSleep()
 | 
					void *OctonetData::Process(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  kodi::Log(ADDON_LOG_INFO, "Received event: %s", __func__);
 | 
						return NULL;
 | 
				
			||||||
  // FIXME: Disconnect?
 | 
					 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PVR_ERROR OctonetData::OnSystemWake()
 | 
					int OctonetData::getChannelCount(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  kodi::Log(ADDON_LOG_INFO, "Received event: %s", __func__);
 | 
						return channels.size();
 | 
				
			||||||
  // FIXME:Reconnect?
 | 
					 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int64_t OctonetData::ParseID(std::string id)
 | 
					PVR_ERROR OctonetData::getChannels(ADDON_HANDLE handle, bool bRadio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  std::hash<std::string> hash_fn;
 | 
						for (unsigned int i = 0; i < channels.size(); i++)
 | 
				
			||||||
  int64_t nativeId = hash_fn(id);
 | 
						{
 | 
				
			||||||
 | 
							OctonetChannel &channel = channels.at(i);
 | 
				
			||||||
 | 
							if (channel.radio == bRadio)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								PVR_CHANNEL chan;
 | 
				
			||||||
 | 
								memset(&chan, 0, sizeof(PVR_CHANNEL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return nativeId;
 | 
								chan.iUniqueId = channel.id;
 | 
				
			||||||
 | 
								chan.bIsRadio = channel.radio;
 | 
				
			||||||
 | 
								chan.iChannelNumber = i;
 | 
				
			||||||
 | 
								strncpy(chan.strChannelName, channel.name.c_str(), strlen(channel.name.c_str()));
 | 
				
			||||||
 | 
								strcpy(chan.strInputFormat, "video/x-mpegts");
 | 
				
			||||||
 | 
								chan.bIsHidden = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								pvr->TransferChannelEntry(handle, &chan);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return PVR_ERROR_NO_ERROR;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool OctonetData::LoadChannelList()
 | 
					PVR_ERROR OctonetData::getEPG(ADDON_HANDLE handle, const PVR_CHANNEL &channel, time_t start, time_t end)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  std::string jsonContent;
 | 
						for (unsigned int i = 0; i < channels.size(); i++)
 | 
				
			||||||
  kodi::vfs::CFile f;
 | 
						{
 | 
				
			||||||
  if (!f.OpenFile("http://" + m_serverAddress + "/channellist.lua?select=json", 0))
 | 
							OctonetChannel &chan = channels.at(i);
 | 
				
			||||||
    return false;
 | 
							if (channel.iUniqueId != chan.id)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  char buf[1024];
 | 
							if(chan.epg.empty()) {
 | 
				
			||||||
  while (int read = f.Read(buf, 1024))
 | 
								loadEPG();
 | 
				
			||||||
    jsonContent.append(buf, read);
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  f.Close();
 | 
							// FIXME: Check if reload is needed!?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Json::Value root;
 | 
							std::vector<OctonetEpgEntry>::iterator it;
 | 
				
			||||||
  Json::Reader reader;
 | 
							time_t last_end = 0;
 | 
				
			||||||
 | 
							for (it = chan.epg.begin(); it != chan.epg.end(); ++it) {
 | 
				
			||||||
 | 
								if (it->end > last_end)
 | 
				
			||||||
 | 
									last_end = it->end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!reader.parse(jsonContent, root, false))
 | 
								if (it->end < start || it->start > end) {
 | 
				
			||||||
    return false;
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const Json::Value groupList = root["GroupList"];
 | 
								EPG_TAG entry;
 | 
				
			||||||
  for (unsigned int i = 0; i < groupList.size(); i++)
 | 
								memset(&entry, 0, sizeof(EPG_TAG));
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    const Json::Value channelList = groupList[i]["ChannelList"];
 | 
					 | 
				
			||||||
    OctonetGroup group;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    group.name = groupList[i]["Title"].asString();
 | 
								entry.iChannelNumber = i;
 | 
				
			||||||
    group.radio = group.name.compare(0, 5, "Radio") ? false : true;
 | 
								entry.iUniqueBroadcastId = it->id;
 | 
				
			||||||
 | 
								entry.strTitle = it->title.c_str();
 | 
				
			||||||
 | 
								entry.strPlotOutline = it->subtitle.c_str();
 | 
				
			||||||
 | 
								entry.startTime = it->start;
 | 
				
			||||||
 | 
								entry.endTime = it->end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (unsigned int j = 0; j < channelList.size(); j++)
 | 
								pvr->TransferEpgEntry(handle, &entry);
 | 
				
			||||||
    {
 | 
							}
 | 
				
			||||||
      const Json::Value channel = channelList[j];
 | 
					 | 
				
			||||||
      OctonetChannel chan;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      chan.name = channel["Title"].asString();
 | 
							if (last_end < end)
 | 
				
			||||||
      chan.url = "rtsp://" + m_serverAddress + "/" + channel["Request"].asString();
 | 
								loadEPG();
 | 
				
			||||||
      chan.radio = group.radio;
 | 
					 | 
				
			||||||
      chan.nativeId = ParseID(channel["ID"].asString());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      chan.id = 1000 + m_channels.size();
 | 
							for (it = chan.epg.begin(); it != chan.epg.end(); ++it) {
 | 
				
			||||||
      group.members.push_back(m_channels.size());
 | 
								if (it->end < start || it->start > end) {
 | 
				
			||||||
      m_channels.push_back(chan);
 | 
									continue;
 | 
				
			||||||
    }
 | 
								}
 | 
				
			||||||
    m_groups.push_back(group);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return true;
 | 
								EPG_TAG entry;
 | 
				
			||||||
 | 
								memset(&entry, 0, sizeof(EPG_TAG));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								entry.iChannelNumber = i;
 | 
				
			||||||
 | 
								entry.iUniqueBroadcastId = it->id;
 | 
				
			||||||
 | 
								entry.strTitle = it->title.c_str();
 | 
				
			||||||
 | 
								entry.strPlotOutline = it->subtitle.c_str();
 | 
				
			||||||
 | 
								entry.startTime = it->start;
 | 
				
			||||||
 | 
								entry.endTime = it->end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								pvr->TransferEpgEntry(handle, &entry);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return PVR_ERROR_NO_ERROR;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OctonetChannel* OctonetData::FindChannel(int64_t nativeId)
 | 
					const std::string& OctonetData::getUrl(int id) const {
 | 
				
			||||||
 | 
						for(std::vector<OctonetChannel>::const_iterator iter = channels.begin(); iter != channels.end(); ++iter) {
 | 
				
			||||||
 | 
							if(iter->id == id) {
 | 
				
			||||||
 | 
								return iter->url;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return channels[0].url;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const std::string& OctonetData::getName(int id) const {
 | 
				
			||||||
 | 
						for(std::vector<OctonetChannel>::const_iterator iter = channels.begin(); iter != channels.end(); ++iter) {
 | 
				
			||||||
 | 
							if(iter->id == id) {
 | 
				
			||||||
 | 
								return iter->name;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return channels[0].name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int OctonetData::getGroupCount(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  for (auto& channel : m_channels)
 | 
						return groups.size();
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    if (channel.nativeId == nativeId)
 | 
					 | 
				
			||||||
      return &channel;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return nullptr;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
time_t OctonetData::ParseDateTime(std::string date)
 | 
					PVR_ERROR OctonetData::getGroups(ADDON_HANDLE handle, bool bRadio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  struct tm timeinfo;
 | 
						for (unsigned int i = 0; i < groups.size(); i++)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							OctonetGroup &group = groups.at(i);
 | 
				
			||||||
 | 
							if (group.radio == bRadio)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								PVR_CHANNEL_GROUP g;
 | 
				
			||||||
 | 
								memset(&g, 0, sizeof(PVR_CHANNEL_GROUP));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  memset(&timeinfo, 0, sizeof(timeinfo));
 | 
								g.iPosition = 0;
 | 
				
			||||||
 | 
								g.bIsRadio = group.radio;
 | 
				
			||||||
 | 
								strncpy(g.strGroupName, group.name.c_str(), strlen(group.name.c_str()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (date.length() > 8)
 | 
								pvr->TransferChannelGroup(handle, &g);
 | 
				
			||||||
  {
 | 
							}
 | 
				
			||||||
    sscanf(date.c_str(), "%04d-%02d-%02dT%02d:%02d:%02dZ", &timeinfo.tm_year, &timeinfo.tm_mon,
 | 
						}
 | 
				
			||||||
           &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec);
 | 
					 | 
				
			||||||
    timeinfo.tm_mon -= 1;
 | 
					 | 
				
			||||||
    timeinfo.tm_year -= 1900;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    sscanf(date.c_str(), "%02d:%02d:%02d", &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec);
 | 
					 | 
				
			||||||
    timeinfo.tm_year = 70; // unix timestamps start 1970
 | 
					 | 
				
			||||||
    timeinfo.tm_mday = 1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  timeinfo.tm_isdst = -1;
 | 
						return PVR_ERROR_NO_ERROR;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  return timegm(&timeinfo);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool OctonetData::LoadEPG(void)
 | 
					PVR_ERROR OctonetData::getGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  /* Reload at most every 30 seconds */
 | 
						OctonetGroup *g = findGroup(group.strGroupName);
 | 
				
			||||||
  if (m_lastEpgLoad + 30 > time(nullptr))
 | 
						if (g == NULL)
 | 
				
			||||||
    return false;
 | 
							return PVR_ERROR_UNKNOWN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string jsonContent;
 | 
						for (unsigned int i = 0; i < g->members.size(); i++)
 | 
				
			||||||
  kodi::vfs::CFile f;
 | 
						{
 | 
				
			||||||
  if (!f.OpenFile("http://" + m_serverAddress + "/epg.lua?;#|encoding=gzip", 0))
 | 
							OctonetChannel &channel = channels.at(g->members[i]);
 | 
				
			||||||
    return false;
 | 
							PVR_CHANNEL_GROUP_MEMBER m;
 | 
				
			||||||
 | 
							memset(&m, 0, sizeof(PVR_CHANNEL_GROUP_MEMBER));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  char buf[1024];
 | 
							strncpy(m.strGroupName, group.strGroupName, strlen(group.strGroupName));
 | 
				
			||||||
  while (int read = f.Read(buf, 1024))
 | 
							m.iChannelUniqueId = channel.id;
 | 
				
			||||||
    jsonContent.append(buf, read);
 | 
							m.iChannelNumber = channel.id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  f.Close();
 | 
							pvr->TransferChannelGroupMember(handle, &m);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Json::Value root;
 | 
						return PVR_ERROR_NO_ERROR;
 | 
				
			||||||
  Json::Reader reader;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!reader.parse(jsonContent, root, false))
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const Json::Value eventList = root["EventList"];
 | 
					 | 
				
			||||||
  OctonetChannel* channel = nullptr;
 | 
					 | 
				
			||||||
  for (unsigned int i = 0; i < eventList.size(); i++)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    const Json::Value event = eventList[i];
 | 
					 | 
				
			||||||
    OctonetEpgEntry entry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    entry.start = ParseDateTime(event["Time"].asString());
 | 
					 | 
				
			||||||
    entry.end = entry.start + ParseDateTime(event["Duration"].asString());
 | 
					 | 
				
			||||||
    entry.title = event["Name"].asString();
 | 
					 | 
				
			||||||
    entry.subtitle = event["Text"].asString();
 | 
					 | 
				
			||||||
    std::string channelId = event["ID"].asString();
 | 
					 | 
				
			||||||
    std::string epgId = channelId.substr(channelId.rfind(":") + 1);
 | 
					 | 
				
			||||||
    channelId = channelId.substr(0, channelId.rfind(":"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    entry.channelId = ParseID(channelId);
 | 
					 | 
				
			||||||
    entry.id = std::stoi(epgId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (channel == nullptr || channel->nativeId != entry.channelId)
 | 
					 | 
				
			||||||
      channel = FindChannel(entry.channelId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (channel == nullptr)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      kodi::Log(ADDON_LOG_ERROR, "EPG for unknown channel.");
 | 
					 | 
				
			||||||
      continue;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    channel->epg.push_back(entry);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  m_lastEpgLoad = time(nullptr);
 | 
					 | 
				
			||||||
  return true;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OctonetData::Process()
 | 
					OctonetGroup* OctonetData::findGroup(const std::string &name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  return;
 | 
						for (unsigned int i = 0; i < groups.size(); i++)
 | 
				
			||||||
}
 | 
						{
 | 
				
			||||||
 | 
							if (groups.at(i).name == name)
 | 
				
			||||||
PVR_ERROR OctonetData::GetChannelsAmount(int& amount)
 | 
								return &groups.at(i);
 | 
				
			||||||
{
 | 
						}
 | 
				
			||||||
  amount = m_channels.size();
 | 
					
 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PVR_ERROR OctonetData::GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  for (unsigned int i = 0; i < m_channels.size(); i++)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    OctonetChannel& channel = m_channels.at(i);
 | 
					 | 
				
			||||||
    if (channel.radio == radio)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      kodi::addon::PVRChannel chan;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      chan.SetUniqueId(channel.id);
 | 
					 | 
				
			||||||
      chan.SetIsRadio(channel.radio);
 | 
					 | 
				
			||||||
      chan.SetChannelNumber(i);
 | 
					 | 
				
			||||||
      chan.SetChannelName(channel.name);
 | 
					 | 
				
			||||||
      chan.SetMimeType("video/x-mpegts");
 | 
					 | 
				
			||||||
      chan.SetIsHidden(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      results.Add(chan);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PVR_ERROR OctonetData::GetEPGForChannel(int channelUid,
 | 
					 | 
				
			||||||
                                        time_t start,
 | 
					 | 
				
			||||||
                                        time_t end,
 | 
					 | 
				
			||||||
                                        kodi::addon::PVREPGTagsResultSet& results)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  for (unsigned int i = 0; i < m_channels.size(); i++)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    OctonetChannel& chan = m_channels.at(i);
 | 
					 | 
				
			||||||
    if (channelUid != chan.id)
 | 
					 | 
				
			||||||
      continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (chan.epg.empty())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      LoadEPG();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // FIXME: Check if reload is needed!?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    time_t last_end = 0;
 | 
					 | 
				
			||||||
    for (const auto& epg : chan.epg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      if (epg.end > last_end)
 | 
					 | 
				
			||||||
        last_end = epg.end;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (epg.end < start || epg.start > end)
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        continue;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      kodi::addon::PVREPGTag entry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      entry.SetUniqueChannelId(chan.id);
 | 
					 | 
				
			||||||
      entry.SetUniqueBroadcastId(epg.id);
 | 
					 | 
				
			||||||
      entry.SetTitle(epg.title);
 | 
					 | 
				
			||||||
      entry.SetPlotOutline(epg.subtitle);
 | 
					 | 
				
			||||||
      entry.SetStartTime(epg.start);
 | 
					 | 
				
			||||||
      entry.SetEndTime(epg.end);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      results.Add(entry);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (last_end < end)
 | 
					 | 
				
			||||||
      LoadEPG();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (const auto& epg : chan.epg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      if (epg.end < start || epg.start > end)
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        continue;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      kodi::addon::PVREPGTag entry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      entry.SetUniqueChannelId(chan.id);
 | 
					 | 
				
			||||||
      entry.SetUniqueBroadcastId(epg.id);
 | 
					 | 
				
			||||||
      entry.SetTitle(epg.title);
 | 
					 | 
				
			||||||
      entry.SetPlotOutline(epg.subtitle);
 | 
					 | 
				
			||||||
      entry.SetStartTime(epg.start);
 | 
					 | 
				
			||||||
      entry.SetEndTime(epg.end);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      results.Add(entry);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const std::string& OctonetData::GetUrl(int id) const
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  for (const auto& channel : m_channels)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    if (channel.id == id)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      return channel.url;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return m_channels[0].url;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const std::string& OctonetData::GetName(int id) const
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  for (const auto& channel : m_channels)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    if (channel.id == id)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      return channel.name;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return m_channels[0].name;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PVR_ERROR OctonetData::GetChannelGroupsAmount(int& amount)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  amount = m_groups.size();
 | 
					 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PVR_ERROR OctonetData::GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& results)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  for (const auto& group : m_groups)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    if (group.radio == radio)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      kodi::addon::PVRChannelGroup g;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      g.SetPosition(0);
 | 
					 | 
				
			||||||
      g.SetIsRadio(group.radio);
 | 
					 | 
				
			||||||
      g.SetGroupName(group.name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      results.Add(g);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PVR_ERROR OctonetData::GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group,
 | 
					 | 
				
			||||||
                                              kodi::addon::PVRChannelGroupMembersResultSet& results)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  const OctonetGroup* g = FindGroup(group.GetGroupName());
 | 
					 | 
				
			||||||
  if (g == nullptr)
 | 
					 | 
				
			||||||
    return PVR_ERROR_UNKNOWN;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (unsigned int i = 0; i < g->members.size(); i++)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    OctonetChannel& channel = m_channels.at(g->members[i]);
 | 
					 | 
				
			||||||
    kodi::addon::PVRChannelGroupMember m;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    m.SetGroupName(group.GetGroupName());
 | 
					 | 
				
			||||||
    m.SetChannelUniqueId(channel.id);
 | 
					 | 
				
			||||||
    m.SetChannelNumber(channel.id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    results.Add(m);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return PVR_ERROR_NO_ERROR;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
OctonetGroup* OctonetData::FindGroup(const std::string& name)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  for (auto& group : m_groups)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    if (group.name == name)
 | 
					 | 
				
			||||||
      return &group;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return nullptr;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* PVR stream handling */
 | 
					 | 
				
			||||||
/* entirely unused, as we use standard RTSP+TS mux, which can be handlded by
 | 
					 | 
				
			||||||
 * Kodi core */
 | 
					 | 
				
			||||||
bool OctonetData::OpenLiveStream(const kodi::addon::PVRChannel& channelinfo)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  return rtsp_open(GetName(channelinfo.GetUniqueId()), GetUrl(channelinfo.GetUniqueId()));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int OctonetData::ReadLiveStream(unsigned char* pBuffer, unsigned int iBufferSize)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  return rtsp_read(pBuffer, iBufferSize);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void OctonetData::CloseLiveStream()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  rtsp_close();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,102 +1,93 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Copyright (C) 2015 Julian Scheel <julian@jusst.de>
 | 
					 * Copyright (C) 2015 Julian Scheel <julian@jusst.de>
 | 
				
			||||||
 *  Copyright (C) 2015 jusst technologies GmbH
 | 
					 * Copyright (C) 2015 jusst technologies GmbH
 | 
				
			||||||
 *  Copyright (C) 2015 Digital Devices GmbH
 | 
					 * Copyright (C) 2015 Digital Devices GmbH
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  SPDX-License-Identifier: GPL-2.0-or-later
 | 
					 * This program is free software; you can redistribute it and/or
 | 
				
			||||||
 *  See LICENSE.md for more information.
 | 
					 * modify it under the terms of the GNU General Public License
 | 
				
			||||||
 | 
					 * as published by the Free Software Foundation; either version 2
 | 
				
			||||||
 | 
					 * of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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 this program; if not, write to the Free Software
 | 
				
			||||||
 | 
					 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 | 
				
			||||||
 | 
					 * USA.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <atomic>
 | 
					 | 
				
			||||||
#include <kodi/addon-instance/PVR.h>
 | 
					 | 
				
			||||||
#include <thread>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "p8-platform/threads/threads.h"
 | 
				
			||||||
 | 
					#include "p8-platform/util/StdString.h"
 | 
				
			||||||
 | 
					#include "client.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct OctonetEpgEntry
 | 
					struct OctonetEpgEntry
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int64_t channelId;
 | 
						int64_t channelId;
 | 
				
			||||||
  time_t start;
 | 
						time_t start;
 | 
				
			||||||
  time_t end;
 | 
						time_t end;
 | 
				
			||||||
  int id;
 | 
						int id;
 | 
				
			||||||
  std::string title;
 | 
						std::string title;
 | 
				
			||||||
  std::string subtitle;
 | 
						std::string subtitle;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct OctonetChannel
 | 
					struct OctonetChannel
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int64_t nativeId;
 | 
						int64_t nativeId;
 | 
				
			||||||
  std::string name;
 | 
						std::string name;
 | 
				
			||||||
  std::string url;
 | 
						std::string url;
 | 
				
			||||||
  bool radio;
 | 
						bool radio;
 | 
				
			||||||
  int id;
 | 
						int id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<OctonetEpgEntry> epg;
 | 
						std::vector<OctonetEpgEntry> epg;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct OctonetGroup
 | 
					struct OctonetGroup
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  std::string name;
 | 
						std::string name;
 | 
				
			||||||
  bool radio;
 | 
						bool radio;
 | 
				
			||||||
  std::vector<int> members;
 | 
						std::vector<int> members;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ATTRIBUTE_HIDDEN OctonetData : public kodi::addon::CInstancePVRClient
 | 
					class OctonetData : public P8PLATFORM::CThread
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
						public:
 | 
				
			||||||
  OctonetData(const std::string& octonetAddress,
 | 
							OctonetData(void);
 | 
				
			||||||
              KODI_HANDLE instance,
 | 
							virtual ~OctonetData(void);
 | 
				
			||||||
              const std::string& kodiVersion);
 | 
					 | 
				
			||||||
  ~OctonetData() override;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PVR_ERROR GetCapabilities(kodi::addon::PVRCapabilities& capabilities) override;
 | 
							virtual int getChannelCount(void);
 | 
				
			||||||
  PVR_ERROR GetBackendName(std::string& name) override;
 | 
							virtual PVR_ERROR getChannels(ADDON_HANDLE handle, bool bRadio);
 | 
				
			||||||
  PVR_ERROR GetBackendVersion(std::string& version) override;
 | 
					 | 
				
			||||||
  PVR_ERROR GetConnectionString(std::string& connection) override;
 | 
					 | 
				
			||||||
  PVR_ERROR GetBackendHostname(std::string& hostname) override;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PVR_ERROR OnSystemSleep() override;
 | 
							virtual int getGroupCount(void);
 | 
				
			||||||
  PVR_ERROR OnSystemWake() override;
 | 
							virtual PVR_ERROR getGroups(ADDON_HANDLE handle, bool bRadio);
 | 
				
			||||||
 | 
							virtual PVR_ERROR getGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PVR_ERROR GetChannelsAmount(int& amount) override;
 | 
							virtual PVR_ERROR getEPG(ADDON_HANDLE handle, const PVR_CHANNEL &channel, time_t start, time_t end);
 | 
				
			||||||
  PVR_ERROR GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results) override;
 | 
							const std::string& getUrl(int id) const;
 | 
				
			||||||
 | 
							const std::string& getName(int id) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PVR_ERROR GetChannelGroupsAmount(int& amount) override;
 | 
						protected:
 | 
				
			||||||
  PVR_ERROR GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& results) override;
 | 
							virtual bool loadChannelList(void);
 | 
				
			||||||
  PVR_ERROR GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group,
 | 
							virtual bool loadEPG(void);
 | 
				
			||||||
                                   kodi::addon::PVRChannelGroupMembersResultSet& results) override;
 | 
							virtual OctonetGroup* findGroup(const std::string &name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PVR_ERROR GetEPGForChannel(int channelUid,
 | 
							virtual void *Process(void);
 | 
				
			||||||
                             time_t start,
 | 
					 | 
				
			||||||
                             time_t end,
 | 
					 | 
				
			||||||
                             kodi::addon::PVREPGTagsResultSet& results) override;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool OpenLiveStream(const kodi::addon::PVRChannel& channelinfo) override;
 | 
							OctonetChannel* findChannel(int64_t nativeId);
 | 
				
			||||||
  int ReadLiveStream(unsigned char* buffer, unsigned int size) override;
 | 
							time_t parseDateTime(std::string date);
 | 
				
			||||||
  void CloseLiveStream() override;
 | 
							int64_t parseID(std::string id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
						private:
 | 
				
			||||||
  void Process();
 | 
							std::string serverAddress;
 | 
				
			||||||
 | 
							std::vector<OctonetChannel> channels;
 | 
				
			||||||
 | 
							std::vector<OctonetGroup> groups;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const std::string& GetUrl(int id) const;
 | 
							time_t lastEpgLoad;
 | 
				
			||||||
  const std::string& GetName(int id) const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool LoadChannelList(void);
 | 
					 | 
				
			||||||
  bool LoadEPG(void);
 | 
					 | 
				
			||||||
  OctonetGroup* FindGroup(const std::string& name);
 | 
					 | 
				
			||||||
  OctonetChannel* FindChannel(int64_t nativeId);
 | 
					 | 
				
			||||||
  time_t ParseDateTime(std::string date);
 | 
					 | 
				
			||||||
  int64_t ParseID(std::string id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
  std::string m_serverAddress;
 | 
					 | 
				
			||||||
  std::vector<OctonetChannel> m_channels;
 | 
					 | 
				
			||||||
  std::vector<OctonetGroup> m_groups;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  time_t m_lastEpgLoad;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::atomic<bool> m_running = {false};
 | 
					 | 
				
			||||||
  std::thread m_thread;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										483
									
								
								src/Socket.cpp
									
									
									
									
									
								
							
							
						
						
									
										483
									
								
								src/Socket.cpp
									
									
									
									
									
								
							@@ -1,18 +1,30 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Copyright (C) 2005-2020 Team Kodi
 | 
					 *      Copyright (C) 2005-2011 Team XBMC
 | 
				
			||||||
 *  https://kodi.tv
 | 
					 *      http://www.xbmc.org
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This program 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 2 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  SPDX-License-Identifier: GPL-2.0-or-later
 | 
					 | 
				
			||||||
 *  See LICENSE.md for more information.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					#include "libXBMC_addon.h"
 | 
				
			||||||
#include "Socket.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <cstdio>
 | 
					 | 
				
			||||||
#include <kodi/General.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include "p8-platform/os.h"
 | 
				
			||||||
 | 
					#include "client.h"
 | 
				
			||||||
 | 
					#include "Socket.h"
 | 
				
			||||||
 | 
					#include <cstdio>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					using namespace std;
 | 
				
			||||||
 | 
					using namespace ADDON;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OCTO
 | 
					namespace OCTO
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -20,31 +32,28 @@ namespace OCTO
 | 
				
			|||||||
/* Master defines for client control */
 | 
					/* Master defines for client control */
 | 
				
			||||||
#define RECEIVE_TIMEOUT 6 //sec
 | 
					#define RECEIVE_TIMEOUT 6 //sec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Socket::Socket(const enum SocketFamily family,
 | 
					Socket::Socket(const enum SocketFamily family, const enum SocketDomain domain, const enum SocketType type, const enum SocketProtocol protocol)
 | 
				
			||||||
               const enum SocketDomain domain,
 | 
					 | 
				
			||||||
               const enum SocketType type,
 | 
					 | 
				
			||||||
               const enum SocketProtocol protocol)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  m_sd = INVALID_SOCKET;
 | 
					  _sd = INVALID_SOCKET;
 | 
				
			||||||
  m_family = family;
 | 
					  _family = family;
 | 
				
			||||||
  m_domain = domain;
 | 
					  _domain = domain;
 | 
				
			||||||
  m_type = type;
 | 
					  _type = type;
 | 
				
			||||||
  m_protocol = protocol;
 | 
					  _protocol = protocol;
 | 
				
			||||||
  m_port = 0;
 | 
					  _port = 0;
 | 
				
			||||||
  memset(&m_sockaddr, 0, sizeof(m_sockaddr));
 | 
					  memset (&_sockaddr, 0, sizeof( _sockaddr ) );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Socket::Socket()
 | 
					Socket::Socket()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  // Default constructor, default settings
 | 
					  // Default constructor, default settings
 | 
				
			||||||
  m_sd = INVALID_SOCKET;
 | 
					  _sd = INVALID_SOCKET;
 | 
				
			||||||
  m_family = af_inet;
 | 
					  _family = af_inet;
 | 
				
			||||||
  m_domain = pf_inet;
 | 
					  _domain = pf_inet;
 | 
				
			||||||
  m_type = sock_stream;
 | 
					  _type = sock_stream;
 | 
				
			||||||
  m_protocol = tcp;
 | 
					  _protocol = tcp;
 | 
				
			||||||
  m_port = 0;
 | 
					  _port = 0;
 | 
				
			||||||
  memset(&m_sockaddr, 0, sizeof(m_sockaddr));
 | 
					  memset (&_sockaddr, 0, sizeof( _sockaddr ) );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -56,7 +65,7 @@ Socket::~Socket()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool Socket::setHostname(const std::string& host)
 | 
					bool Socket::setHostname(const std::string& host)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  m_hostname = host;
 | 
					  _hostname = host;
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,9 +73,9 @@ bool Socket::close()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  if (is_valid())
 | 
					  if (is_valid())
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (m_sd != SOCKET_ERROR)
 | 
					    if (_sd != SOCKET_ERROR)
 | 
				
			||||||
      closesocket(m_sd);
 | 
					      closesocket(_sd);
 | 
				
			||||||
    m_sd = INVALID_SOCKET;
 | 
					    _sd = INVALID_SOCKET;
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return false;
 | 
					  return false;
 | 
				
			||||||
@@ -76,7 +85,7 @@ bool Socket::create()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  close();
 | 
					  close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!osInit())
 | 
					  if(!osInit())
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -85,25 +94,25 @@ bool Socket::create()
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Socket::bind(const unsigned short port)
 | 
					bool Socket::bind ( const unsigned short port )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (is_valid())
 | 
					  if (is_valid())
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    close();
 | 
					      close();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  m_sd = socket(m_family, m_type, m_protocol);
 | 
					  _sd = socket(_family, _type, _protocol);
 | 
				
			||||||
  m_port = port;
 | 
					  _port = port;
 | 
				
			||||||
  m_sockaddr.sin_family = (sa_family_t)m_family;
 | 
					  _sockaddr.sin_family = (sa_family_t) _family;
 | 
				
			||||||
  m_sockaddr.sin_addr.s_addr = INADDR_ANY; //listen to all
 | 
					  _sockaddr.sin_addr.s_addr = INADDR_ANY;  //listen to all
 | 
				
			||||||
  m_sockaddr.sin_port = htons(m_port);
 | 
					  _sockaddr.sin_port = htons( _port );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int bind_return = ::bind(m_sd, (sockaddr*)(&m_sockaddr), sizeof(m_sockaddr));
 | 
					  int bind_return = ::bind(_sd, (sockaddr*)(&_sockaddr), sizeof(_sockaddr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (bind_return == -1)
 | 
					  if ( bind_return == -1 )
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    errormessage(getLastError(), "Socket::bind");
 | 
					    errormessage( getLastError(), "Socket::bind" );
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -119,13 +128,13 @@ bool Socket::listen() const
 | 
				
			|||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int listen_return = ::listen(m_sd, SOMAXCONN);
 | 
					  int listen_return = ::listen (_sd, SOMAXCONN);
 | 
				
			||||||
  //This is defined as 5 in winsock.h, and 0x7FFFFFFF in winsock2.h.
 | 
					  //This is defined as 5 in winsock.h, and 0x7FFFFFFF in winsock2.h.
 | 
				
			||||||
  //linux 128//MAXCONNECTIONS =1
 | 
					  //linux 128//MAXCONNECTIONS =1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (listen_return == -1)
 | 
					  if (listen_return == -1)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    errormessage(getLastError(), "Socket::listen");
 | 
					    errormessage( getLastError(), "Socket::listen" );
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -133,24 +142,23 @@ bool Socket::listen() const
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Socket::accept(Socket& new_socket) const
 | 
					bool Socket::accept ( Socket& new_socket ) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (!is_valid())
 | 
					  if (!is_valid())
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  socklen_t addr_length = sizeof(m_sockaddr);
 | 
					  socklen_t addr_length = sizeof( _sockaddr );
 | 
				
			||||||
  new_socket.m_sd =
 | 
					  new_socket._sd = ::accept(_sd, const_cast<sockaddr*>( (const sockaddr*) &_sockaddr), &addr_length );
 | 
				
			||||||
      ::accept(m_sd, const_cast<sockaddr*>((const sockaddr*)&m_sockaddr), &addr_length);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TARGET_WINDOWS
 | 
					#ifdef TARGET_WINDOWS
 | 
				
			||||||
  if (new_socket.m_sd == INVALID_SOCKET)
 | 
					  if (new_socket._sd == INVALID_SOCKET)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  if (new_socket.m_sd <= 0)
 | 
					  if (new_socket._sd <= 0)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    errormessage(getLastError(), "Socket::accept");
 | 
					    errormessage( getLastError(), "Socket::accept" );
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -158,17 +166,17 @@ bool Socket::accept(Socket& new_socket) const
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int Socket::send(const std::string& data)
 | 
					int Socket::send ( const std::string& data )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  return Socket::send((const char*)data.c_str(), (const unsigned int)data.size());
 | 
					  return Socket::send( (const char*) data.c_str(), (const unsigned int) data.size());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int Socket::send(const char* data, const unsigned int len)
 | 
					int Socket::send ( const char* data, const unsigned int len )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  fd_set set_w, set_e;
 | 
					  fd_set set_w, set_e;
 | 
				
			||||||
  struct timeval tv;
 | 
					  struct timeval tv;
 | 
				
			||||||
  int result;
 | 
					  int  result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!is_valid())
 | 
					  if (!is_valid())
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@@ -176,35 +184,35 @@ int Socket::send(const char* data, const unsigned int len)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // fill with new data
 | 
					  // fill with new data
 | 
				
			||||||
  tv.tv_sec = 0;
 | 
					  tv.tv_sec  = 0;
 | 
				
			||||||
  tv.tv_usec = 0;
 | 
					  tv.tv_usec = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  FD_ZERO(&set_w);
 | 
					  FD_ZERO(&set_w);
 | 
				
			||||||
  FD_ZERO(&set_e);
 | 
					  FD_ZERO(&set_e);
 | 
				
			||||||
  FD_SET(m_sd, &set_w);
 | 
					  FD_SET(_sd, &set_w);
 | 
				
			||||||
  FD_SET(m_sd, &set_e);
 | 
					  FD_SET(_sd, &set_e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  result = select(FD_SETSIZE, &set_w, nullptr, &set_e, &tv);
 | 
					  result = select(FD_SETSIZE, &set_w, NULL, &set_e, &tv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (result < 0)
 | 
					  if (result < 0)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    kodi::Log(ADDON_LOG_ERROR, "Socket::send  - select failed");
 | 
					    kodi->Log(LOG_ERROR, "Socket::send  - select failed");
 | 
				
			||||||
    close();
 | 
					    close();
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (FD_ISSET(m_sd, &set_w))
 | 
					  if (FD_ISSET(_sd, &set_w))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    kodi::Log(ADDON_LOG_ERROR, "Socket::send  - failed to send data");
 | 
					    kodi->Log(LOG_ERROR, "Socket::send  - failed to send data");
 | 
				
			||||||
    close();
 | 
					    close();
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int status = ::send(m_sd, data, len, 0);
 | 
					  int status = ::send(_sd, data, len, 0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (status == -1)
 | 
					  if (status == -1)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    errormessage(getLastError(), "Socket::send");
 | 
					    errormessage( getLastError(), "Socket::send");
 | 
				
			||||||
    kodi::Log(ADDON_LOG_ERROR, "Socket::send  - failed to send data");
 | 
					    kodi->Log(LOG_ERROR, "Socket::send  - failed to send data");
 | 
				
			||||||
    close();
 | 
					    close();
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -212,31 +220,31 @@ int Socket::send(const char* data, const unsigned int len)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int Socket::sendto(const char* data, unsigned int size, bool sendcompletebuffer)
 | 
					int Socket::sendto ( const char* data, unsigned int size, bool sendcompletebuffer)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int sentbytes = 0;
 | 
					  int sentbytes = 0;
 | 
				
			||||||
  int i;
 | 
					  int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  do
 | 
					  do
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    i = ::sendto(m_sd, data, size, 0, (const struct sockaddr*)&m_sockaddr, sizeof(m_sockaddr));
 | 
					    i = ::sendto(_sd, data, size, 0, (const struct sockaddr*) &_sockaddr, sizeof( _sockaddr ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (i <= 0)
 | 
					    if (i <= 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      errormessage(getLastError(), "Socket::sendto");
 | 
					      errormessage( getLastError(), "Socket::sendto");
 | 
				
			||||||
      osCleanup();
 | 
					      osCleanup();
 | 
				
			||||||
      return i;
 | 
					      return i;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    sentbytes += i;
 | 
					    sentbytes += i;
 | 
				
			||||||
  } while ((sentbytes < (int)size) && (sendcompletebuffer == true));
 | 
					  } while ( (sentbytes < (int) size) && (sendcompletebuffer == true));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return i;
 | 
					  return i;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int Socket::receive(std::string& data, unsigned int minpacketsize) const
 | 
					int Socket::receive ( std::string& data, unsigned int minpacketsize ) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  char* buf = nullptr;
 | 
					  char * buf = NULL;
 | 
				
			||||||
  int status = 0;
 | 
					  int status = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!is_valid())
 | 
					  if (!is_valid())
 | 
				
			||||||
@@ -244,10 +252,10 @@ int Socket::receive(std::string& data, unsigned int minpacketsize) const
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  buf = new char[minpacketsize + 1];
 | 
					  buf = new char [ minpacketsize + 1 ];
 | 
				
			||||||
  memset(buf, 0, minpacketsize + 1);
 | 
					  memset ( buf, 0, minpacketsize + 1 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  status = receive(buf, minpacketsize, minpacketsize);
 | 
					  status = receive( buf, minpacketsize, minpacketsize );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  data = buf;
 | 
					  data = buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -257,12 +265,12 @@ int Socket::receive(std::string& data, unsigned int minpacketsize) const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//Receive until error or \n
 | 
					//Receive until error or \n
 | 
				
			||||||
bool Socket::ReadLine(string& line)
 | 
					bool Socket::ReadLine (string& line)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  fd_set set_r, set_e;
 | 
					  fd_set         set_r, set_e;
 | 
				
			||||||
  timeval timeout;
 | 
					  timeval        timeout;
 | 
				
			||||||
  int retries = 6;
 | 
					  int            retries = 6;
 | 
				
			||||||
  char buffer[2048];
 | 
					  char           buffer[2048];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!is_valid())
 | 
					  if (!is_valid())
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
@@ -276,20 +284,20 @@ bool Socket::ReadLine(string& line)
 | 
				
			|||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    timeout.tv_sec = RECEIVE_TIMEOUT;
 | 
					    timeout.tv_sec  = RECEIVE_TIMEOUT;
 | 
				
			||||||
    timeout.tv_usec = 0;
 | 
					    timeout.tv_usec = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // fill with new data
 | 
					    // fill with new data
 | 
				
			||||||
    FD_ZERO(&set_r);
 | 
					    FD_ZERO(&set_r);
 | 
				
			||||||
    FD_ZERO(&set_e);
 | 
					    FD_ZERO(&set_e);
 | 
				
			||||||
    FD_SET(m_sd, &set_r);
 | 
					    FD_SET(_sd, &set_r);
 | 
				
			||||||
    FD_SET(m_sd, &set_e);
 | 
					    FD_SET(_sd, &set_e);
 | 
				
			||||||
    int result = select(FD_SETSIZE, &set_r, nullptr, &set_e, &timeout);
 | 
					    int result = select(FD_SETSIZE, &set_r, NULL, &set_e, &timeout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (result < 0)
 | 
					    if (result < 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      kodi::Log(ADDON_LOG_DEBUG, "%s: select failed", __func__);
 | 
					      kodi->Log(LOG_DEBUG, "%s: select failed", __FUNCTION__);
 | 
				
			||||||
      errormessage(getLastError(), __func__);
 | 
					      errormessage(getLastError(), __FUNCTION__);
 | 
				
			||||||
      close();
 | 
					      close();
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -298,24 +306,20 @@ bool Socket::ReadLine(string& line)
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
      if (retries != 0)
 | 
					      if (retries != 0)
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        kodi::Log(ADDON_LOG_DEBUG, "%s: timeout waiting for response, retrying... (%i)", __func__,
 | 
					         kodi->Log(LOG_DEBUG, "%s: timeout waiting for response, retrying... (%i)", __FUNCTION__, retries);
 | 
				
			||||||
                  retries);
 | 
					         retries--;
 | 
				
			||||||
        retries--;
 | 
					 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      }
 | 
					      } else {
 | 
				
			||||||
      else
 | 
					         kodi->Log(LOG_DEBUG, "%s: timeout waiting for response. Aborting after 10 retries.", __FUNCTION__);
 | 
				
			||||||
      {
 | 
					         return false;
 | 
				
			||||||
        kodi::Log(ADDON_LOG_DEBUG, "%s: timeout waiting for response. Aborting after 10 retries.",
 | 
					 | 
				
			||||||
                  __func__);
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    result = recv(m_sd, buffer, sizeof(buffer) - 1, 0);
 | 
					    result = recv(_sd, buffer, sizeof(buffer) - 1, 0);
 | 
				
			||||||
    if (result < 0)
 | 
					    if (result < 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      kodi::Log(ADDON_LOG_DEBUG, "%s: recv failed", __func__);
 | 
					      kodi->Log(LOG_DEBUG, "%s: recv failed", __FUNCTION__);
 | 
				
			||||||
      errormessage(getLastError(), __func__);
 | 
					      errormessage(getLastError(), __FUNCTION__);
 | 
				
			||||||
      close();
 | 
					      close();
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -328,41 +332,39 @@ bool Socket::ReadLine(string& line)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int Socket::receive(std::string& data) const
 | 
					int Socket::receive ( std::string& data) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  char buf[MAXRECV + 1];
 | 
					  char buf[MAXRECV + 1];
 | 
				
			||||||
  int status = 0;
 | 
					  int status = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!is_valid())
 | 
					  if ( !is_valid() )
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  memset(buf, 0, MAXRECV + 1);
 | 
					  memset ( buf, 0, MAXRECV + 1 );
 | 
				
			||||||
  status = receive(buf, MAXRECV, 0);
 | 
					  status = receive( buf, MAXRECV, 0 );
 | 
				
			||||||
  data = buf;
 | 
					  data = buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return status;
 | 
					  return status;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int Socket::receive(char* data,
 | 
					int Socket::receive ( char* data, const unsigned int buffersize, const unsigned int minpacketsize ) const
 | 
				
			||||||
                    const unsigned int buffersize,
 | 
					 | 
				
			||||||
                    const unsigned int minpacketsize) const
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  unsigned int receivedsize = 0;
 | 
					  unsigned int receivedsize = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!is_valid())
 | 
					  if ( !is_valid() )
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while ((receivedsize <= minpacketsize) && (receivedsize < buffersize))
 | 
					  while ( (receivedsize <= minpacketsize) && (receivedsize < buffersize) )
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    int status = ::recv(m_sd, data + receivedsize, (buffersize - receivedsize), 0);
 | 
					    int status = ::recv(_sd, data+receivedsize, (buffersize - receivedsize), 0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (status == SOCKET_ERROR)
 | 
					    if ( status == SOCKET_ERROR )
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      errormessage(getLastError(), "Socket::receive");
 | 
					      errormessage( getLastError(), "Socket::receive" );
 | 
				
			||||||
      return status;
 | 
					      return status;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -373,38 +375,35 @@ int Socket::receive(char* data,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int Socket::recvfrom(char* data,
 | 
					int Socket::recvfrom ( char* data, const int buffersize, struct sockaddr* from, socklen_t* fromlen) const
 | 
				
			||||||
                     const int buffersize,
 | 
					 | 
				
			||||||
                     struct sockaddr* from,
 | 
					 | 
				
			||||||
                     socklen_t* fromlen) const
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int status = ::recvfrom(m_sd, data, buffersize, 0, from, fromlen);
 | 
					  int status = ::recvfrom(_sd, data, buffersize, 0, from, fromlen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return status;
 | 
					  return status;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Socket::connect(const std::string& host, const unsigned short port)
 | 
					bool Socket::connect ( const std::string& host, const unsigned short port )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  close();
 | 
					  close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!setHostname(host))
 | 
					  if ( !setHostname( host ) )
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    kodi::Log(ADDON_LOG_ERROR, "Socket::setHostname(%s) failed.\n", host.c_str());
 | 
					    kodi->Log(LOG_ERROR, "Socket::setHostname(%s) failed.\n", host.c_str());
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  m_port = port;
 | 
					  _port = port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  char strPort[15];
 | 
					  char strPort[15];
 | 
				
			||||||
  snprintf(strPort, 15, "%hu", port);
 | 
					  snprintf(strPort, 15, "%hu", port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct addrinfo hints;
 | 
					  struct addrinfo hints;
 | 
				
			||||||
  struct addrinfo* result = nullptr;
 | 
					  struct addrinfo* result = NULL;
 | 
				
			||||||
  struct addrinfo* address = nullptr;
 | 
					  struct addrinfo *address = NULL;
 | 
				
			||||||
  memset(&hints, 0, sizeof(hints));
 | 
					  memset(&hints, 0, sizeof(hints));
 | 
				
			||||||
  hints.ai_family = m_family;
 | 
					  hints.ai_family = _family;
 | 
				
			||||||
  hints.ai_socktype = m_type;
 | 
					  hints.ai_socktype = _type;
 | 
				
			||||||
  hints.ai_protocol = m_protocol;
 | 
					  hints.ai_protocol = _protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int retval = getaddrinfo(host.c_str(), strPort, &hints, &result);
 | 
					  int retval = getaddrinfo(host.c_str(), strPort, &hints, &result);
 | 
				
			||||||
  if (retval != 0)
 | 
					  if (retval != 0)
 | 
				
			||||||
@@ -413,18 +412,18 @@ bool Socket::connect(const std::string& host, const unsigned short port)
 | 
				
			|||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (address = result; address != nullptr; address = address->ai_next)
 | 
					  for (address = result; address != NULL; address = address->ai_next)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    // Create the socket
 | 
					    // Create the socket
 | 
				
			||||||
    m_sd = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
 | 
					    _sd = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (m_sd == INVALID_SOCKET)
 | 
					    if (_sd == INVALID_SOCKET)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      errormessage(getLastError(), "Socket::create");
 | 
					      errormessage(getLastError(), "Socket::create");
 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int status = ::connect(m_sd, address->ai_addr, address->ai_addrlen);
 | 
					    int status = ::connect(_sd, address->ai_addr, address->ai_addrlen);
 | 
				
			||||||
    if (status == SOCKET_ERROR)
 | 
					    if (status == SOCKET_ERROR)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      close();
 | 
					      close();
 | 
				
			||||||
@@ -437,9 +436,9 @@ bool Socket::connect(const std::string& host, const unsigned short port)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  freeaddrinfo(result);
 | 
					  freeaddrinfo(result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (address == nullptr)
 | 
					  if (address == NULL)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    kodi::Log(ADDON_LOG_ERROR, "Socket::connect %s:%u\n", host.c_str(), port);
 | 
					    kodi->Log(LOG_ERROR, "Socket::connect %s:%u\n", host.c_str(), port);
 | 
				
			||||||
    errormessage(getLastError(), "Socket::connect");
 | 
					    errormessage(getLastError(), "Socket::connect");
 | 
				
			||||||
    close();
 | 
					    close();
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
@@ -450,124 +449,123 @@ bool Socket::connect(const std::string& host, const unsigned short port)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool Socket::reconnect()
 | 
					bool Socket::reconnect()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (is_valid())
 | 
					  if ( is_valid() )
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return connect(m_hostname, m_port);
 | 
					  return connect(_hostname, _port);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Socket::is_valid() const
 | 
					bool Socket::is_valid() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  return (m_sd != INVALID_SOCKET);
 | 
					  return (_sd != INVALID_SOCKET);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(TARGET_WINDOWS)
 | 
					#if defined(TARGET_WINDOWS)
 | 
				
			||||||
bool Socket::set_non_blocking(const bool b)
 | 
					bool Socket::set_non_blocking ( const bool b )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  u_long iMode;
 | 
					  u_long iMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (b)
 | 
					  if ( b )
 | 
				
			||||||
    iMode = 1; // enable non_blocking
 | 
					    iMode = 1;  // enable non_blocking
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    iMode = 0; // disable non_blocking
 | 
					    iMode = 0;  // disable non_blocking
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (ioctlsocket(m_sd, FIONBIO, &iMode) == -1)
 | 
					  if (ioctlsocket(_sd, FIONBIO, &iMode) == -1)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    kodi::Log(ADDON_LOG_ERROR, "Socket::set_non_blocking - Can't set socket condition to: %i",
 | 
					    kodi->Log(LOG_ERROR, "Socket::set_non_blocking - Can't set socket condition to: %i", iMode);
 | 
				
			||||||
              iMode);
 | 
					 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Socket::errormessage(int errnum, const char* functionname) const
 | 
					void Socket::errormessage( int errnum, const char* functionname) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  const char* errmsg = nullptr;
 | 
					  const char* errmsg = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  switch (errnum)
 | 
					  switch (errnum)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    case WSANOTINITIALISED:
 | 
					  case WSANOTINITIALISED:
 | 
				
			||||||
      errmsg = "A successful WSAStartup call must occur before using this function.";
 | 
					    errmsg = "A successful WSAStartup call must occur before using this function.";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAENETDOWN:
 | 
					  case WSAENETDOWN:
 | 
				
			||||||
      errmsg = "The network subsystem or the associated service provider has failed";
 | 
					    errmsg = "The network subsystem or the associated service provider has failed";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSA_NOT_ENOUGH_MEMORY:
 | 
					  case WSA_NOT_ENOUGH_MEMORY:
 | 
				
			||||||
      errmsg = "Insufficient memory available";
 | 
					    errmsg = "Insufficient memory available";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSA_INVALID_PARAMETER:
 | 
					  case WSA_INVALID_PARAMETER:
 | 
				
			||||||
      errmsg = "One or more parameters are invalid";
 | 
					    errmsg = "One or more parameters are invalid";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSA_OPERATION_ABORTED:
 | 
					  case WSA_OPERATION_ABORTED:
 | 
				
			||||||
      errmsg = "Overlapped operation aborted";
 | 
					    errmsg = "Overlapped operation aborted";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEINTR:
 | 
					  case WSAEINTR:
 | 
				
			||||||
      errmsg = "Interrupted function call";
 | 
					    errmsg = "Interrupted function call";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEBADF:
 | 
					  case WSAEBADF:
 | 
				
			||||||
      errmsg = "File handle is not valid";
 | 
					    errmsg = "File handle is not valid";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEACCES:
 | 
					  case WSAEACCES:
 | 
				
			||||||
      errmsg = "Permission denied";
 | 
					    errmsg = "Permission denied";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEFAULT:
 | 
					  case WSAEFAULT:
 | 
				
			||||||
      errmsg = "Bad address";
 | 
					    errmsg = "Bad address";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEINVAL:
 | 
					  case WSAEINVAL:
 | 
				
			||||||
      errmsg = "Invalid argument";
 | 
					    errmsg = "Invalid argument";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAENOTSOCK:
 | 
					  case WSAENOTSOCK:
 | 
				
			||||||
      errmsg = "Socket operation on nonsocket";
 | 
					    errmsg = "Socket operation on nonsocket";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEDESTADDRREQ:
 | 
					  case WSAEDESTADDRREQ:
 | 
				
			||||||
      errmsg = "Destination address required";
 | 
					    errmsg = "Destination address required";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEMSGSIZE:
 | 
					  case WSAEMSGSIZE:
 | 
				
			||||||
      errmsg = "Message too long";
 | 
					    errmsg = "Message too long";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEPROTOTYPE:
 | 
					  case WSAEPROTOTYPE:
 | 
				
			||||||
      errmsg = "Protocol wrong type for socket";
 | 
					    errmsg = "Protocol wrong type for socket";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAENOPROTOOPT:
 | 
					  case WSAENOPROTOOPT:
 | 
				
			||||||
      errmsg = "Bad protocol option";
 | 
					    errmsg = "Bad protocol option";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEPFNOSUPPORT:
 | 
					  case WSAEPFNOSUPPORT:
 | 
				
			||||||
      errmsg = "Protocol family not supported";
 | 
					    errmsg = "Protocol family not supported";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEAFNOSUPPORT:
 | 
					  case WSAEAFNOSUPPORT:
 | 
				
			||||||
      errmsg = "Address family not supported by protocol family";
 | 
					    errmsg = "Address family not supported by protocol family";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEADDRINUSE:
 | 
					  case WSAEADDRINUSE:
 | 
				
			||||||
      errmsg = "Address already in use";
 | 
					    errmsg = "Address already in use";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAECONNRESET:
 | 
					  case WSAECONNRESET:
 | 
				
			||||||
      errmsg = "Connection reset by peer";
 | 
					    errmsg = "Connection reset by peer";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAHOST_NOT_FOUND:
 | 
					  case WSAHOST_NOT_FOUND:
 | 
				
			||||||
      errmsg = "Authoritative answer host not found";
 | 
					    errmsg = "Authoritative answer host not found";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSATRY_AGAIN:
 | 
					  case WSATRY_AGAIN:
 | 
				
			||||||
      errmsg = "Nonauthoritative host not found, or server failure";
 | 
					    errmsg = "Nonauthoritative host not found, or server failure";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAEISCONN:
 | 
					  case WSAEISCONN:
 | 
				
			||||||
      errmsg = "Socket is already connected";
 | 
					    errmsg = "Socket is already connected";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAETIMEDOUT:
 | 
					  case WSAETIMEDOUT:
 | 
				
			||||||
      errmsg = "Connection timed out";
 | 
					    errmsg = "Connection timed out";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSAECONNREFUSED:
 | 
					  case WSAECONNREFUSED:
 | 
				
			||||||
      errmsg = "Connection refused";
 | 
					    errmsg = "Connection refused";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    case WSANO_DATA:
 | 
					  case WSANO_DATA:
 | 
				
			||||||
      errmsg = "Valid name, no data record of requested type";
 | 
					    errmsg = "Valid name, no data record of requested type";
 | 
				
			||||||
      break;
 | 
					    break;
 | 
				
			||||||
    default:
 | 
					  default:
 | 
				
			||||||
      errmsg = "WSA Error";
 | 
					    errmsg = "WSA Error";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  kodi::Log(ADDON_LOG_ERROR, "%s: (Winsock error=%i) %s\n", functionname, errnum, errmsg);
 | 
					  kodi->Log(LOG_ERROR, "%s: (Winsock error=%i) %s\n", functionname, errnum, errmsg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int Socket::getLastError() const
 | 
					int Socket::getLastError() const
 | 
				
			||||||
@@ -581,15 +579,15 @@ bool Socket::osInit()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  win_usage_count++;
 | 
					  win_usage_count++;
 | 
				
			||||||
  // initialize winsock:
 | 
					  // initialize winsock:
 | 
				
			||||||
  if (WSAStartup(MAKEWORD(2, 2), &m_wsaData) != 0)
 | 
					  if (WSAStartup(MAKEWORD(2,2),&_wsaData) != 0)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  WORD wVersionRequested = MAKEWORD(2, 2);
 | 
					  WORD wVersionRequested = MAKEWORD(2,2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // check version
 | 
					  // check version
 | 
				
			||||||
  if (m_wsaData.wVersion != wVersionRequested)
 | 
					  if (_wsaData.wVersion != wVersionRequested)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -600,42 +598,42 @@ bool Socket::osInit()
 | 
				
			|||||||
void Socket::osCleanup()
 | 
					void Socket::osCleanup()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  win_usage_count--;
 | 
					  win_usage_count--;
 | 
				
			||||||
  if (win_usage_count == 0)
 | 
					  if(win_usage_count == 0)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    WSACleanup();
 | 
					    WSACleanup();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#elif defined TARGET_LINUX || defined TARGET_DARWIN || defined TARGET_FREEBSD
 | 
					#elif defined TARGET_LINUX || defined TARGET_DARWIN || defined TARGET_FREEBSD
 | 
				
			||||||
bool Socket::set_non_blocking(const bool b)
 | 
					bool Socket::set_non_blocking ( const bool b )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int opts;
 | 
					  int opts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  opts = fcntl(m_sd, F_GETFL);
 | 
					  opts = fcntl(_sd, F_GETFL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (opts < 0)
 | 
					  if ( opts < 0 )
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (b)
 | 
					  if ( b )
 | 
				
			||||||
    opts = (opts | O_NONBLOCK);
 | 
					    opts = ( opts | O_NONBLOCK );
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    opts = (opts & ~O_NONBLOCK);
 | 
					    opts = ( opts & ~O_NONBLOCK );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (fcntl(m_sd, F_SETFL, opts) == -1)
 | 
					  if(fcntl (_sd , F_SETFL, opts) == -1)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    kodi::Log(ADDON_LOG_ERROR, "Socket::set_non_blocking - Can't set socket flags to: %i", opts);
 | 
					    kodi->Log(LOG_ERROR, "Socket::set_non_blocking - Can't set socket flags to: %i", opts);
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Socket::errormessage(int errnum, const char* functionname) const
 | 
					void Socket::errormessage( int errnum, const char* functionname) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  const char* errmsg = nullptr;
 | 
					  const char* errmsg = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  switch (errnum)
 | 
					  switch ( errnum )
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    case EAGAIN: //same as EWOULDBLOCK
 | 
					    case EAGAIN: //same as EWOULDBLOCK
 | 
				
			||||||
      errmsg = "EAGAIN: The socket is marked non-blocking and the requested operation would block";
 | 
					      errmsg = "EAGAIN: The socket is marked non-blocking and the requested operation would block";
 | 
				
			||||||
@@ -662,8 +660,7 @@ void Socket::errormessage(int errnum, const char* functionname) const
 | 
				
			|||||||
      errmsg = "ENOTSOCK: The argument is not a valid socket";
 | 
					      errmsg = "ENOTSOCK: The argument is not a valid socket";
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case EMSGSIZE:
 | 
					    case EMSGSIZE:
 | 
				
			||||||
      errmsg = "EMSGSIZE: The socket requires that message be sent atomically, and the size of the "
 | 
					      errmsg = "EMSGSIZE: The socket requires that message be sent atomically, and the size of the message to be sent made this impossible";
 | 
				
			||||||
               "message to be sent made this impossible";
 | 
					 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ENOBUFS:
 | 
					    case ENOBUFS:
 | 
				
			||||||
      errmsg = "ENOBUFS: The output queue for a network interface was full";
 | 
					      errmsg = "ENOBUFS: The output queue for a network interface was full";
 | 
				
			||||||
@@ -675,8 +672,7 @@ void Socket::errormessage(int errnum, const char* functionname) const
 | 
				
			|||||||
      errmsg = "EPIPE: The local end has been shut down on a connection oriented socket";
 | 
					      errmsg = "EPIPE: The local end has been shut down on a connection oriented socket";
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case EPROTONOSUPPORT:
 | 
					    case EPROTONOSUPPORT:
 | 
				
			||||||
      errmsg = "EPROTONOSUPPORT: The protocol type or the specified protocol is not supported "
 | 
					      errmsg = "EPROTONOSUPPORT: The protocol type or the specified protocol is not supported within this domain";
 | 
				
			||||||
               "within this domain";
 | 
					 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case EAFNOSUPPORT:
 | 
					    case EAFNOSUPPORT:
 | 
				
			||||||
      errmsg = "EAFNOSUPPORT: The implementation does not support the specified address family";
 | 
					      errmsg = "EAFNOSUPPORT: The implementation does not support the specified address family";
 | 
				
			||||||
@@ -688,16 +684,13 @@ void Socket::errormessage(int errnum, const char* functionname) const
 | 
				
			|||||||
      errmsg = "EMFILE: Process file table overflow";
 | 
					      errmsg = "EMFILE: Process file table overflow";
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case EACCES:
 | 
					    case EACCES:
 | 
				
			||||||
      errmsg =
 | 
					      errmsg = "EACCES: Permission to create a socket of the specified type and/or protocol is denied";
 | 
				
			||||||
          "EACCES: Permission to create a socket of the specified type and/or protocol is denied";
 | 
					 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ECONNREFUSED:
 | 
					    case ECONNREFUSED:
 | 
				
			||||||
      errmsg = "ECONNREFUSED: A remote host refused to allow the network connection (typically "
 | 
					      errmsg = "ECONNREFUSED: A remote host refused to allow the network connection (typically because it is not running the requested service)";
 | 
				
			||||||
               "because it is not running the requested service)";
 | 
					 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ENOTCONN:
 | 
					    case ENOTCONN:
 | 
				
			||||||
      errmsg = "ENOTCONN: The socket is associated with a connection-oriented protocol and has not "
 | 
					      errmsg = "ENOTCONN: The socket is associated with a connection-oriented protocol and has not been connected";
 | 
				
			||||||
               "been connected";
 | 
					 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    //case E:
 | 
					    //case E:
 | 
				
			||||||
    //	errmsg = "";
 | 
					    //	errmsg = "";
 | 
				
			||||||
@@ -706,7 +699,7 @@ void Socket::errormessage(int errnum, const char* functionname) const
 | 
				
			|||||||
      break;
 | 
					      break;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  kodi::Log(ADDON_LOG_ERROR, "%s: (errno=%i) %s\n", functionname, errnum, errmsg);
 | 
					  kodi->Log(LOG_ERROR, "%s: (errno=%i) %s\n", functionname, errnum, errmsg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int Socket::getLastError() const
 | 
					int Socket::getLastError() const
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										428
									
								
								src/Socket.h
									
									
									
									
									
								
							
							
						
						
									
										428
									
								
								src/Socket.h
									
									
									
									
									
								
							@@ -1,73 +1,83 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Copyright (C) 2005-2020 Team Kodi
 | 
					 *      Copyright (C) 2005-2011 Team XBMC
 | 
				
			||||||
 *  https://kodi.tv
 | 
					 *      http://www.xbmc.org
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This Program 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 2, or (at your option)
 | 
				
			||||||
 | 
					 *  any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This Program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  SPDX-License-Identifier: GPL-2.0-or-later
 | 
					 | 
				
			||||||
 *  See LICENSE.md for more information.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//Include platform specific datatypes, header files, defines and constants:
 | 
					//Include platform specific datatypes, header files, defines and constants:
 | 
				
			||||||
#if defined TARGET_WINDOWS
 | 
					#if defined TARGET_WINDOWS
 | 
				
			||||||
#define WIN32_LEAN_AND_MEAN // Enable LEAN_AND_MEAN support
 | 
					  #define WIN32_LEAN_AND_MEAN           // Enable LEAN_AND_MEAN support
 | 
				
			||||||
#pragma warning(disable : 4005) // Disable "warning C4005: '_WINSOCKAPI_' : macro redefinition"
 | 
					  #pragma warning(disable:4005) // Disable "warning C4005: '_WINSOCKAPI_' : macro redefinition"
 | 
				
			||||||
#include <WS2tcpip.h>
 | 
					  #include <winsock2.h>
 | 
				
			||||||
#include <winsock2.h>
 | 
					  #include <WS2tcpip.h>
 | 
				
			||||||
#pragma warning(default : 4005)
 | 
					  #pragma warning(default:4005)
 | 
				
			||||||
#include <windows.h>
 | 
					  #include <windows.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef NI_MAXHOST
 | 
					  #ifndef NI_MAXHOST
 | 
				
			||||||
#define NI_MAXHOST 1025
 | 
					    #define NI_MAXHOST 1025
 | 
				
			||||||
#endif
 | 
					  #endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef socklen_t
 | 
					  #ifndef socklen_t
 | 
				
			||||||
typedef int socklen_t;
 | 
					    typedef int socklen_t;
 | 
				
			||||||
#endif
 | 
					  #endif
 | 
				
			||||||
#ifndef ipaddr_t
 | 
					  #ifndef ipaddr_t
 | 
				
			||||||
typedef unsigned long ipaddr_t;
 | 
					    typedef unsigned long ipaddr_t;
 | 
				
			||||||
#endif
 | 
					  #endif
 | 
				
			||||||
#ifndef port_t
 | 
					  #ifndef port_t
 | 
				
			||||||
typedef unsigned short port_t;
 | 
					    typedef unsigned short port_t;
 | 
				
			||||||
#endif
 | 
					  #endif
 | 
				
			||||||
#ifndef sa_family_t
 | 
					  #ifndef sa_family_t
 | 
				
			||||||
#define sa_family_t ADDRESS_FAMILY
 | 
					    #define sa_family_t ADDRESS_FAMILY
 | 
				
			||||||
#endif
 | 
					  #endif
 | 
				
			||||||
#elif defined TARGET_LINUX || defined TARGET_DARWIN || defined TARGET_FREEBSD
 | 
					#elif defined TARGET_LINUX || defined TARGET_DARWIN || defined TARGET_FREEBSD
 | 
				
			||||||
#ifdef SOCKADDR_IN
 | 
					#ifdef SOCKADDR_IN
 | 
				
			||||||
#undef SOCKADDR_IN
 | 
					#undef SOCKADDR_IN
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include <arpa/inet.h> /* for inet_pton */
 | 
					  #include <sys/types.h>     /* for socket,connect */
 | 
				
			||||||
#include <errno.h>
 | 
					  #include <sys/socket.h>    /* for socket,connect */
 | 
				
			||||||
#include <fcntl.h>
 | 
					  #include <sys/un.h>        /* for Unix socket */
 | 
				
			||||||
#include <netdb.h> /* for gethostbyname */
 | 
					  #include <arpa/inet.h>     /* for inet_pton */
 | 
				
			||||||
#include <netinet/in.h> /* for htons */
 | 
					  #include <netdb.h>         /* for gethostbyname */
 | 
				
			||||||
#include <sys/socket.h> /* for socket,connect */
 | 
					  #include <netinet/in.h>    /* for htons */
 | 
				
			||||||
#include <sys/types.h> /* for socket,connect */
 | 
					  #include <unistd.h>        /* for read, write, close */
 | 
				
			||||||
#include <sys/un.h> /* for Unix socket */
 | 
					  #include <errno.h>
 | 
				
			||||||
#include <unistd.h> /* for read, write, close */
 | 
					  #include <fcntl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef int SOCKET;
 | 
					  typedef int SOCKET;
 | 
				
			||||||
typedef sockaddr SOCKADDR;
 | 
					  typedef sockaddr SOCKADDR;
 | 
				
			||||||
typedef sockaddr_in SOCKADDR_IN;
 | 
					  typedef sockaddr_in SOCKADDR_IN;
 | 
				
			||||||
#ifndef INVALID_SOCKET
 | 
					  #ifndef INVALID_SOCKET
 | 
				
			||||||
#define INVALID_SOCKET (-1)
 | 
					  #define INVALID_SOCKET (-1)
 | 
				
			||||||
#endif
 | 
					  #endif
 | 
				
			||||||
#define SOCKET_ERROR (-1)
 | 
					  #define SOCKET_ERROR (-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define closesocket(sd) ::close(sd)
 | 
					  #define closesocket(sd) ::close(sd)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#error Platform specific socket support is not yet available on this platform!
 | 
					  #error Platform specific socket support is not yet available on this platform!
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string>
 | 
					
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OCTO
 | 
					namespace OCTO
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAXCONNECTIONS 1 ///< Maximum number of pending connections before "Connection refused"
 | 
					#define MAXCONNECTIONS 1  ///< Maximum number of pending connections before "Connection refused"
 | 
				
			||||||
#define MAXRECV 1500 ///< Maximum packet size
 | 
					#define MAXRECV 1500      ///< Maximum packet size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum SocketFamily
 | 
					enum SocketFamily
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -78,10 +88,10 @@ enum SocketFamily
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
enum SocketDomain
 | 
					enum SocketDomain
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#if defined TARGET_LINUX || defined TARGET_DARWIN || defined TARGET_FREEBSD
 | 
					  #if defined TARGET_LINUX || defined TARGET_DARWIN || defined TARGET_FREEBSD
 | 
				
			||||||
  pf_unix = PF_UNIX,
 | 
					    pf_unix  = PF_UNIX,
 | 
				
			||||||
  pf_local = PF_LOCAL,
 | 
					    pf_local = PF_LOCAL,
 | 
				
			||||||
#endif
 | 
					  #endif
 | 
				
			||||||
  pf_inet = PF_INET
 | 
					  pf_inet = PF_INET
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -99,187 +109,197 @@ enum SocketProtocol
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class Socket
 | 
					class Socket
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					  public:
 | 
				
			||||||
  /*!
 | 
					 | 
				
			||||||
   * An unconnected socket may be created directly on the local
 | 
					 | 
				
			||||||
   * machine. The socket type (SOCK_STREAM, SOCK_DGRAM) and
 | 
					 | 
				
			||||||
   * protocol may also be specified.
 | 
					 | 
				
			||||||
   * If the socket cannot be created, an exception is thrown.
 | 
					 | 
				
			||||||
   *
 | 
					 | 
				
			||||||
   * \param family Socket family (IPv4 or IPv6)
 | 
					 | 
				
			||||||
   * \param domain The domain parameter specifies a communications domain within which communication will take place;
 | 
					 | 
				
			||||||
   * this selects the protocol family which should be used.
 | 
					 | 
				
			||||||
   * \param type base type and protocol family of the socket.
 | 
					 | 
				
			||||||
   * \param protocol specific protocol to apply.
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  Socket(const enum SocketFamily family,
 | 
					 | 
				
			||||||
         const enum SocketDomain domain,
 | 
					 | 
				
			||||||
         const enum SocketType type,
 | 
					 | 
				
			||||||
         const enum SocketProtocol protocol = tcp);
 | 
					 | 
				
			||||||
  Socket(void);
 | 
					 | 
				
			||||||
  virtual ~Socket();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  //Socket settings
 | 
					    /*!
 | 
				
			||||||
 | 
					     * An unconnected socket may be created directly on the local
 | 
				
			||||||
 | 
					     * machine. The socket type (SOCK_STREAM, SOCK_DGRAM) and
 | 
				
			||||||
 | 
					     * protocol may also be specified.
 | 
				
			||||||
 | 
					     * If the socket cannot be created, an exception is thrown.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * \param family Socket family (IPv4 or IPv6)
 | 
				
			||||||
 | 
					     * \param domain The domain parameter specifies a communications domain within which communication will take place;
 | 
				
			||||||
 | 
					     * this selects the protocol family which should be used.
 | 
				
			||||||
 | 
					     * \param type base type and protocol family of the socket.
 | 
				
			||||||
 | 
					     * \param protocol specific protocol to apply.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Socket(const enum SocketFamily family, const enum SocketDomain domain, const enum SocketType type, const enum SocketProtocol protocol = tcp);
 | 
				
			||||||
 | 
					    Socket(void);
 | 
				
			||||||
 | 
					    virtual ~Socket();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    //Socket settings
 | 
				
			||||||
   * Socket setFamily
 | 
					 | 
				
			||||||
   * \param family    Can be af_inet or af_inet6. Default: af_inet
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  void setFamily(const enum SocketFamily family) { m_family = family; };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket setDomain
 | 
					     * Socket setFamily
 | 
				
			||||||
   * \param domain    Can be pf_unix, pf_local, pf_inet or pf_inet6. Default: pf_inet
 | 
					     * \param family    Can be af_inet or af_inet6. Default: af_inet
 | 
				
			||||||
   */
 | 
					     */
 | 
				
			||||||
  void setDomain(const enum SocketDomain domain) { m_domain = domain; };
 | 
					    void setFamily(const enum SocketFamily family)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      _family = family;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket setType
 | 
					     * Socket setDomain
 | 
				
			||||||
   * \param type    Can be sock_stream or sock_dgram. Default: sock_stream.
 | 
					     * \param domain    Can be pf_unix, pf_local, pf_inet or pf_inet6. Default: pf_inet
 | 
				
			||||||
   */
 | 
					     */
 | 
				
			||||||
  void setType(const enum SocketType type) { m_type = type; };
 | 
					    void setDomain(const enum SocketDomain domain)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      _domain = domain;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket setProtocol
 | 
					     * Socket setType
 | 
				
			||||||
   * \param protocol    Can be tcp or udp. Default: tcp.
 | 
					     * \param type    Can be sock_stream or sock_dgram. Default: sock_stream.
 | 
				
			||||||
   */
 | 
					     */
 | 
				
			||||||
  void setProtocol(const enum SocketProtocol protocol) { m_protocol = protocol; };
 | 
					    void setType(const enum SocketType type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      _type = type;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket setPort
 | 
					     * Socket setProtocol
 | 
				
			||||||
   * \param port    port number for socket communication
 | 
					     * \param protocol    Can be tcp or udp. Default: tcp.
 | 
				
			||||||
   */
 | 
					     */
 | 
				
			||||||
  void setPort(const unsigned short port) { m_sockaddr.sin_port = htons(port); };
 | 
					    void setProtocol(const enum SocketProtocol protocol)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      _protocol = protocol;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool setHostname(const std::string& host);
 | 
					    /*!
 | 
				
			||||||
 | 
					     * Socket setPort
 | 
				
			||||||
 | 
					     * \param port    port number for socket communication
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void setPort (const unsigned short port)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      _sockaddr.sin_port = htons ( port );
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Server initialization
 | 
					    bool setHostname ( const std::string& host );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    // Server initialization
 | 
				
			||||||
   * Socket create
 | 
					 | 
				
			||||||
   * Create a new socket
 | 
					 | 
				
			||||||
   * \return     True if succesful
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  bool create();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket close
 | 
					     * Socket create
 | 
				
			||||||
   * Close the socket
 | 
					     * Create a new socket
 | 
				
			||||||
   * \return     True if succesful
 | 
					     * \return     True if succesful
 | 
				
			||||||
   */
 | 
					     */
 | 
				
			||||||
  bool close();
 | 
					    bool create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket bind
 | 
					     * Socket close
 | 
				
			||||||
   */
 | 
					     * Close the socket
 | 
				
			||||||
  bool bind(const unsigned short port);
 | 
					     * \return     True if succesful
 | 
				
			||||||
  bool listen() const;
 | 
					     */
 | 
				
			||||||
  bool accept(Socket& socket) const;
 | 
					    bool close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Client initialization
 | 
					    /*!
 | 
				
			||||||
  bool connect(const std::string& host, const unsigned short port);
 | 
					     * Socket bind
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    bool bind ( const unsigned short port );
 | 
				
			||||||
 | 
					    bool listen() const;
 | 
				
			||||||
 | 
					    bool accept ( Socket& socket ) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool reconnect();
 | 
					    // Client initialization
 | 
				
			||||||
 | 
					    bool connect ( const std::string& host, const unsigned short port );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Data Transmission
 | 
					    bool reconnect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    // Data Transmission
 | 
				
			||||||
   * Socket send function
 | 
					 | 
				
			||||||
   *
 | 
					 | 
				
			||||||
   * \param data    Reference to a std::string with the data to transmit
 | 
					 | 
				
			||||||
   * \return    Number of bytes send or -1 in case of an error
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  int send(const std::string& data);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket send function
 | 
					     * Socket send function
 | 
				
			||||||
   *
 | 
					     *
 | 
				
			||||||
   * \param data    Pointer to a character array of size 'size' with the data to transmit
 | 
					     * \param data    Reference to a std::string with the data to transmit
 | 
				
			||||||
   * \param size    Length of the data to transmit
 | 
					     * \return    Number of bytes send or -1 in case of an error
 | 
				
			||||||
   * \return    Number of bytes send or -1 in case of an error
 | 
					     */
 | 
				
			||||||
   */
 | 
					    int send ( const std::string& data );
 | 
				
			||||||
  int send(const char* data, const unsigned int size);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket sendto function
 | 
					     * Socket send function
 | 
				
			||||||
   *
 | 
					     *
 | 
				
			||||||
   * \param data    Reference to a std::string with the data to transmit
 | 
					     * \param data    Pointer to a character array of size 'size' with the data to transmit
 | 
				
			||||||
   * \param size    Length of the data to transmit
 | 
					     * \param size    Length of the data to transmit
 | 
				
			||||||
   * \param sendcompletebuffer    If 'true': do not return until the complete buffer is transmitted
 | 
					     * \return    Number of bytes send or -1 in case of an error
 | 
				
			||||||
   * \return    Number of bytes send or -1 in case of an error
 | 
					     */
 | 
				
			||||||
   */
 | 
					    int send ( const char* data, const unsigned int size );
 | 
				
			||||||
  int sendto(const char* data, unsigned int size, bool sendcompletebuffer = false);
 | 
					 | 
				
			||||||
  // Data Receive
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket receive function
 | 
					     * Socket sendto function
 | 
				
			||||||
   *
 | 
					     *
 | 
				
			||||||
   * \param data    Reference to a std::string for storage of the received data.
 | 
					     * \param data    Reference to a std::string with the data to transmit
 | 
				
			||||||
   * \param minpacketsize    The minimum number of bytes that should be received before returning from this function
 | 
					     * \param size    Length of the data to transmit
 | 
				
			||||||
   * \return    Number of bytes received or SOCKET_ERROR
 | 
					     * \param sendcompletebuffer    If 'true': do not return until the complete buffer is transmitted
 | 
				
			||||||
   */
 | 
					     * \return    Number of bytes send or -1 in case of an error
 | 
				
			||||||
  int receive(std::string& data, unsigned int minpacketsize) const;
 | 
					     */
 | 
				
			||||||
 | 
					    int sendto ( const char* data, unsigned int size, bool sendcompletebuffer = false);
 | 
				
			||||||
 | 
					    // Data Receive
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket receive function
 | 
					     * Socket receive function
 | 
				
			||||||
   *
 | 
					     *
 | 
				
			||||||
   * \param data    Reference to a std::string for storage of the received data.
 | 
					     * \param data    Reference to a std::string for storage of the received data.
 | 
				
			||||||
   * \return    Number of bytes received or SOCKET_ERROR
 | 
					     * \param minpacketsize    The minimum number of bytes that should be received before returning from this function
 | 
				
			||||||
   */
 | 
					     * \return    Number of bytes received or SOCKET_ERROR
 | 
				
			||||||
  int receive(std::string& data) const;
 | 
					     */
 | 
				
			||||||
 | 
					    int receive ( std::string& data, unsigned int minpacketsize ) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket receive function
 | 
					     * Socket receive function
 | 
				
			||||||
   *
 | 
					     *
 | 
				
			||||||
   * \param data    Pointer to a character array of size buffersize. Used to store the received data.
 | 
					     * \param data    Reference to a std::string for storage of the received data.
 | 
				
			||||||
   * \param buffersize    Size of the 'data' buffer
 | 
					     * \return    Number of bytes received or SOCKET_ERROR
 | 
				
			||||||
   * \param minpacketsize    Specifies the minimum number of bytes that need to be received before returning
 | 
					     */
 | 
				
			||||||
   * \return    Number of bytes received or SOCKET_ERROR
 | 
					    int receive ( std::string& data ) const;
 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  int receive(char* data, const unsigned int buffersize, const unsigned int minpacketsize) const;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*!
 | 
					    /*!
 | 
				
			||||||
   * Socket recvfrom function
 | 
					     * Socket receive function
 | 
				
			||||||
   *
 | 
					     *
 | 
				
			||||||
   * \param data    Pointer to a character array of size buffersize. Used to store the received data.
 | 
					     * \param data    Pointer to a character array of size buffersize. Used to store the received data.
 | 
				
			||||||
   * \param buffersize    Size of the 'data' buffer
 | 
					     * \param buffersize    Size of the 'data' buffer
 | 
				
			||||||
   * \param from        Optional: pointer to a sockaddr struct that will get the address from which the data is received
 | 
					     * \param minpacketsize    Specifies the minimum number of bytes that need to be received before returning
 | 
				
			||||||
   * \param fromlen    Optional, only required if 'from' is given: length of from struct
 | 
					     * \return    Number of bytes received or SOCKET_ERROR
 | 
				
			||||||
   * \return    Number of bytes received or SOCKET_ERROR
 | 
					     */
 | 
				
			||||||
   */
 | 
					    int receive ( char* data, const unsigned int buffersize, const unsigned int minpacketsize ) const;
 | 
				
			||||||
  int recvfrom(char* data,
 | 
					 | 
				
			||||||
               const int buffersize,
 | 
					 | 
				
			||||||
               struct sockaddr* from = nullptr,
 | 
					 | 
				
			||||||
               socklen_t* fromlen = nullptr) const;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool set_non_blocking(const bool);
 | 
					    /*!
 | 
				
			||||||
 | 
					     * Socket recvfrom function
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * \param data    Pointer to a character array of size buffersize. Used to store the received data.
 | 
				
			||||||
 | 
					     * \param buffersize    Size of the 'data' buffer
 | 
				
			||||||
 | 
					     * \param from        Optional: pointer to a sockaddr struct that will get the address from which the data is received
 | 
				
			||||||
 | 
					     * \param fromlen    Optional, only required if 'from' is given: length of from struct
 | 
				
			||||||
 | 
					     * \return    Number of bytes received or SOCKET_ERROR
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    int recvfrom ( char* data, const int buffersize, struct sockaddr* from = NULL, socklen_t* fromlen = NULL) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool ReadLine(std::string& line);
 | 
					    bool set_non_blocking ( const bool );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool is_valid() const;
 | 
					    bool ReadLine (std::string& line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					    bool is_valid() const;
 | 
				
			||||||
  SOCKET m_sd; ///< Socket Descriptor
 | 
					 | 
				
			||||||
  SOCKADDR_IN m_sockaddr; ///< Socket Address
 | 
					 | 
				
			||||||
  //struct addrinfo* m_addrinfo;         ///< Socket address info
 | 
					 | 
				
			||||||
  std::string m_hostname; ///< Hostname
 | 
					 | 
				
			||||||
  unsigned short m_port; ///< Port number
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  enum SocketFamily m_family; ///< Socket Address Family
 | 
					  private:
 | 
				
			||||||
  enum SocketProtocol m_protocol; ///< Socket Protocol
 | 
					 | 
				
			||||||
  enum SocketType m_type; ///< Socket Type
 | 
					 | 
				
			||||||
  enum SocketDomain m_domain; ///< Socket domain
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TARGET_WINDOWS
 | 
					    SOCKET _sd;                         ///< Socket Descriptor
 | 
				
			||||||
  WSADATA m_wsaData; ///< Windows Socket data
 | 
					    SOCKADDR_IN _sockaddr;              ///< Socket Address
 | 
				
			||||||
  static int
 | 
					    //struct addrinfo* _addrinfo;         ///< Socket address info
 | 
				
			||||||
      win_usage_count; ///< Internal Windows usage counter used to prevent a global WSACleanup when more than one Socket object is used
 | 
					    std::string _hostname;              ///< Hostname
 | 
				
			||||||
#endif
 | 
					    unsigned short _port;               ///< Port number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void errormessage(int errornum, const char* functionname = nullptr) const;
 | 
					    enum SocketFamily _family;          ///< Socket Address Family
 | 
				
			||||||
  int getLastError(void) const;
 | 
					    enum SocketProtocol _protocol;      ///< Socket Protocol
 | 
				
			||||||
  bool osInit();
 | 
					    enum SocketType _type;              ///< Socket Type
 | 
				
			||||||
  void osCleanup();
 | 
					    enum SocketDomain _domain;          ///< Socket domain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #ifdef TARGET_WINDOWS
 | 
				
			||||||
 | 
					      WSADATA _wsaData;                 ///< Windows Socket data
 | 
				
			||||||
 | 
					      static int win_usage_count;       ///< Internal Windows usage counter used to prevent a global WSACleanup when more than one Socket object is used
 | 
				
			||||||
 | 
					    #endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void errormessage( int errornum, const char* functionname = NULL) const;
 | 
				
			||||||
 | 
					    int getLastError(void) const;
 | 
				
			||||||
 | 
					    bool osInit();
 | 
				
			||||||
 | 
					    void osCleanup();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} //namespace OCTO
 | 
					} //namespace OCTO
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,62 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  Copyright (C) 2015 Julian Scheel <julian@jusst.de>
 | 
					 | 
				
			||||||
 *  Copyright (C) 2015 jusst technologies GmbH
 | 
					 | 
				
			||||||
 *  Copyright (C) 2015 Digital Devices GmbH
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  SPDX-License-Identifier: GPL-2.0-or-later
 | 
					 | 
				
			||||||
 *  See LICENSE.md for more information.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "addon.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "OctonetData.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADDON_STATUS COctonetAddon::SetSetting(const std::string& settingName,
 | 
					 | 
				
			||||||
                                       const kodi::CSettingValue& settingValue)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  /* For simplicity do a full addon restart whenever settings are
 | 
					 | 
				
			||||||
   * changed */
 | 
					 | 
				
			||||||
  return ADDON_STATUS_NEED_RESTART;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADDON_STATUS COctonetAddon::CreateInstance(int instanceType,
 | 
					 | 
				
			||||||
                                           const std::string& instanceID,
 | 
					 | 
				
			||||||
                                           KODI_HANDLE instance,
 | 
					 | 
				
			||||||
                                           const std::string& version,
 | 
					 | 
				
			||||||
                                           KODI_HANDLE& addonInstance)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  if (instanceType == ADDON_INSTANCE_PVR)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    kodi::Log(ADDON_LOG_DEBUG, "%s: Creating octonet pvr instance", __func__);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* IP or hostname of the octonet to be connected to */
 | 
					 | 
				
			||||||
    std::string octonetAddress = kodi::GetSettingString("octonetAddress");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    OctonetData* usedInstance = new OctonetData(octonetAddress, instance, version);
 | 
					 | 
				
			||||||
    addonInstance = usedInstance;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    m_usedInstances.emplace(instanceID, usedInstance);
 | 
					 | 
				
			||||||
    return ADDON_STATUS_OK;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return ADDON_STATUS_UNKNOWN;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void COctonetAddon::DestroyInstance(int instanceType,
 | 
					 | 
				
			||||||
                                    const std::string& instanceID,
 | 
					 | 
				
			||||||
                                    KODI_HANDLE addonInstance)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  if (instanceType == ADDON_INSTANCE_PVR)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    kodi::Log(ADDON_LOG_DEBUG, "%s: Destoying octonet pvr instance", __func__);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const auto& it = m_usedInstances.find(instanceID);
 | 
					 | 
				
			||||||
    if (it != m_usedInstances.end())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      m_usedInstances.erase(it);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADDONCREATOR(COctonetAddon)
 | 
					 | 
				
			||||||
							
								
								
									
										36
									
								
								src/addon.h
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								src/addon.h
									
									
									
									
									
								
							@@ -1,36 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  Copyright (C) 2015 Julian Scheel <julian@jusst.de>
 | 
					 | 
				
			||||||
 *  Copyright (C) 2015 jusst technologies GmbH
 | 
					 | 
				
			||||||
 *  Copyright (C) 2015 Digital Devices GmbH
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  SPDX-License-Identifier: GPL-2.0-or-later
 | 
					 | 
				
			||||||
 *  See LICENSE.md for more information.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <kodi/AddonBase.h>
 | 
					 | 
				
			||||||
#include <unordered_map>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class OctonetData;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ATTRIBUTE_HIDDEN COctonetAddon : public kodi::addon::CAddonBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
  COctonetAddon() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ADDON_STATUS SetSetting(const std::string& settingName,
 | 
					 | 
				
			||||||
                          const kodi::CSettingValue& settingValue) override;
 | 
					 | 
				
			||||||
  ADDON_STATUS CreateInstance(int instanceType,
 | 
					 | 
				
			||||||
                              const std::string& instanceID,
 | 
					 | 
				
			||||||
                              KODI_HANDLE instance,
 | 
					 | 
				
			||||||
                              const std::string& version,
 | 
					 | 
				
			||||||
                              KODI_HANDLE& addonInstance) override;
 | 
					 | 
				
			||||||
  void DestroyInstance(int instanceType,
 | 
					 | 
				
			||||||
                       const std::string& instanceID,
 | 
					 | 
				
			||||||
                       KODI_HANDLE addonInstance) override;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
  std::unordered_map<std::string, OctonetData*> m_usedInstances;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
							
								
								
									
										318
									
								
								src/client.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								src/client.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,318 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Julian Scheel <julian@jusst.de>
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 jusst technologies GmbH
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Digital Devices GmbH
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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 2
 | 
				
			||||||
 | 
					 * of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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 this program; if not, write to the Free Software
 | 
				
			||||||
 | 
					 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 | 
				
			||||||
 | 
					 * USA.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "client.h"
 | 
				
			||||||
 | 
					#include <xbmc_pvr_dll.h>
 | 
				
			||||||
 | 
					#include <libXBMC_addon.h>
 | 
				
			||||||
 | 
					#include <p8-platform/util/util.h>
 | 
				
			||||||
 | 
					#include <libKODI_guilib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "OctonetData.h"
 | 
				
			||||||
 | 
					#include "rtsp_client.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace ADDON;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* setting variables with defaults */
 | 
				
			||||||
 | 
					std::string octonetAddress = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* internal state variables */
 | 
				
			||||||
 | 
					ADDON_STATUS addonStatus = ADDON_STATUS_UNKNOWN;
 | 
				
			||||||
 | 
					CHelper_libXBMC_addon *kodi = NULL;
 | 
				
			||||||
 | 
					CHelper_libXBMC_pvr *pvr = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OctonetData *data = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* KODI Core Addon functions
 | 
				
			||||||
 | 
					 * see xbmc_addon_dll.h */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADDON_ReadSettings(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char buffer[2048];
 | 
				
			||||||
 | 
						if (kodi->GetSetting("octonetAddress", &buffer))
 | 
				
			||||||
 | 
							octonetAddress = buffer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ADDON_STATUS ADDON_Create(void *callbacks, void* props)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (callbacks == NULL || props == NULL)
 | 
				
			||||||
 | 
							return ADDON_STATUS_UNKNOWN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PVR_PROPERTIES *pvrprops = (PVR_PROPERTIES*)props;
 | 
				
			||||||
 | 
						kodi = new CHelper_libXBMC_addon;
 | 
				
			||||||
 | 
						if (!kodi->RegisterMe(callbacks)) {
 | 
				
			||||||
 | 
							kodi->Log(LOG_ERROR, "%s: Failed to register octonet addon", __func__);
 | 
				
			||||||
 | 
							SAFE_DELETE(kodi);
 | 
				
			||||||
 | 
							return ADDON_STATUS_PERMANENT_FAILURE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pvr = new CHelper_libXBMC_pvr;
 | 
				
			||||||
 | 
						if (!pvr->RegisterMe(callbacks)) {
 | 
				
			||||||
 | 
							kodi->Log(LOG_ERROR, "%s: Failed to register octonet pvr addon", __func__);
 | 
				
			||||||
 | 
							SAFE_DELETE(pvr);
 | 
				
			||||||
 | 
							SAFE_DELETE(kodi);
 | 
				
			||||||
 | 
							return ADDON_STATUS_PERMANENT_FAILURE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kodi->Log(LOG_DEBUG, "%s: Creating octonet pvr addon", __func__);
 | 
				
			||||||
 | 
						ADDON_ReadSettings();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data = new OctonetData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addonStatus = ADDON_STATUS_OK;
 | 
				
			||||||
 | 
						return addonStatus;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADDON_Stop() {} /* no-op */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADDON_Destroy()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						delete pvr;
 | 
				
			||||||
 | 
						delete kodi;
 | 
				
			||||||
 | 
						addonStatus = ADDON_STATUS_UNKNOWN;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ADDON_STATUS ADDON_GetStatus()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return addonStatus;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ADDON_HasSettings()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned int ADDON_GetSettings(ADDON_StructSetting ***sSet)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ADDON_STATUS ADDON_SetSetting(const char *settingName, const void *settingValue)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* For simplicity do a full addon restart whenever settings are
 | 
				
			||||||
 | 
						 * changed */
 | 
				
			||||||
 | 
						return ADDON_STATUS_NEED_RESTART;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADDON_FreeSettings() {} /* no-op */
 | 
				
			||||||
 | 
					void ADDON_Announce(const char *flag, const char *sender, const char *message, const void *data) {} /* no-op */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* KODI PVR Addon functions
 | 
				
			||||||
 | 
					 * see xbmc_pvr_dll.h */
 | 
				
			||||||
 | 
					extern "C"
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* GetPVRAPIVersion(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return XBMC_PVR_API_VERSION;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* GetMininumPVRAPIVersion(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return XBMC_PVR_MIN_API_VERSION;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* GetGUIAPIVersion(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return KODI_GUILIB_API_VERSION;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* GetMininumGUIAPIVersion(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return KODI_GUILIB_MIN_API_VERSION;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PVR_ERROR GetAddonCapabilities(PVR_ADDON_CAPABILITIES *pCapabilities)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pCapabilities->bSupportsTV = true;
 | 
				
			||||||
 | 
						pCapabilities->bSupportsRadio = true;
 | 
				
			||||||
 | 
						pCapabilities->bSupportsChannelGroups = true;
 | 
				
			||||||
 | 
						pCapabilities->bSupportsEPG = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return PVR_ERROR_NO_ERROR;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* GetBackendName(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return "Digital Devices Octopus NET Client";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* GetBackendVersion(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return XBMC_PVR_API_VERSION;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* GetConnectionString(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return "connected"; // FIXME: translate?
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PVR_ERROR GetDriveSpace(long long* iTotal, long long* iUsed) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR CallMenuHook(const PVR_MENUHOOK& menuhook, const PVR_MENUHOOK_DATA &item) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void OnSystemSleep() {
 | 
				
			||||||
 | 
						kodi->Log(LOG_INFO, "Received event: %s", __FUNCTION__);
 | 
				
			||||||
 | 
						// FIXME: Disconnect?
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void OnSystemWake() {
 | 
				
			||||||
 | 
						kodi->Log(LOG_INFO, "Received event: %s", __FUNCTION__);
 | 
				
			||||||
 | 
						// FIXME:Reconnect?
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void OnPowerSavingActivated() {}
 | 
				
			||||||
 | 
					void OnPowerSavingDeactivated() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* EPG */
 | 
				
			||||||
 | 
					PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL& channel, time_t iStart, time_t iEnd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return data->getEPG(handle, channel, iStart, iEnd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Channel groups */
 | 
				
			||||||
 | 
					int GetChannelGroupsAmount(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return data->getGroupCount();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool bRadio)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return data->getGroups(handle, bRadio);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP& group)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return data->getGroupMembers(handle, group);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Channels */
 | 
				
			||||||
 | 
					PVR_ERROR OpenDialogChannelScan(void) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int GetChannelsAmount(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return data->getChannelCount();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PVR_ERROR GetChannels(ADDON_HANDLE handle, bool bRadio)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return data->getChannels(handle, bRadio);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PVR_ERROR DeleteChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR RenameChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR MoveChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR OpenDialogChannelSettings(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR OpenDialogChannelAdd(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Recordings */
 | 
				
			||||||
 | 
					int GetRecordingsAmount(bool deleted) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR GetRecordings(ADDON_HANDLE handle, bool deleted) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR DeleteRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR UndeleteRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR DeleteAllRecordingsFromTrash() { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR RenameRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING& recording, int count) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING& recording, int lastplayedposition) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					int GetRecordingLastPlayedPosition(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR GetRecordingEdl(const PVR_RECORDING&, PVR_EDL_ENTRY edl[], int *size) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR GetTimerTypes(PVR_TIMER_TYPE types[], int *size) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					int GetTimersAmount(void) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR GetTimers(ADDON_HANDLE handle) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR AddTimer(const PVR_TIMER& timer) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR DeleteTimer(const PVR_TIMER& timer, bool bForceDelete) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					PVR_ERROR UpdateTimer(const PVR_TIMER& timer) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PVR stream handling */
 | 
				
			||||||
 | 
					/* entirely unused, as we use standard RTSP+TS mux, which can be handlded by
 | 
				
			||||||
 | 
					 * Kodi core */
 | 
				
			||||||
 | 
					bool OpenLiveStream(const PVR_CHANNEL& channel) {
 | 
				
			||||||
 | 
						return rtsp_open(data->getName(channel.iUniqueId), data->getUrl(channel.iUniqueId));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ReadLiveStream(unsigned char* pBuffer, unsigned int iBufferSize) {
 | 
				
			||||||
 | 
						return rtsp_read(pBuffer, iBufferSize);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CloseLiveStream(void) {
 | 
				
			||||||
 | 
						rtsp_close();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					long long SeekLiveStream(long long iPosition, int iWhence) { return -1; }
 | 
				
			||||||
 | 
					long long PositionLiveStream(void) { return -1; }
 | 
				
			||||||
 | 
					long long LengthLiveStream(void) { return -1; }
 | 
				
			||||||
 | 
					bool IsRealTimeStream(void) { return true; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool SwitchChannel(const PVR_CHANNEL& channel) {
 | 
				
			||||||
 | 
						CloseLiveStream();
 | 
				
			||||||
 | 
						return OpenLiveStream(channel);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PVR_ERROR SignalStatus(PVR_SIGNAL_STATUS& signalStatus) {
 | 
				
			||||||
 | 
						memset(&signalStatus, 0, sizeof(PVR_SIGNAL_STATUS));
 | 
				
			||||||
 | 
						rtsp_fill_signal_status(signalStatus);
 | 
				
			||||||
 | 
						return PVR_ERROR_NO_ERROR;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* GetLiveStreamURL(const PVR_CHANNEL& channel) { return NULL; }
 | 
				
			||||||
 | 
					PVR_ERROR GetStreamProperties(PVR_STREAM_PROPERTIES* pProperties) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Recording stream handling */
 | 
				
			||||||
 | 
					bool OpenRecordedStream(const PVR_RECORDING& recording) { return false; }
 | 
				
			||||||
 | 
					void CloseRecordedStream(void) {}
 | 
				
			||||||
 | 
					int ReadRecordedStream(unsigned char* pBuffer, unsigned int iBufferSize) { return -1; }
 | 
				
			||||||
 | 
					long long SeekRecordedStream(long long iPosition, int iWhence) { return -1; }
 | 
				
			||||||
 | 
					long long PositionRecordedStream(void) { return -1; }
 | 
				
			||||||
 | 
					long long LengthRecordedStream(void) { return -1; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PVR demuxer */
 | 
				
			||||||
 | 
					/* entirey unused, as we use TS */
 | 
				
			||||||
 | 
					void DemuxReset(void) {}
 | 
				
			||||||
 | 
					void DemuxAbort(void) {}
 | 
				
			||||||
 | 
					void DemuxFlush(void) {}
 | 
				
			||||||
 | 
					DemuxPacket* DemuxRead(void) { return NULL; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Various helper functions */
 | 
				
			||||||
 | 
					unsigned int GetChannelSwitchDelay(void) { return 0; }
 | 
				
			||||||
 | 
					bool IsTimeshifting(void) { return false; }
 | 
				
			||||||
 | 
					bool CanPauseStream() { return false; }
 | 
				
			||||||
 | 
					bool CanSeekStream() { return false; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Callbacks */
 | 
				
			||||||
 | 
					void PauseStream(bool bPaused) {}
 | 
				
			||||||
 | 
					bool SeekTime(double time, bool backwards, double *startpts) { return false; }
 | 
				
			||||||
 | 
					void SetSpeed(int speed) {}
 | 
				
			||||||
 | 
					PVR_ERROR SetEPGTimeFrame(int) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					time_t GetPlayingTime() { return 0; }
 | 
				
			||||||
 | 
					time_t GetBufferTimeStart() { return 0; }
 | 
				
			||||||
 | 
					time_t GetBufferTimeEnd() { return 0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* GetBackendHostname()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return octonetAddress.c_str();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								src/client.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/client.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Julian Scheel <julian@jusst.de>
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 jusst technologies GmbH
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Digital Devices GmbH
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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 2
 | 
				
			||||||
 | 
					 * of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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 this program; if not, write to the Free Software
 | 
				
			||||||
 | 
					 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 | 
				
			||||||
 | 
					 * USA.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libXBMC_addon.h"
 | 
				
			||||||
 | 
					#include "libXBMC_pvr.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __func__
 | 
				
			||||||
 | 
					#define __func__ __FUNCTION__
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern ADDON::CHelper_libXBMC_addon *kodi;
 | 
				
			||||||
 | 
					extern CHelper_libXBMC_pvr *pvr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* IP or hostname of the octonet to be connected to */
 | 
				
			||||||
 | 
					extern std::string octonetAddress;
 | 
				
			||||||
@@ -1,41 +1,32 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  Copyright (C) 2005-2020 Team Kodi
 | 
					 | 
				
			||||||
 *  https://kodi.tv
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  SPDX-License-Identifier: GPL-2.0-or-later
 | 
					 | 
				
			||||||
 *  See LICENSE.md for more information.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "rtsp_client.hpp"
 | 
					#include "rtsp_client.hpp"
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Socket.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <cctype>
 | 
					#include <cctype>
 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
#include <iterator>
 | 
					#include <iterator>
 | 
				
			||||||
 | 
					#include "Socket.h"
 | 
				
			||||||
 | 
					#include "client.h"
 | 
				
			||||||
 | 
					#include <p8-platform/util/util.h>
 | 
				
			||||||
 | 
					#include <libXBMC_addon.h>
 | 
				
			||||||
 | 
					#include <cstring>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(_WIN32) || defined(_WIN64)
 | 
					#if defined(_WIN32) || defined(_WIN64)
 | 
				
			||||||
#define strtok_r strtok_s
 | 
					#define strtok_r strtok_s
 | 
				
			||||||
#define strncasecmp _strnicmp
 | 
					#define strncasecmp _strnicmp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int vasprintf(char** sptr, char* fmt, va_list argv)
 | 
					int vasprintf(char **sptr, char *fmt, va_list argv) {
 | 
				
			||||||
{
 | 
						int wanted = vsnprintf(*sptr = NULL, 0, fmt, argv);
 | 
				
			||||||
  int wanted = vsnprintf(*sptr = nullptr, 0, fmt, argv);
 | 
						if((wanted < 0) || ((*sptr = (char *)malloc(1 + wanted)) == NULL))
 | 
				
			||||||
  if ((wanted < 0) || ((*sptr = (char*)malloc(1 + wanted)) == nullptr))
 | 
							return -1;
 | 
				
			||||||
    return -1;
 | 
						return vsprintf(*sptr, fmt, argv);
 | 
				
			||||||
  return vsprintf(*sptr, fmt, argv);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int asprintf(char** sptr, char* fmt, ...)
 | 
					int asprintf(char **sptr, char *fmt, ...) {
 | 
				
			||||||
{
 | 
						int retval;
 | 
				
			||||||
  int retval;
 | 
						va_list argv;
 | 
				
			||||||
  va_list argv;
 | 
						va_start(argv, fmt);
 | 
				
			||||||
  va_start(argv, fmt);
 | 
						retval = vasprintf(sptr, fmt, argv);
 | 
				
			||||||
  retval = vasprintf(sptr, fmt, argv);
 | 
						va_end(argv);
 | 
				
			||||||
  va_end(argv);
 | 
						return retval;
 | 
				
			||||||
  return retval;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,501 +40,441 @@ int asprintf(char** sptr, char* fmt, ...)
 | 
				
			|||||||
#define RTCP_BUFFER_SIZE 1024
 | 
					#define RTCP_BUFFER_SIZE 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std;
 | 
					using namespace std;
 | 
				
			||||||
 | 
					using namespace ADDON;
 | 
				
			||||||
using namespace OCTO;
 | 
					using namespace OCTO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum rtsp_state
 | 
					enum rtsp_state {
 | 
				
			||||||
{
 | 
						RTSP_IDLE,
 | 
				
			||||||
  RTSP_IDLE,
 | 
						RTSP_DESCRIBE,
 | 
				
			||||||
  RTSP_DESCRIBE,
 | 
						RTSP_SETUP,
 | 
				
			||||||
  RTSP_SETUP,
 | 
						RTSP_PLAY,
 | 
				
			||||||
  RTSP_PLAY,
 | 
						RTSP_RUNNING
 | 
				
			||||||
  RTSP_RUNNING
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum rtsp_result
 | 
					enum rtsp_result {
 | 
				
			||||||
{
 | 
						RTSP_RESULT_OK = 200,
 | 
				
			||||||
  RTSP_RESULT_OK = 200,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rtsp_client
 | 
					struct rtsp_client {
 | 
				
			||||||
{
 | 
						char *content_base;
 | 
				
			||||||
  char* content_base;
 | 
						char *control;
 | 
				
			||||||
  char* control;
 | 
						char session_id[64];
 | 
				
			||||||
  char session_id[64];
 | 
						uint16_t stream_id;
 | 
				
			||||||
  uint16_t stream_id;
 | 
						int keepalive_interval;
 | 
				
			||||||
  int keepalive_interval;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  char udp_address[UDP_ADDRESS_LEN];
 | 
						char udp_address[UDP_ADDRESS_LEN];
 | 
				
			||||||
  uint16_t udp_port;
 | 
						uint16_t udp_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Socket tcp_sock;
 | 
						Socket tcp_sock;
 | 
				
			||||||
  Socket udp_sock;
 | 
						Socket udp_sock;
 | 
				
			||||||
  Socket rtcp_sock;
 | 
						Socket rtcp_sock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  enum rtsp_state state;
 | 
						enum rtsp_state state;
 | 
				
			||||||
  int cseq;
 | 
						int cseq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  size_t fifo_size;
 | 
						size_t fifo_size;
 | 
				
			||||||
  uint16_t last_seq_nr;
 | 
						uint16_t last_seq_nr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  string name;
 | 
						string name;
 | 
				
			||||||
  int level;
 | 
						int level;
 | 
				
			||||||
  int quality;
 | 
						int quality;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct url
 | 
					struct url {
 | 
				
			||||||
{
 | 
						string protocol;
 | 
				
			||||||
  string protocol;
 | 
						string host;
 | 
				
			||||||
  string host;
 | 
						int port;
 | 
				
			||||||
  int port;
 | 
						string path;
 | 
				
			||||||
  string path;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rtcp_app
 | 
					struct rtcp_app {
 | 
				
			||||||
{
 | 
						uint8_t subtype;
 | 
				
			||||||
  uint8_t subtype;
 | 
						uint8_t pt;
 | 
				
			||||||
  uint8_t pt;
 | 
						uint16_t len;
 | 
				
			||||||
  uint16_t len;
 | 
						uint32_t ssrc;
 | 
				
			||||||
  uint32_t ssrc;
 | 
						char name[4];
 | 
				
			||||||
  char name[4];
 | 
						uint16_t identifier;
 | 
				
			||||||
  uint16_t identifier;
 | 
						uint16_t string_len;
 | 
				
			||||||
  uint16_t string_len;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static rtsp_client* rtsp = nullptr;
 | 
					static rtsp_client *rtsp = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static url parse_url(const std::string& str)
 | 
					static url parse_url(const std::string& str) {
 | 
				
			||||||
{
 | 
						static const string prot_end = "://";
 | 
				
			||||||
  static const string prot_end = "://";
 | 
						static const string host_end = "/";
 | 
				
			||||||
  static const string host_end = "/";
 | 
						url result;
 | 
				
			||||||
  url result;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  string::const_iterator begin = str.begin();
 | 
						string::const_iterator begin = str.begin();
 | 
				
			||||||
  string::const_iterator end = search(begin, str.end(), prot_end.begin(), prot_end.end());
 | 
						string::const_iterator end = search(begin, str.end(), prot_end.begin(), prot_end.end());
 | 
				
			||||||
  result.protocol.reserve(distance(begin, end));
 | 
						result.protocol.reserve(distance(begin, end));
 | 
				
			||||||
  transform(begin, end, back_inserter(result.protocol), ::tolower);
 | 
						transform(begin, end, back_inserter(result.protocol), ::tolower);
 | 
				
			||||||
  advance(end, prot_end.size());
 | 
						advance(end, prot_end.size());
 | 
				
			||||||
  begin = end;
 | 
						begin = end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  end = search(begin, str.end(), host_end.begin(), host_end.end());
 | 
						end = search(begin, str.end(), host_end.begin(), host_end.end());
 | 
				
			||||||
  result.host.reserve(distance(begin, end));
 | 
						result.host.reserve(distance(begin, end));
 | 
				
			||||||
  transform(begin, end, back_inserter(result.host), ::tolower);
 | 
						transform(begin, end, back_inserter(result.host), ::tolower);
 | 
				
			||||||
  advance(end, host_end.size());
 | 
						advance(end, host_end.size());
 | 
				
			||||||
  begin = end;
 | 
						begin = end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  result.port = RTSP_DEFAULT_PORT;
 | 
						result.port = RTSP_DEFAULT_PORT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  result.path.reserve(distance(begin, str.end()));
 | 
						result.path.reserve(distance(begin, str.end()));
 | 
				
			||||||
  transform(begin, str.end(), back_inserter(result.path), ::tolower);
 | 
						transform(begin, str.end(), back_inserter(result.path), ::tolower);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void split_string(const string& s, char delim, vector<string>& elems)
 | 
					void split_string(const string& s, char delim, vector<string>& elems) {
 | 
				
			||||||
{
 | 
						stringstream ss;
 | 
				
			||||||
  stringstream ss;
 | 
						ss.str(s);
 | 
				
			||||||
  ss.str(s);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  string item;
 | 
						string item;
 | 
				
			||||||
  while (getline(ss, item, delim))
 | 
						while(getline(ss, item, delim)) {
 | 
				
			||||||
  {
 | 
							elems.push_back(item);
 | 
				
			||||||
    elems.push_back(item);
 | 
						}
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tcp_sock_read_line(string& line)
 | 
					static int tcp_sock_read_line(string &line) {
 | 
				
			||||||
{
 | 
						static string buf;
 | 
				
			||||||
  static string buf;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while (true)
 | 
						while(true) {
 | 
				
			||||||
  {
 | 
							string::size_type pos = buf.find("\r\n");
 | 
				
			||||||
    string::size_type pos = buf.find("\r\n");
 | 
							if(pos != string::npos) {
 | 
				
			||||||
    if (pos != string::npos)
 | 
								line = buf.substr(0, pos);
 | 
				
			||||||
    {
 | 
								buf.erase(0, pos + 2);
 | 
				
			||||||
      line = buf.substr(0, pos);
 | 
								return 0;
 | 
				
			||||||
      buf.erase(0, pos + 2);
 | 
							}
 | 
				
			||||||
      return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char tmp_buf[2048];
 | 
							char tmp_buf[2048];
 | 
				
			||||||
    int size = rtsp->tcp_sock.receive(tmp_buf, sizeof(tmp_buf), 1);
 | 
							int size = rtsp->tcp_sock.receive(tmp_buf, sizeof(tmp_buf), 1);
 | 
				
			||||||
    if (size <= 0)
 | 
							if(size <= 0) {
 | 
				
			||||||
    {
 | 
								return 1;
 | 
				
			||||||
      return 1;
 | 
							}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    buf.append(&tmp_buf[0], &tmp_buf[size]);
 | 
							buf.append(&tmp_buf[0], &tmp_buf[size]);
 | 
				
			||||||
  }
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static string compose_url(const url& u)
 | 
					static string compose_url(const url& u)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  stringstream res;
 | 
						stringstream res;
 | 
				
			||||||
  res << u.protocol << "://" << u.host;
 | 
						res << u.protocol << "://" << u.host;
 | 
				
			||||||
  if (u.port > 0)
 | 
						if (u.port > 0)
 | 
				
			||||||
    res << ":" << u.port;
 | 
							res << ":" << u.port;
 | 
				
			||||||
  res << "/" << u.path;
 | 
						res << "/" << u.path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return res.str();
 | 
						return res.str();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void parse_session(char* request_line, char* session, unsigned max, int* timeout)
 | 
					static void parse_session(char *request_line, char *session, unsigned max, int *timeout) {
 | 
				
			||||||
{
 | 
						char *state;
 | 
				
			||||||
  char* state;
 | 
						char *tok;
 | 
				
			||||||
  char* tok;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  tok = strtok_r(request_line, ";", &state);
 | 
						tok = strtok_r(request_line, ";", &state);
 | 
				
			||||||
  if (tok == nullptr)
 | 
						if (tok == NULL)
 | 
				
			||||||
    return;
 | 
							return;
 | 
				
			||||||
  strncpy(session, tok, min(strlen(tok), (size_t)(max - 1)));
 | 
						strncpy(session, tok, min(strlen(tok), (size_t)(max - 1)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while ((tok = strtok_r(nullptr, ";", &state)) != nullptr)
 | 
						while ((tok = strtok_r(NULL, ";", &state)) != NULL) {
 | 
				
			||||||
  {
 | 
							if (strncmp(tok, "timeout=", 8) == 0) {
 | 
				
			||||||
    if (strncmp(tok, "timeout=", 8) == 0)
 | 
								*timeout = atoi(tok + 8);
 | 
				
			||||||
    {
 | 
								if (*timeout > 5)
 | 
				
			||||||
      *timeout = atoi(tok + 8);
 | 
									*timeout -= KEEPALIVE_MARGIN;
 | 
				
			||||||
      if (*timeout > 5)
 | 
								else if (*timeout > 0)
 | 
				
			||||||
        *timeout -= KEEPALIVE_MARGIN;
 | 
									*timeout = 1;
 | 
				
			||||||
      else if (*timeout > 0)
 | 
							}
 | 
				
			||||||
        *timeout = 1;
 | 
						}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int parse_port(char* str, uint16_t* port)
 | 
					static int parse_port(char *str, uint16_t *port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int p = atoi(str);
 | 
						int p = atoi(str);
 | 
				
			||||||
  if (p < 0 || p > UINT16_MAX)
 | 
						if (p < 0 || p > UINT16_MAX)
 | 
				
			||||||
    return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  *port = p;
 | 
						*port = p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int parse_transport(char* request_line)
 | 
					static int parse_transport(char *request_line) {
 | 
				
			||||||
{
 | 
						char *state;
 | 
				
			||||||
  char* state;
 | 
						char *tok;
 | 
				
			||||||
  char* tok;
 | 
						int err;
 | 
				
			||||||
  int err;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  tok = strtok_r(request_line, ";", &state);
 | 
						tok = strtok_r(request_line, ";", &state);
 | 
				
			||||||
  if (tok == nullptr || strncmp(tok, "RTP/AVP", 7) != 0)
 | 
						if (tok == NULL || strncmp(tok, "RTP/AVP", 7) != 0)
 | 
				
			||||||
    return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  tok = strtok_r(nullptr, ";", &state);
 | 
						tok = strtok_r(NULL, ";", &state);
 | 
				
			||||||
  if (tok == nullptr || strncmp(tok, "multicast", 9) != 0)
 | 
						if (tok == NULL || strncmp(tok, "multicast", 9) != 0)
 | 
				
			||||||
    return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while ((tok = strtok_r(nullptr, ";", &state)) != nullptr)
 | 
						while ((tok = strtok_r(NULL, ";", &state)) != NULL) {
 | 
				
			||||||
  {
 | 
							if (strncmp(tok, "destination=", 12) == 0) {
 | 
				
			||||||
    if (strncmp(tok, "destination=", 12) == 0)
 | 
								strncpy(rtsp->udp_address, tok + 12, min(strlen(tok + 12), (size_t)(UDP_ADDRESS_LEN - 1)));
 | 
				
			||||||
    {
 | 
							} else if (strncmp(tok, "port=", 5) == 0) {
 | 
				
			||||||
      strncpy(rtsp->udp_address, tok + 12, min(strlen(tok + 12), (size_t)(UDP_ADDRESS_LEN - 1)));
 | 
								char port[6];
 | 
				
			||||||
    }
 | 
								char *end;
 | 
				
			||||||
    else if (strncmp(tok, "port=", 5) == 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      char port[6];
 | 
					 | 
				
			||||||
      char* end;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      memset(port, 0x00, 6);
 | 
								memset(port, 0x00, 6);
 | 
				
			||||||
      strncpy(port, tok + 5, min(strlen(tok + 5), (size_t)5));
 | 
								strncpy(port, tok + 5, min(strlen(tok + 5), (size_t)5));
 | 
				
			||||||
      if ((end = strstr(port, "-")) != nullptr)
 | 
								if ((end = strstr(port, "-")) != NULL)
 | 
				
			||||||
        *end = '\0';
 | 
									*end = '\0';
 | 
				
			||||||
      err = parse_port(port, &rtsp->udp_port);
 | 
								err = parse_port(port, &rtsp->udp_port);
 | 
				
			||||||
      if (err)
 | 
								if (err)
 | 
				
			||||||
        return err;
 | 
									return err;
 | 
				
			||||||
    }
 | 
							}
 | 
				
			||||||
  }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define skip_whitespace(x) \
 | 
					#define skip_whitespace(x) while(*x == ' ') x++
 | 
				
			||||||
  while (*x == ' ') \
 | 
					static enum rtsp_result rtsp_handle() {
 | 
				
			||||||
  x++
 | 
						uint8_t buffer[512];
 | 
				
			||||||
static enum rtsp_result rtsp_handle()
 | 
						int rtsp_result = 0;
 | 
				
			||||||
{
 | 
						bool have_header = false;
 | 
				
			||||||
  uint8_t buffer[512];
 | 
						size_t content_length = 0;
 | 
				
			||||||
  int rtsp_result = 0;
 | 
						size_t read = 0;
 | 
				
			||||||
  bool have_header = false;
 | 
						char *in, *val;
 | 
				
			||||||
  size_t content_length = 0;
 | 
						string in_str;
 | 
				
			||||||
  size_t read = 0;
 | 
					 | 
				
			||||||
  char *in, *val;
 | 
					 | 
				
			||||||
  string in_str;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Parse header */
 | 
						/* Parse header */
 | 
				
			||||||
  while (!have_header)
 | 
						while (!have_header) {
 | 
				
			||||||
  {
 | 
							if (tcp_sock_read_line(in_str) < 0)
 | 
				
			||||||
    if (tcp_sock_read_line(in_str) < 0)
 | 
								break;
 | 
				
			||||||
      break;
 | 
							in = const_cast<char *>(in_str.c_str());
 | 
				
			||||||
    in = const_cast<char*>(in_str.c_str());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (strncmp(in, "RTSP/1.0 ", 9) == 0)
 | 
							if (strncmp(in, "RTSP/1.0 ", 9) == 0) {
 | 
				
			||||||
    {
 | 
								rtsp_result = atoi(in + 9);
 | 
				
			||||||
      rtsp_result = atoi(in + 9);
 | 
							} else if (strncmp(in, "Content-Base:", 13) == 0) {
 | 
				
			||||||
    }
 | 
								free(rtsp->content_base);
 | 
				
			||||||
    else if (strncmp(in, "Content-Base:", 13) == 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      free(rtsp->content_base);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      val = in + 13;
 | 
								val = in + 13;
 | 
				
			||||||
      skip_whitespace(val);
 | 
								skip_whitespace(val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      rtsp->content_base = strdup(val);
 | 
								rtsp->content_base = strdup(val);
 | 
				
			||||||
    }
 | 
							} else if (strncmp(in, "Content-Length:", 15) == 0) {
 | 
				
			||||||
    else if (strncmp(in, "Content-Length:", 15) == 0)
 | 
								val = in + 16;
 | 
				
			||||||
    {
 | 
								skip_whitespace(val);
 | 
				
			||||||
      val = in + 16;
 | 
					 | 
				
			||||||
      skip_whitespace(val);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      content_length = atoi(val);
 | 
								content_length = atoi(val);
 | 
				
			||||||
    }
 | 
							} else if (strncmp("Session:", in, 8) == 0) {
 | 
				
			||||||
    else if (strncmp("Session:", in, 8) == 0)
 | 
								val = in + 8;
 | 
				
			||||||
    {
 | 
								skip_whitespace(val);
 | 
				
			||||||
      val = in + 8;
 | 
					 | 
				
			||||||
      skip_whitespace(val);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      parse_session(val, rtsp->session_id, 64, &rtsp->keepalive_interval);
 | 
								parse_session(val, rtsp->session_id, 64, &rtsp->keepalive_interval);
 | 
				
			||||||
    }
 | 
							} else if (strncmp("Transport:", in, 10) == 0) {
 | 
				
			||||||
    else if (strncmp("Transport:", in, 10) == 0)
 | 
								val = in + 10;
 | 
				
			||||||
    {
 | 
								skip_whitespace(val);
 | 
				
			||||||
      val = in + 10;
 | 
					 | 
				
			||||||
      skip_whitespace(val);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (parse_transport(val) != 0)
 | 
								if (parse_transport(val) != 0) {
 | 
				
			||||||
      {
 | 
									rtsp_result = -1;
 | 
				
			||||||
        rtsp_result = -1;
 | 
									break;
 | 
				
			||||||
        break;
 | 
								}
 | 
				
			||||||
      }
 | 
							} else if (strncmp("com.ses.streamID:", in, 17) == 0) {
 | 
				
			||||||
    }
 | 
								val = in + 17;
 | 
				
			||||||
    else if (strncmp("com.ses.streamID:", in, 17) == 0)
 | 
								skip_whitespace(val);
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      val = in + 17;
 | 
					 | 
				
			||||||
      skip_whitespace(val);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      rtsp->stream_id = atoi(val);
 | 
								rtsp->stream_id = atoi(val);
 | 
				
			||||||
    }
 | 
							} else if (in[0] == '\0') {
 | 
				
			||||||
    else if (in[0] == '\0')
 | 
								have_header = true;
 | 
				
			||||||
    {
 | 
							}
 | 
				
			||||||
      have_header = true;
 | 
						}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Discard further content */
 | 
						/* Discard further content */
 | 
				
			||||||
  while (content_length > 0 && (read = rtsp->tcp_sock.receive((char*)buffer, sizeof(buffer),
 | 
						while (content_length > 0 &&
 | 
				
			||||||
                                                              min(sizeof(buffer), content_length))))
 | 
								(read = rtsp->tcp_sock.receive((char*)buffer, sizeof(buffer), min(sizeof(buffer), content_length))))
 | 
				
			||||||
    content_length -= read;
 | 
							content_length -= read;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (enum rtsp_result)rtsp_result;
 | 
						return (enum rtsp_result)rtsp_result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool rtsp_open(const string& name, const string& url_str)
 | 
					bool rtsp_open(const string& name, const string& url_str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  string setup_url_str;
 | 
						string setup_url_str;
 | 
				
			||||||
  const char* psz_setup_url;
 | 
						const char *psz_setup_url;
 | 
				
			||||||
  stringstream setup_ss;
 | 
						stringstream setup_ss;
 | 
				
			||||||
  stringstream play_ss;
 | 
						stringstream play_ss;
 | 
				
			||||||
  url setup_url;
 | 
						url setup_url;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rtsp_close();
 | 
						rtsp_close();
 | 
				
			||||||
  rtsp = new rtsp_client();
 | 
						rtsp = new rtsp_client();
 | 
				
			||||||
  if (rtsp == nullptr)
 | 
						if (rtsp == NULL)
 | 
				
			||||||
    return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rtsp->name = name;
 | 
						rtsp->name = name;
 | 
				
			||||||
  rtsp->level = 0;
 | 
						rtsp->level = 0;
 | 
				
			||||||
  rtsp->quality = 0;
 | 
						rtsp->quality = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  kodi::Log(ADDON_LOG_DEBUG, "try to open '%s'", url_str.c_str());
 | 
						kodi->Log(LOG_DEBUG, "try to open '%s'", url_str.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  url dst = parse_url(url_str);
 | 
						url dst = parse_url(url_str);
 | 
				
			||||||
  kodi::Log(ADDON_LOG_DEBUG, "connect to host '%s'", dst.host.c_str());
 | 
						kodi->Log(LOG_DEBUG, "connect to host '%s'", dst.host.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!rtsp->tcp_sock.connect(dst.host, dst.port))
 | 
						if(!rtsp->tcp_sock.connect(dst.host, dst.port)) {
 | 
				
			||||||
  {
 | 
							kodi->Log(LOG_ERROR, "Failed to connect to RTSP server %s:%d", dst.host.c_str(), dst.port);
 | 
				
			||||||
    kodi::Log(ADDON_LOG_ERROR, "Failed to connect to RTSP server %s:%d", dst.host.c_str(),
 | 
							goto error;
 | 
				
			||||||
              dst.port);
 | 
						}
 | 
				
			||||||
    goto error;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO: tcp keep alive?
 | 
						// TODO: tcp keep alive?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (asprintf(&rtsp->content_base, "rtsp://%s:%d/", dst.host.c_str(), dst.port) < 0)
 | 
						if (asprintf(&rtsp->content_base, "rtsp://%s:%d/", dst.host.c_str(),
 | 
				
			||||||
  {
 | 
									dst.port) < 0) {
 | 
				
			||||||
    rtsp->content_base = nullptr;
 | 
							rtsp->content_base = NULL;
 | 
				
			||||||
    goto error;
 | 
							goto error;
 | 
				
			||||||
  }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rtsp->last_seq_nr = 0;
 | 
						rtsp->last_seq_nr = 0;
 | 
				
			||||||
  rtsp->keepalive_interval = (KEEPALIVE_INTERVAL - KEEPALIVE_MARGIN);
 | 
						rtsp->keepalive_interval = (KEEPALIVE_INTERVAL - KEEPALIVE_MARGIN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setup_url = dst;
 | 
						setup_url = dst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // reverse the satip protocol trick, as SAT>IP believes to be RTSP
 | 
						// reverse the satip protocol trick, as SAT>IP believes to be RTSP
 | 
				
			||||||
  if (!strncasecmp(setup_url.protocol.c_str(), "satip", 5))
 | 
						if (!strncasecmp(setup_url.protocol.c_str(), "satip", 5)) {
 | 
				
			||||||
  {
 | 
							setup_url.protocol = "rtsp";
 | 
				
			||||||
    setup_url.protocol = "rtsp";
 | 
						}
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setup_url_str = compose_url(setup_url);
 | 
						setup_url_str = compose_url(setup_url);
 | 
				
			||||||
  psz_setup_url = setup_url_str.c_str();
 | 
						psz_setup_url = setup_url_str.c_str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO: Find available port
 | 
						// TODO: Find available port
 | 
				
			||||||
  rtsp->udp_sock = Socket(af_inet, pf_inet, sock_dgram, udp);
 | 
						rtsp->udp_sock = Socket(af_inet, pf_inet, sock_dgram, udp);
 | 
				
			||||||
  rtsp->udp_port = 6785;
 | 
						rtsp->udp_port = 6785;
 | 
				
			||||||
  if (!rtsp->udp_sock.bind(rtsp->udp_port))
 | 
						if(!rtsp->udp_sock.bind(rtsp->udp_port)) {
 | 
				
			||||||
  {
 | 
							goto error;
 | 
				
			||||||
    goto error;
 | 
						}
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setup_ss << "SETUP " << setup_url_str << " RTSP/1.0\r\n";
 | 
						setup_ss << "SETUP " << setup_url_str<< " RTSP/1.0\r\n";
 | 
				
			||||||
  setup_ss << "CSeq: " << rtsp->cseq++ << "\r\n";
 | 
						setup_ss << "CSeq: " << rtsp->cseq++ << "\r\n";
 | 
				
			||||||
  setup_ss << "Transport: RTP/AVP;unicast;client_port=" << rtsp->udp_port << "-"
 | 
						setup_ss << "Transport: RTP/AVP;unicast;client_port=" << rtsp->udp_port << "-" << (rtsp->udp_port + 1) << "\r\n\r\n";
 | 
				
			||||||
           << (rtsp->udp_port + 1) << "\r\n\r\n";
 | 
						rtsp->tcp_sock.send(setup_ss.str());
 | 
				
			||||||
  rtsp->tcp_sock.send(setup_ss.str());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rtsp_handle() != RTSP_RESULT_OK)
 | 
						if (rtsp_handle() != RTSP_RESULT_OK) {
 | 
				
			||||||
  {
 | 
							kodi->Log(LOG_ERROR, "Failed to setup RTSP session");
 | 
				
			||||||
    kodi::Log(ADDON_LOG_ERROR, "Failed to setup RTSP session");
 | 
							goto error;
 | 
				
			||||||
    goto error;
 | 
						}
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (asprintf(&rtsp->control, "%sstream=%d", rtsp->content_base, rtsp->stream_id) < 0)
 | 
						if (asprintf(&rtsp->control, "%sstream=%d", rtsp->content_base, rtsp->stream_id) < 0) {
 | 
				
			||||||
  {
 | 
							rtsp->control = NULL;
 | 
				
			||||||
    rtsp->control = nullptr;
 | 
							goto error;
 | 
				
			||||||
    goto error;
 | 
						}
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  play_ss << "PLAY " << rtsp->control << " RTSP/1.0\r\n";
 | 
						play_ss << "PLAY " << rtsp->control << " RTSP/1.0\r\n";
 | 
				
			||||||
  play_ss << "CSeq: " << rtsp->cseq++ << "\r\n";
 | 
						play_ss << "CSeq: " << rtsp->cseq++ << "\r\n";
 | 
				
			||||||
  play_ss << "Session: " << rtsp->session_id << "\r\n\r\n";
 | 
						play_ss << "Session: " << rtsp->session_id << "\r\n\r\n";
 | 
				
			||||||
  rtsp->tcp_sock.send(play_ss.str());
 | 
						rtsp->tcp_sock.send(play_ss.str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rtsp_handle() != RTSP_RESULT_OK)
 | 
						if (rtsp_handle() != RTSP_RESULT_OK) {
 | 
				
			||||||
  {
 | 
							kodi->Log(LOG_ERROR, "Failed to play RTSP session");
 | 
				
			||||||
    kodi::Log(ADDON_LOG_ERROR, "Failed to play RTSP session");
 | 
							goto error;
 | 
				
			||||||
    goto error;
 | 
						}
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rtsp->rtcp_sock = Socket(af_inet, pf_inet, sock_dgram, udp);
 | 
						rtsp->rtcp_sock = Socket(af_inet, pf_inet, sock_dgram, udp);
 | 
				
			||||||
  if (!rtsp->rtcp_sock.bind(rtsp->udp_port + 1))
 | 
						if(!rtsp->rtcp_sock.bind(rtsp->udp_port + 1)) {
 | 
				
			||||||
  {
 | 
							goto error;
 | 
				
			||||||
    goto error;
 | 
						}
 | 
				
			||||||
  }
 | 
						if(!rtsp->rtcp_sock.set_non_blocking(true)) {
 | 
				
			||||||
  if (!rtsp->rtcp_sock.set_non_blocking(true))
 | 
							goto error;
 | 
				
			||||||
  {
 | 
						}
 | 
				
			||||||
    goto error;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return true;
 | 
						return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
  rtsp_close();
 | 
						rtsp_close();
 | 
				
			||||||
  return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void parse_rtcp(const char* buf, int size)
 | 
					static void parse_rtcp(const char *buf, int size) {
 | 
				
			||||||
{
 | 
						int offset = 0;
 | 
				
			||||||
  int offset = 0;
 | 
						while(size > 4) {
 | 
				
			||||||
  while (size > 4)
 | 
							const rtcp_app *app = reinterpret_cast<const rtcp_app *>(buf + offset);
 | 
				
			||||||
  {
 | 
							uint16_t len = 4 * (ntohs(app->len) + 1);
 | 
				
			||||||
    const rtcp_app* app = reinterpret_cast<const rtcp_app*>(buf + offset);
 | 
					 | 
				
			||||||
    uint16_t len = 4 * (ntohs(app->len) + 1);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((app->pt != 204) || (memcmp(app->name, "SES1", 4) != 0))
 | 
							if((app->pt != 204) || (memcmp(app->name, "SES1", 4) != 0)) {
 | 
				
			||||||
    {
 | 
								size -= len;
 | 
				
			||||||
      size -= len;
 | 
								offset += len;
 | 
				
			||||||
      offset += len;
 | 
								continue;
 | 
				
			||||||
      continue;
 | 
							}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint16_t string_len = ntohs(app->string_len);
 | 
							uint16_t string_len = ntohs(app->string_len);
 | 
				
			||||||
    string app_data(&buf[offset + sizeof(rtcp_app)], string_len);
 | 
							string app_data(&buf[offset + sizeof(rtcp_app)], string_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vector<string> elems;
 | 
							vector<string> elems;
 | 
				
			||||||
    split_string(app_data, ';', elems);
 | 
							split_string(app_data, ';', elems);
 | 
				
			||||||
    if (elems.size() != 4)
 | 
							if(elems.size() != 4) {
 | 
				
			||||||
    {
 | 
								return;
 | 
				
			||||||
      return;
 | 
							}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vector<string> tuner;
 | 
							vector<string> tuner;
 | 
				
			||||||
    split_string(elems[2], ',', tuner);
 | 
							split_string(elems[2], ',', tuner);
 | 
				
			||||||
    if (tuner.size() < 4)
 | 
							if(tuner.size() < 4) {
 | 
				
			||||||
    {
 | 
								return;
 | 
				
			||||||
      return;
 | 
							}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rtsp->level = atoi(tuner[1].c_str());
 | 
							rtsp->level = atoi(tuner[1].c_str());
 | 
				
			||||||
    rtsp->quality = atoi(tuner[3].c_str());
 | 
							rtsp->quality = atoi(tuner[3].c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return;
 | 
							return;
 | 
				
			||||||
  }
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int rtsp_read(void* buf, unsigned buf_size)
 | 
					int rtsp_read(void *buf, unsigned buf_size) {
 | 
				
			||||||
{
 | 
						sockaddr addr;
 | 
				
			||||||
  sockaddr addr;
 | 
						socklen_t addr_len = sizeof(addr);
 | 
				
			||||||
  socklen_t addr_len = sizeof(addr);
 | 
						int ret = rtsp->udp_sock.recvfrom((char *)buf, buf_size, (sockaddr *)&addr, &addr_len);
 | 
				
			||||||
  int ret = rtsp->udp_sock.recvfrom((char*)buf, buf_size, (sockaddr*)&addr, &addr_len);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  char rtcp_buf[RTCP_BUFFER_SIZE];
 | 
						char rtcp_buf[RTCP_BUFFER_SIZE];
 | 
				
			||||||
  int rtcp_len = rtsp->rtcp_sock.recvfrom(rtcp_buf, RTCP_BUFFER_SIZE, (sockaddr*)&addr, &addr_len);
 | 
						int rtcp_len = rtsp->rtcp_sock.recvfrom(rtcp_buf, RTCP_BUFFER_SIZE, (sockaddr *)&addr, &addr_len);
 | 
				
			||||||
  parse_rtcp(rtcp_buf, rtcp_len);
 | 
						parse_rtcp(rtcp_buf, rtcp_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO: check ip
 | 
						// TODO: check ip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void rtsp_teardown()
 | 
					static void rtsp_teardown() {
 | 
				
			||||||
{
 | 
						if(!rtsp->tcp_sock.is_valid()) {
 | 
				
			||||||
  if (!rtsp->tcp_sock.is_valid())
 | 
							return;
 | 
				
			||||||
  {
 | 
						}
 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rtsp->session_id[0] > 0)
 | 
						if (rtsp->session_id[0] > 0) {
 | 
				
			||||||
  {
 | 
							char *msg;
 | 
				
			||||||
    char* msg;
 | 
							int len;
 | 
				
			||||||
    int len;
 | 
							stringstream ss;
 | 
				
			||||||
    stringstream ss;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rtsp->udp_sock.close();
 | 
							rtsp->udp_sock.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss << "TEARDOWN " << rtsp->control << " RTSP/1.0\r\n";
 | 
							ss << "TEARDOWN " << rtsp->control << " RTSP/1.0\r\n";
 | 
				
			||||||
    ss << "CSeq: " << rtsp->cseq++ << "\r\n";
 | 
							ss << "CSeq: " << rtsp->cseq++ << "\r\n";
 | 
				
			||||||
    ss << "Session: " << rtsp->session_id << "\r\n\r\n";
 | 
							ss << "Session: " << rtsp->session_id << "\r\n\r\n";
 | 
				
			||||||
    rtsp->tcp_sock.send(ss.str());
 | 
							rtsp->tcp_sock.send(ss.str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (rtsp_handle() != RTSP_RESULT_OK)
 | 
							if (rtsp_handle() != RTSP_RESULT_OK) {
 | 
				
			||||||
    {
 | 
								kodi->Log(LOG_ERROR, "Failed to teardown RTSP session");
 | 
				
			||||||
      kodi::Log(ADDON_LOG_ERROR, "Failed to teardown RTSP session");
 | 
								return;
 | 
				
			||||||
      return;
 | 
							}
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void rtsp_close()
 | 
					void rtsp_close()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (rtsp)
 | 
						if(rtsp) {
 | 
				
			||||||
  {
 | 
							rtsp_teardown();
 | 
				
			||||||
    rtsp_teardown();
 | 
							rtsp->tcp_sock.close();
 | 
				
			||||||
    rtsp->tcp_sock.close();
 | 
							rtsp->udp_sock.close();
 | 
				
			||||||
    rtsp->udp_sock.close();
 | 
							rtsp->rtcp_sock.close();
 | 
				
			||||||
    rtsp->rtcp_sock.close();
 | 
							delete rtsp;
 | 
				
			||||||
    delete rtsp;
 | 
							rtsp = NULL;
 | 
				
			||||||
    rtsp = nullptr;
 | 
						}
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void rtsp_fill_signal_status(kodi::addon::PVRSignalStatus& signal_status)
 | 
					void rtsp_fill_signal_status(PVR_SIGNAL_STATUS& signal_status) {
 | 
				
			||||||
{
 | 
						if(rtsp) {
 | 
				
			||||||
  if (rtsp)
 | 
							strncpy(signal_status.strServiceName, rtsp->name.c_str(), PVR_ADDON_NAME_STRING_LENGTH - 1);
 | 
				
			||||||
  {
 | 
							signal_status.iSNR = 0x1111 * rtsp->quality;
 | 
				
			||||||
    signal_status.SetAdapterName(rtsp->name);
 | 
							signal_status.iSignal = 0x101 * rtsp->level;
 | 
				
			||||||
    signal_status.SetSNR(0x1111 * rtsp->quality);
 | 
						}
 | 
				
			||||||
    signal_status.SetSignal(0x101 * rtsp->level);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,12 @@
 | 
				
			|||||||
/*
 | 
					#ifndef _RTSP_CLIENT_HPP_
 | 
				
			||||||
 *  Copyright (C) 2005-2020 Team Kodi
 | 
					#define _RTSP_CLIENT_HPP_
 | 
				
			||||||
 *  https://kodi.tv
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  SPDX-License-Identifier: GPL-2.0-or-later
 | 
					 | 
				
			||||||
 *  See LICENSE.md for more information.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <kodi/addon-instance/pvr/Channels.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <xbmc_pvr_types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool rtsp_open(const std::string& name, const std::string& url_str);
 | 
					bool rtsp_open(const std::string& name, const std::string& url_str);
 | 
				
			||||||
void rtsp_close();
 | 
					void rtsp_close();
 | 
				
			||||||
int rtsp_read(void* buf, unsigned buf_size);
 | 
					int rtsp_read(void *buf, unsigned buf_size);
 | 
				
			||||||
void rtsp_fill_signal_status(kodi::addon::PVRSignalStatus& signal_status);
 | 
					void rtsp_fill_signal_status(PVR_SIGNAL_STATUS& signal_status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user