parent
11b452df03
commit
9cc824cb5d
|
|
@ -0,0 +1,2 @@
|
|||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,4 @@
|
|||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
./gradlew build
|
||||
java -jar build/libs/portmapper-*.jar
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
id 'eclipse'
|
||||
id "com.github.hierynomus.license" version "0.13.1"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven { url 'http://4thline.org/m2' }
|
||||
jcenter()
|
||||
flatDir { dirs 'lib' }
|
||||
}
|
||||
|
||||
version = '2.0.0'
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs << '-Xlint:all'
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
||||
test {
|
||||
if(logger.infoEnabled) {
|
||||
testLogging.showStandardStreams = true
|
||||
}
|
||||
jvmArgs '-XX:+HeapDumpOnOutOfMemoryError', '-enableassertions'
|
||||
}
|
||||
|
||||
processResources {
|
||||
rename(/(\w+)_en.properties/, '$1.properties')
|
||||
}
|
||||
|
||||
task replaceVersionTokenInTranslations {
|
||||
doLast {
|
||||
ant.replace(dir: 'build/resources/main', encoding: 'ISO-8859-1') {
|
||||
include(name: '**/*.properties')
|
||||
replacefilter(token: '@VERSION_NUMBER@', value: project.version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jar.dependsOn(replaceVersionTokenInTranslations)
|
||||
|
||||
jar {
|
||||
from {
|
||||
configurations.compile.collect {
|
||||
it.isDirectory() ? it : zipTree(it)
|
||||
}
|
||||
configurations.runtime.collect {
|
||||
it.isDirectory() ? it : zipTree(it)
|
||||
}
|
||||
}
|
||||
manifest { attributes 'Main-Class': 'org.chris.portmapper.PortMapperStarter' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile 'org.mockito:mockito-core:2.1.0'
|
||||
|
||||
compile 'args4j:args4j:2.33'
|
||||
compile 'org.slf4j:slf4j-api:1.7.22'
|
||||
compile 'ch.qos.logback:logback-classic:1.1.8'
|
||||
compile 'com.miglayout:miglayout-swing:5.0'
|
||||
compile 'org.jdesktop.bsaf:bsaf:1.9.2'
|
||||
compile ':sbbi-upnplib:1.0.4'
|
||||
compile 'org.fourthline.cling:cling-support:2.1.1'
|
||||
compile 'org.bitlet:weupnp:0.1.4'
|
||||
|
||||
runtime 'commons-jxpath:commons-jxpath:1.1' // sbbi
|
||||
compile 'org.slf4j:jul-to-slf4j:1.7.22'
|
||||
}
|
||||
|
||||
license {
|
||||
header = file('gradle/license-header.txt')
|
||||
ext.year = 2015
|
||||
ext.name = 'Christoph Pirkl'
|
||||
ext.email = 'christoph at users.sourceforge.net'
|
||||
}
|
||||
|
||||
eclipse {
|
||||
classpath {
|
||||
downloadSources = true
|
||||
}
|
||||
jdt.file {
|
||||
beforeMerged { jdt ->
|
||||
File defaultProperties = new File("${rootProject.projectDir}/gradle/defaultEclipseJdtPrefs.properties").absoluteFile
|
||||
logger.info "Load defaults from $defaultProperties for $project"
|
||||
jdt.load(defaultProperties)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${workspace}"/>
|
||||
<stringAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_ENCODING" value="UTF-8"/>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/PortMapper/gradlew.bat}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="clean build --info"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/PortMapper}"/>
|
||||
</launchConfiguration>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/PortMapper/src/org/chris/portmapper/PortMapperStarter.java"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="1"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||
</listAttribute>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.chris.portmapper.PortMapperStarter"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="PortMapper"/>
|
||||
</launchConfiguration>
|
||||
|
|
@ -0,0 +1,313 @@
|
|||
# Template for org.eclipse.jdt.core.prefs, used by build.gradle
|
||||
|
||||
# The following settings will be overwritten by gradle:
|
||||
#eclipse.preferences.version=1
|
||||
#org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
#org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
#org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
#org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
#org.eclipse.jdt.core.compiler.source=1.8
|
||||
|
||||
# Formatter settings:
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.codeComplete.argumentPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.argumentSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.fieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.fieldSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.localPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.localSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=120
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=2
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
|
||||
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.lineSplit=120
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=space
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=4
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
Copyright (C) ${year} ${name} <${email}>
|
||||
|
||||
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 3 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/>.
|
||||
Binary file not shown.
|
|
@ -0,0 +1,6 @@
|
|||
#Sun Jun 18 20:27:21 CEST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-bin.zip
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
Binary file not shown.
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper;
|
||||
|
||||
import org.chris.portmapper.model.Protocol;
|
||||
import org.kohsuke.args4j.CmdLineException;
|
||||
import org.kohsuke.args4j.CmdLineParser;
|
||||
import org.kohsuke.args4j.Option;
|
||||
import org.kohsuke.args4j.ParserProperties;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
|
||||
public class CommandLineArguments {
|
||||
|
||||
@Option(name = "-add", usage = "add pf", depends = { "-internalPort", "-externalPort",
|
||||
"-protocol" }, forbids = { "-gui", "-delete", "-info", "-list" })
|
||||
private boolean addPortMapping;
|
||||
@Option(name = "-delete", usage = "delete pf", depends = { "-externalPort",
|
||||
"-protocol" }, forbids = { "-gui", "-add", "-info", "-list" })
|
||||
private boolean deletePortMapping;
|
||||
@Option(name = "-info", usage = "router info", forbids = { "-gui", "-delete", "-add", "-list" })
|
||||
private boolean printInfo;
|
||||
@Option(name = "-list", usage = "print pf", forbids = { "-gui", "-delete", "-info", "-add" })
|
||||
private boolean listPortMappings;
|
||||
|
||||
@Option(name = "-ip", usage = "Internal IP of the port mapping (default: localhost)")
|
||||
private String internalIp;
|
||||
@Option(name = "-internalPort", usage = "Internal port of the port mapping")
|
||||
private int internalPort;
|
||||
@Option(name = "-externalPort", usage = "External port of the port mapping")
|
||||
private int externalPort;
|
||||
@Option(name = "-protocol", usage = "Protocol of the port mapping")
|
||||
private Protocol protocol;
|
||||
@Option(name = "-description", usage = "Description of the port mapping")
|
||||
private String description;
|
||||
|
||||
@Option(name = "-lib", usage = "UPnP library")
|
||||
private String upnpLib;
|
||||
|
||||
@Option(name = "-routerIndex", usage = "router index")
|
||||
private Integer routerIndex;
|
||||
|
||||
private final CmdLineParser parser;
|
||||
|
||||
public CommandLineArguments() {
|
||||
parser = new CmdLineParser(this, ParserProperties.defaults().withShowDefaults(true).withUsageWidth(80));
|
||||
}
|
||||
|
||||
public boolean parse(final String[] args) {
|
||||
try {
|
||||
parser.parseArgument(asList(args));
|
||||
return true;
|
||||
} catch (final CmdLineException e) {
|
||||
System.err.println(e.getMessage());
|
||||
printHelp();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAddPortMapping() {
|
||||
return addPortMapping;
|
||||
}
|
||||
|
||||
public boolean isDeletePortMapping() {
|
||||
return deletePortMapping;
|
||||
}
|
||||
|
||||
public boolean isPrintInfo() {
|
||||
return printInfo;
|
||||
}
|
||||
|
||||
public boolean isListPortMappings() {
|
||||
return listPortMappings;
|
||||
}
|
||||
|
||||
public String getInternalIp() {
|
||||
return internalIp;
|
||||
}
|
||||
|
||||
public int getInternalPort() {
|
||||
return internalPort;
|
||||
}
|
||||
|
||||
public int getExternalPort() {
|
||||
return externalPort;
|
||||
}
|
||||
|
||||
public Protocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public String getUpnpLib() {
|
||||
return upnpLib;
|
||||
}
|
||||
|
||||
public Integer getRouterIndex() {
|
||||
return routerIndex;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper;
|
||||
|
||||
/**
|
||||
* This class contains mac specific settings for the application name and the application menu.
|
||||
*/
|
||||
public class MacSetup {
|
||||
|
||||
public static void setupMac() {
|
||||
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "UPnP PortMapper");
|
||||
System.setProperty("apple.laf.useScreenMenuBar", "true");
|
||||
System.setProperty("apple.awt.brushMetalLook", "false");
|
||||
System.setProperty("com.apple.mrj.application.growbox.intrudes", "false");
|
||||
System.setProperty("com.apple.mrj.application.live-resize", "true");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,389 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EventObject;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import org.chris.portmapper.gui.PortMapperView;
|
||||
import org.chris.portmapper.logging.LogMessageListener;
|
||||
import org.chris.portmapper.logging.LogMessageOutputStream;
|
||||
import org.chris.portmapper.logging.LogbackConfiguration;
|
||||
import org.chris.portmapper.model.PortMappingPreset;
|
||||
import org.chris.portmapper.router.AbstractRouterFactory;
|
||||
import org.chris.portmapper.router.IRouter;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
import org.jdesktop.application.ResourceMap;
|
||||
import org.jdesktop.application.SingleFrameApplication;
|
||||
import org.jdesktop.application.utils.AppHelper;
|
||||
import org.jdesktop.application.utils.OSXAdapter;
|
||||
import org.jdesktop.application.utils.PlatformType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The main application class
|
||||
*/
|
||||
public class PortMapperApp extends SingleFrameApplication {
|
||||
|
||||
/**
|
||||
* The name of the system property which will be used as the directory where all configuration files will be stored.
|
||||
*/
|
||||
private static final String CONFIG_DIR_PROPERTY_NAME = "portmapper.config.dir";
|
||||
|
||||
/**
|
||||
* The file name for the settings file.
|
||||
*/
|
||||
private static final String SETTINGS_FILENAME = "settings.xml";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private IRouter router;
|
||||
private Settings settings;
|
||||
private final LogMessageOutputStream logMessageOutputStream = new LogMessageOutputStream();
|
||||
private final LogbackConfiguration logbackConfig = new LogbackConfiguration();
|
||||
|
||||
@Override
|
||||
protected void startup() {
|
||||
logbackConfig.registerOutputStream(logMessageOutputStream);
|
||||
|
||||
setCustomConfigDir();
|
||||
|
||||
loadSettings();
|
||||
|
||||
final PortMapperView view = new PortMapperView(this);
|
||||
addExitListener(new ExitListener() {
|
||||
@Override
|
||||
public boolean canExit(final EventObject arg0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void willExit(final EventObject arg0) {
|
||||
disconnectRouter();
|
||||
}
|
||||
});
|
||||
|
||||
show(view);
|
||||
|
||||
if (AppHelper.getPlatform() == PlatformType.OS_X) {
|
||||
registerMacOSXListeners();
|
||||
}
|
||||
}
|
||||
|
||||
private void registerMacOSXListeners() {
|
||||
final PortMapperView view = getView();
|
||||
OSXAdapter.setPreferencesHandler(view, getMethod(PortMapperView.class, "changeSettings"));
|
||||
OSXAdapter.setAboutHandler(view, getMethod(PortMapperView.class, "showAboutDialog"));
|
||||
}
|
||||
|
||||
private static Method getMethod(final Class<?> clazz, final String name, final Class<?>... parameterTypes) {
|
||||
try {
|
||||
return clazz.getMethod(name, parameterTypes);
|
||||
} catch (final SecurityException e) {
|
||||
throw new RuntimeException("Error getting method " + name + " of class " + clazz.getName(), e);
|
||||
} catch (final NoSuchMethodException e) {
|
||||
throw new RuntimeException("Error getting method " + name + " of class " + clazz.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the system property with name {@link PortMapperApp#CONFIG_DIR_PROPERTY_NAME} and change the local storage
|
||||
* directory if the property is given and points to a writable directory. If there is a directory named
|
||||
* <code>PortMapperConf</code> in the current directory, use this as the configuration directory.
|
||||
*/
|
||||
private void setCustomConfigDir() {
|
||||
final String customConfigurationDir = System.getProperty(CONFIG_DIR_PROPERTY_NAME);
|
||||
final File portableAppConfigDir = new File("PortMapperConf");
|
||||
|
||||
// the property is set: check, if the given directory can be used
|
||||
if (customConfigurationDir != null) {
|
||||
final File dir = new File(customConfigurationDir);
|
||||
if (!dir.isDirectory()) {
|
||||
logger.error("Custom configuration directory '{}' is not a directory.", customConfigurationDir);
|
||||
System.exit(1);
|
||||
}
|
||||
if (!dir.canRead() || !dir.canWrite()) {
|
||||
logger.error("Can not read or write to custom configuration directory '{}'.", customConfigurationDir);
|
||||
System.exit(1);
|
||||
}
|
||||
logger.info("Using custom configuration directory '{}'.", dir.getAbsolutePath());
|
||||
getContext().getLocalStorage().setDirectory(dir);
|
||||
|
||||
// check, if the portable app directory exists and use this one
|
||||
} else if (portableAppConfigDir.isDirectory() && portableAppConfigDir.canRead()
|
||||
&& portableAppConfigDir.canWrite()) {
|
||||
logger.info("Found portable app configuration directory '{}'.", portableAppConfigDir.getAbsolutePath());
|
||||
getContext().getLocalStorage().setDirectory(portableAppConfigDir);
|
||||
|
||||
// use the default configuration directory
|
||||
} else {
|
||||
logger.info("Using default configuration directory '{}'.",
|
||||
getContext().getLocalStorage().getDirectory().getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the application settings from file {@link PortMapperApp#SETTINGS_FILENAME} located in the configuration
|
||||
* directory.
|
||||
*/
|
||||
private void loadSettings() {
|
||||
logger.debug("Loading settings from file {}", SETTINGS_FILENAME);
|
||||
try {
|
||||
settings = (Settings) getContext().getLocalStorage().load(SETTINGS_FILENAME);
|
||||
} catch (final IOException e) {
|
||||
logger.warn("Could not load settings from file " + SETTINGS_FILENAME, e);
|
||||
}
|
||||
|
||||
if (settings == null) {
|
||||
logger.debug("Settings were not loaded from file {}: create new settings", SETTINGS_FILENAME);
|
||||
settings = new Settings();
|
||||
} else {
|
||||
logger.debug("Got settings {}", settings);
|
||||
this.setLogLevel(settings.getLogLevel());
|
||||
}
|
||||
}
|
||||
|
||||
public void setLogMessageListener(final LogMessageListener listener) {
|
||||
this.logMessageOutputStream.registerListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutdown() {
|
||||
super.shutdown();
|
||||
logger.debug("Saving settings {} to file {}", settings, SETTINGS_FILENAME);
|
||||
if (logger.isTraceEnabled()) {
|
||||
for (final PortMappingPreset preset : settings.getPresets()) {
|
||||
logger.trace("Saving port mapping {}", preset.getCompleteDescription());
|
||||
}
|
||||
}
|
||||
try {
|
||||
getContext().getLocalStorage().save(settings, SETTINGS_FILENAME);
|
||||
} catch (final IOException e) {
|
||||
logger.warn("Could not save settings to file " + SETTINGS_FILENAME, e);
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceMap getResourceMap() {
|
||||
return getContext().getResourceMap();
|
||||
}
|
||||
|
||||
public PortMapperView getView() {
|
||||
return (PortMapperView) getMainView();
|
||||
}
|
||||
|
||||
public void connectRouter() throws RouterException {
|
||||
if (this.router != null) {
|
||||
logger.warn("Already connected to router. Cannot create a second connection.");
|
||||
return;
|
||||
}
|
||||
|
||||
final AbstractRouterFactory routerFactory;
|
||||
try {
|
||||
routerFactory = createRouterFactory();
|
||||
} catch (final RouterException e) {
|
||||
logger.error("Could not create router factory: " + e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
logger.info("Searching for routers...");
|
||||
|
||||
final Collection<IRouter> foundRouters = routerFactory.findRouters();
|
||||
|
||||
// No routers found
|
||||
if (foundRouters == null || foundRouters.size() == 0) {
|
||||
throw new RouterException("Did not find a router");
|
||||
}
|
||||
|
||||
// One router found: use it.
|
||||
if (foundRouters.size() == 1) {
|
||||
router = foundRouters.iterator().next();
|
||||
logger.info("Connected to router '{}'", router.getName());
|
||||
this.getView().fireConnectionStateChange();
|
||||
return;
|
||||
}
|
||||
|
||||
// More than one router found: ask user.
|
||||
logger.info("Found more than one router (count: {}): ask user.", foundRouters.size());
|
||||
|
||||
final ResourceMap resourceMap = getResourceMap();
|
||||
final IRouter selectedRouter = (IRouter) JOptionPane.showInputDialog(this.getView().getFrame(),
|
||||
resourceMap.getString("messages.select_router.message"),
|
||||
resourceMap.getString("messages.select_router.title"), JOptionPane.QUESTION_MESSAGE, null,
|
||||
foundRouters.toArray(), null);
|
||||
|
||||
if (selectedRouter == null) {
|
||||
logger.info("No router selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.router = selectedRouter;
|
||||
this.getView().fireConnectionStateChange();
|
||||
}
|
||||
|
||||
private AbstractRouterFactory createRouterFactory() throws RouterException {
|
||||
logger.info("Creating router factory for class {}", settings.getRouterFactoryClassName());
|
||||
final Class<AbstractRouterFactory> routerFactoryClass = getClassForName(settings.getRouterFactoryClassName());
|
||||
final Constructor<AbstractRouterFactory> constructor = getConstructor(routerFactoryClass);
|
||||
final AbstractRouterFactory routerFactory = createInstance(constructor);
|
||||
logger.debug("Router factory {} created", routerFactory);
|
||||
return routerFactory;
|
||||
}
|
||||
|
||||
private AbstractRouterFactory createInstance(final Constructor<AbstractRouterFactory> constructor)
|
||||
throws RouterException {
|
||||
try {
|
||||
return constructor.newInstance(this);
|
||||
} catch (final Exception e) {
|
||||
throw new RouterException("Could not create a router factory using constructor " + constructor, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Constructor<AbstractRouterFactory> getConstructor(final Class<AbstractRouterFactory> clazz)
|
||||
throws RouterException {
|
||||
try {
|
||||
return clazz.getConstructor(PortMapperApp.class);
|
||||
} catch (final NoSuchMethodException e) {
|
||||
throw new RouterException("Could not find constructor of " + clazz.getName(), e);
|
||||
} catch (final SecurityException e1) {
|
||||
throw new RouterException("Could not find constructor of " + clazz.getName(), e1);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Class<AbstractRouterFactory> getClassForName(final String className) throws RouterException {
|
||||
try {
|
||||
return (Class<AbstractRouterFactory>) Class.forName(className);
|
||||
} catch (final ClassNotFoundException e) {
|
||||
throw new RouterException("Did not find router factory class for name " + className, e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean disconnectRouter() {
|
||||
if (this.router == null) {
|
||||
logger.warn("Not connected to router. Can not disconnect.");
|
||||
return false;
|
||||
}
|
||||
|
||||
this.router.disconnect();
|
||||
this.router = null;
|
||||
this.getView().fireConnectionStateChange();
|
||||
return true;
|
||||
}
|
||||
|
||||
public IRouter getRouter() {
|
||||
return router;
|
||||
}
|
||||
|
||||
public Settings getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return this.getRouter() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IP address of the local host.
|
||||
*
|
||||
* @return IP address of the local host or <code>null</code>, if the address could not be determined.
|
||||
* @throws RouterException
|
||||
*/
|
||||
public String getLocalHostAddress() {
|
||||
|
||||
try {
|
||||
if (router != null) {
|
||||
logger.debug("Connected to router, get IP of localhost from socket...");
|
||||
return router.getLocalHostAddress();
|
||||
}
|
||||
|
||||
logger.debug("Not connected to router, get IP of localhost from network interface...");
|
||||
final InetAddress address = getLocalhostAddressFromNetworkInterface();
|
||||
if (address != null) {
|
||||
return address.getHostAddress();
|
||||
} else {
|
||||
logger.warn("Did not get IP of localhost from network interface");
|
||||
}
|
||||
|
||||
} catch (final RouterException e) {
|
||||
logger.warn("Could not get address of localhost.", e);
|
||||
logger.warn("Could not get address of localhost. Please enter it manually.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private InetAddress getLocalhostAddressFromNetworkInterface() throws RouterException {
|
||||
try {
|
||||
final List<NetworkInterface> networkInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
||||
logger.trace("Found network interfaces " + networkInterfaces);
|
||||
for (final NetworkInterface nInterface : networkInterfaces) {
|
||||
if (nInterface.isLoopback()) {
|
||||
logger.debug("Found loopback network interface " + nInterface.getDisplayName() + "/"
|
||||
+ nInterface.getName() + " with IPs " + nInterface.getInterfaceAddresses() + ": ignore.");
|
||||
} else if (!nInterface.isUp()) {
|
||||
logger.debug("Found inactive network interface " + nInterface.getDisplayName() + "/"
|
||||
+ nInterface.getName() + " with IPs " + nInterface.getInterfaceAddresses() + ": ignore.");
|
||||
} else {
|
||||
logger.debug("Found network interface " + nInterface.getDisplayName() + "/" + nInterface.getName()
|
||||
+ " with IPs " + nInterface.getInterfaceAddresses() + ": use this one.");
|
||||
final List<InetAddress> addresses = Collections.list(nInterface.getInetAddresses());
|
||||
if (addresses.size() > 0) {
|
||||
final InetAddress address = findIPv4Adress(nInterface, addresses);
|
||||
logger.debug("Found one address for network interface " + nInterface.getName() + ": using "
|
||||
+ address);
|
||||
return address;
|
||||
}
|
||||
logger.debug("Network interface " + nInterface.getName() + " has no addresses.");
|
||||
}
|
||||
}
|
||||
} catch (final SocketException e) {
|
||||
throw new RouterException("Did not get network interfaces.", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private InetAddress findIPv4Adress(final NetworkInterface nInterface, final List<InetAddress> addresses) {
|
||||
if (addresses.size() == 1) {
|
||||
return addresses.get(0);
|
||||
}
|
||||
|
||||
for (final InetAddress inetAddress : addresses) {
|
||||
if (inetAddress.getHostAddress().contains(".")) {
|
||||
logger.debug("Found IPv4 address " + inetAddress);
|
||||
return inetAddress;
|
||||
}
|
||||
}
|
||||
final InetAddress address = addresses.get(0);
|
||||
logger.info("Found more than one address for network interface " + nInterface.getName() + ": using " + address);
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setLogLevel(final String logLevel) {
|
||||
this.logbackConfig.setLogLevel(logLevel);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.chris.portmapper.model.Protocol;
|
||||
import org.chris.portmapper.router.AbstractRouterFactory;
|
||||
import org.chris.portmapper.router.IRouter;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
import org.chris.portmapper.router.cling.ClingRouterFactory;
|
||||
import org.jdesktop.application.Application;
|
||||
import org.jdesktop.application.utils.AppHelper;
|
||||
import org.jdesktop.application.utils.PlatformType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PortMapperCli {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final CommandLineArguments cmdLineArgs;
|
||||
private String routerFactoryClassName = ClingRouterFactory.class.getName();
|
||||
private Integer routerIndex = null;
|
||||
|
||||
public PortMapperCli() {
|
||||
cmdLineArgs = new CommandLineArguments();
|
||||
}
|
||||
|
||||
public void start(final String[] args) {
|
||||
if (!cmdLineArgs.parse(args)) {
|
||||
System.exit(1);
|
||||
}
|
||||
if (isStartGuiRequired()) {
|
||||
startGui(args);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLineArgs.getUpnpLib() != null) {
|
||||
this.routerFactoryClassName = cmdLineArgs.getUpnpLib();
|
||||
logger.info("Using router factory class '" + this.routerFactoryClassName + "'");
|
||||
}
|
||||
|
||||
if (cmdLineArgs.getRouterIndex() != null) {
|
||||
this.routerIndex = cmdLineArgs.getRouterIndex();
|
||||
logger.info("Using router index " + this.routerIndex);
|
||||
}
|
||||
|
||||
if (cmdLineArgs.isPrintHelp()) {
|
||||
printHelp();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final IRouter router = connect();
|
||||
if (router == null) {
|
||||
logger.error("No router found: exit");
|
||||
System.exit(1);
|
||||
return;
|
||||
}
|
||||
if (cmdLineArgs.isAddPortMapping()) {
|
||||
addPortForwarding(router);
|
||||
} else if (cmdLineArgs.isPrintInfo()) {
|
||||
printStatus(router);
|
||||
} else if (cmdLineArgs.isDeletePortMapping()) {
|
||||
deletePortForwardings(router);
|
||||
} else if (cmdLineArgs.isListPortMappings()) {
|
||||
printPortForwardings(router);
|
||||
} else {
|
||||
router.disconnect();
|
||||
System.err.println("Incorrect usage");
|
||||
printHelp();
|
||||
System.exit(1);
|
||||
return;
|
||||
}
|
||||
router.disconnect();
|
||||
} catch (final RouterException e) {
|
||||
logger.error("An error occured", e);
|
||||
System.exit(1);
|
||||
return;
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private void startGui(final String[] args) {
|
||||
if (AppHelper.getPlatform() == PlatformType.OS_X) {
|
||||
MacSetup.setupMac();
|
||||
}
|
||||
Application.launch(PortMapperApp.class, args);
|
||||
}
|
||||
|
||||
private void printPortForwardings(final IRouter router) throws RouterException {
|
||||
final Collection<PortMapping> mappings = router.getPortMappings();
|
||||
if (mappings.size() == 0) {
|
||||
logger.info("No port mappings found");
|
||||
return;
|
||||
}
|
||||
final StringBuilder b = new StringBuilder();
|
||||
for (final Iterator<PortMapping> iterator = mappings.iterator(); iterator.hasNext();) {
|
||||
final PortMapping mapping = iterator.next();
|
||||
b.append(mapping.getCompleteDescription());
|
||||
if (iterator.hasNext()) {
|
||||
b.append("\n");
|
||||
}
|
||||
}
|
||||
logger.info("Found " + mappings.size() + " port forwardings:\n" + b.toString());
|
||||
}
|
||||
|
||||
private void deletePortForwardings(final IRouter router) throws RouterException {
|
||||
|
||||
final String remoteHost = null;
|
||||
final int port = cmdLineArgs.getExternalPort();
|
||||
final Protocol protocol = cmdLineArgs.getProtocol();
|
||||
logger.info("Deleting mapping for protocol " + protocol + " and external port " + port);
|
||||
router.removePortMapping(protocol, remoteHost, port);
|
||||
printPortForwardings(router);
|
||||
}
|
||||
|
||||
private void printStatus(final IRouter router) throws RouterException {
|
||||
router.logRouterInfo();
|
||||
}
|
||||
|
||||
private void addPortForwarding(final IRouter router) throws RouterException {
|
||||
|
||||
final String remoteHost = null;
|
||||
final String internalClient = cmdLineArgs.getInternalIp() != null ? cmdLineArgs.getInternalIp()
|
||||
: router.getLocalHostAddress();
|
||||
final int internalPort = cmdLineArgs.getInternalPort();
|
||||
final int externalPort = cmdLineArgs.getExternalPort();
|
||||
final Protocol protocol = cmdLineArgs.getProtocol();
|
||||
|
||||
final String description = cmdLineArgs.getDescription() != null ? cmdLineArgs.getDescription()
|
||||
: "PortMapper " + protocol + "/" + internalClient + ":" + internalPort;
|
||||
final PortMapping mapping = new PortMapping(protocol, remoteHost, externalPort, internalClient, internalPort,
|
||||
description);
|
||||
logger.info("Adding mapping " + mapping);
|
||||
router.addPortMapping(mapping);
|
||||
printPortForwardings(router);
|
||||
}
|
||||
|
||||
private void printHelp() {
|
||||
cmdLineArgs.printHelp();
|
||||
}
|
||||
|
||||
private boolean isStartGuiRequired() {
|
||||
if (cmdLineArgs.isStartGui()) {
|
||||
return true;
|
||||
}
|
||||
return !(cmdLineArgs.isPrintHelp() || cmdLineArgs.isAddPortMapping() || cmdLineArgs.isPrintInfo()
|
||||
|| cmdLineArgs.isListPortMappings() || cmdLineArgs.isDeletePortMapping());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private AbstractRouterFactory createRouterFactory() throws RouterException {
|
||||
Class<AbstractRouterFactory> routerFactoryClass;
|
||||
logger.info("Creating router factory for class {}", routerFactoryClassName);
|
||||
try {
|
||||
routerFactoryClass = (Class<AbstractRouterFactory>) Class.forName(routerFactoryClassName);
|
||||
} catch (final ClassNotFoundException e) {
|
||||
throw new RouterException("Did not find router factory class for name " + routerFactoryClassName, e);
|
||||
}
|
||||
|
||||
logger.debug("Creating a new instance of the router factory class {}", routerFactoryClass);
|
||||
try {
|
||||
final Constructor<AbstractRouterFactory> constructor = routerFactoryClass
|
||||
.getConstructor(PortMapperApp.class);
|
||||
return constructor.newInstance(new PortMapperApp());
|
||||
} catch (final Exception e) {
|
||||
throw new RouterException("Error creating a router factory using class " + routerFactoryClass.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private IRouter connect() throws RouterException {
|
||||
AbstractRouterFactory routerFactory;
|
||||
try {
|
||||
routerFactory = createRouterFactory();
|
||||
} catch (final RouterException e) {
|
||||
logger.error("Could not create router factory", e);
|
||||
return null;
|
||||
}
|
||||
logger.info("Searching for routers...");
|
||||
|
||||
final List<IRouter> foundRouters = routerFactory.findRouters();
|
||||
|
||||
return selectRouter(foundRouters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param foundRouters
|
||||
* @return
|
||||
*/
|
||||
private IRouter selectRouter(final List<IRouter> foundRouters) {
|
||||
// One router found: use it.
|
||||
if (foundRouters.size() == 1) {
|
||||
final IRouter router = foundRouters.iterator().next();
|
||||
logger.info("Connected to router " + router.getName());
|
||||
return router;
|
||||
} else if (foundRouters.size() == 0) {
|
||||
logger.error("Found no router");
|
||||
return null;
|
||||
} else if (foundRouters.size() > 1 && routerIndex == null) {
|
||||
// let user choose which router to use.
|
||||
logger.error("Found more than one router. Use option -i <index>");
|
||||
|
||||
int index = 0;
|
||||
for (final IRouter iRouter : foundRouters) {
|
||||
logger.error("- index " + index + ": " + iRouter.getName());
|
||||
index++;
|
||||
}
|
||||
return null;
|
||||
} else if (routerIndex >= 0 && routerIndex < foundRouters.size()) {
|
||||
final IRouter router = foundRouters.get(routerIndex);
|
||||
logger.info("Found more than one router, using " + router.getName());
|
||||
return router;
|
||||
} else {
|
||||
logger.error("Index must be between 0 and " + (foundRouters.size() - 1));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.bridge.SLF4JBridgeHandler;
|
||||
|
||||
public class PortMapperStarter {
|
||||
|
||||
private final static Logger LOG = LoggerFactory.getLogger(PortMapperStarter.class);
|
||||
|
||||
public static void main(final String[] args) {
|
||||
redirectJavaUtilLoggingToLogback();
|
||||
final PortMapperCli cli = new PortMapperCli();
|
||||
try {
|
||||
cli.start(args);
|
||||
} catch (final Exception e) {
|
||||
LOG.error("PortMapper failed with exception " + e.getMessage(), e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void redirectJavaUtilLoggingToLogback() {
|
||||
SLF4JBridgeHandler.removeHandlersForRootLogger();
|
||||
SLF4JBridgeHandler.install();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.chris.portmapper.model.PortMappingPreset;
|
||||
import org.chris.portmapper.router.cling.ClingRouterFactory;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
public class Settings implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -1349121864190290050L;
|
||||
|
||||
public final static String PROPERTY_PORT_MAPPING_PRESETS = "presets";
|
||||
|
||||
private List<PortMappingPreset> presets;
|
||||
private boolean useEntityEncoding;
|
||||
private String logLevel;
|
||||
private String routerFactoryClassName;
|
||||
|
||||
private transient PropertyChangeSupport propertyChangeSupport;
|
||||
|
||||
public Settings() {
|
||||
useEntityEncoding = true;
|
||||
logLevel = Level.INFO.toString();
|
||||
presets = new ArrayList<>();
|
||||
routerFactoryClassName = ClingRouterFactory.class.getName();
|
||||
propertyChangeSupport = new PropertyChangeSupport(this);
|
||||
}
|
||||
|
||||
public void addPropertyChangeListener(final String property, final PropertyChangeListener listener) {
|
||||
this.propertyChangeSupport.addPropertyChangeListener(property, listener);
|
||||
}
|
||||
|
||||
public List<PortMappingPreset> getPresets() {
|
||||
return presets;
|
||||
}
|
||||
|
||||
public void setPresets(final List<PortMappingPreset> presets) {
|
||||
this.presets = presets;
|
||||
}
|
||||
|
||||
public void addPreset(final PortMappingPreset newPreset) {
|
||||
final List<PortMappingPreset> oldPresets = new ArrayList<>(this.presets);
|
||||
this.presets.add(newPreset);
|
||||
this.propertyChangeSupport.firePropertyChange(PROPERTY_PORT_MAPPING_PRESETS, oldPresets,
|
||||
new ArrayList<>(this.presets));
|
||||
}
|
||||
|
||||
public void removePresets(final PortMappingPreset selectedPreset) {
|
||||
final List<PortMappingPreset> oldPresets = new ArrayList<>(this.presets);
|
||||
this.presets.remove(selectedPreset);
|
||||
this.propertyChangeSupport.firePropertyChange(PROPERTY_PORT_MAPPING_PRESETS, oldPresets,
|
||||
new ArrayList<>(this.presets));
|
||||
}
|
||||
|
||||
public void savePreset(final PortMappingPreset portMappingPreset) {
|
||||
this.propertyChangeSupport.firePropertyChange(PROPERTY_PORT_MAPPING_PRESETS, null,
|
||||
new ArrayList<>(this.presets));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[Settings: presets=" + presets + ", useEntityEncoding=" + useEntityEncoding + ", logLevel=" + logLevel
|
||||
+ ", routerFactoryClassName=" + routerFactoryClassName + "]";
|
||||
}
|
||||
|
||||
public boolean isUseEntityEncoding() {
|
||||
return useEntityEncoding;
|
||||
}
|
||||
|
||||
public void setUseEntityEncoding(final boolean useEntityEncoding) {
|
||||
this.useEntityEncoding = useEntityEncoding;
|
||||
}
|
||||
|
||||
public String getLogLevel() {
|
||||
return this.logLevel;
|
||||
}
|
||||
|
||||
public void setLogLevel(final String logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
public String getRouterFactoryClassName() {
|
||||
return routerFactoryClassName;
|
||||
}
|
||||
|
||||
public void setRouterFactoryClassName(final String routerFactoryClassName) {
|
||||
this.routerFactoryClassName = routerFactoryClassName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.logging;
|
||||
|
||||
import javax.swing.JTextArea;
|
||||
|
||||
/**
|
||||
* The {@link LogMessageWriter} copies every written string to a {@link LogMessageListener}. All written strings are
|
||||
* buffered, so no string is missed. A {@link LogMessageListener} can be registered using method
|
||||
* {@link #registerListener(JTextArea)}.
|
||||
*/
|
||||
public interface LogMessageListener {
|
||||
|
||||
/**
|
||||
* Process the given log message. This could mean e.g. to display the message to the user.
|
||||
*
|
||||
* @param message
|
||||
* the message to process.
|
||||
*/
|
||||
public void addLogMessage(String message);
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.logging;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JTextArea;
|
||||
|
||||
/**
|
||||
* This class implements an output stream that appends to a list and allows listeners to register for written lines.
|
||||
*/
|
||||
public class LogMessageOutputStream extends OutputStream {
|
||||
|
||||
/**
|
||||
* The listener to which the strings will be forwarded.
|
||||
*/
|
||||
private LogMessageListener logListener;
|
||||
|
||||
/**
|
||||
* The buffer to which the written strings are added until a listener is registered.
|
||||
*/
|
||||
private List<String> unprocessedMessagesBuffer;
|
||||
|
||||
/**
|
||||
* Creates a new {@link LogMessageOutputStream}. At creation time, no listener is registered, so that all added text
|
||||
* is stored in a buffer.
|
||||
*/
|
||||
public LogMessageOutputStream() {
|
||||
unprocessedMessagesBuffer = new LinkedList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final byte b[], final int off, final int len) throws IOException {
|
||||
final String line = new String(b, off, len);
|
||||
addMessage(line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final int b) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the given message to the registered {@link LogMessageListener}. If no listener is registered, the string
|
||||
* is written to a buffer. When a listener is registered, the buffered text will be appended to the listener.
|
||||
*
|
||||
* @param message
|
||||
* the message to append.
|
||||
*/
|
||||
public void addMessage(final String message) {
|
||||
if (this.logListener != null) {
|
||||
this.logListener.addLogMessage(message);
|
||||
} else {
|
||||
unprocessedMessagesBuffer.add(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a {@link JTextArea}, so that all strings written to this writer are appended to the given text area.
|
||||
* After registration, all buffered strings are appended to the text area, so that no string is missed.
|
||||
*
|
||||
* @param textArea
|
||||
* the text area to wich to append the strings.
|
||||
*/
|
||||
public void registerListener(final LogMessageListener textArea) {
|
||||
this.logListener = textArea;
|
||||
|
||||
// append the buffered text to the text area.
|
||||
for (final String line : unprocessedMessagesBuffer) {
|
||||
this.logListener.addLogMessage(line);
|
||||
}
|
||||
// we do not need the buffer any more, all text will be appended
|
||||
// to the text area.
|
||||
this.unprocessedMessagesBuffer = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.logging;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JTextArea;
|
||||
|
||||
/**
|
||||
* The {@link LogMessageWriter} copies every written string to a {@link LogMessageListener}. All written strings are
|
||||
* buffered, so no string is missed. A {@link LogMessageListener} can be registered using method
|
||||
* {@link #registerListener(JTextArea)}.
|
||||
*/
|
||||
public class LogMessageWriter extends Writer {
|
||||
|
||||
/**
|
||||
* The listener to which the strings will be forwarded.
|
||||
*/
|
||||
private LogMessageListener logListener;
|
||||
|
||||
/**
|
||||
* The buffer to which the written strings are added until a listener is registered.
|
||||
*/
|
||||
private List<String> unprocessedMessagesBuffer;
|
||||
|
||||
/**
|
||||
* Creates a new {@link LogMessageWriter}. At creation time, no listener is registered, so that all added text is
|
||||
* stored in a buffer.
|
||||
*/
|
||||
public LogMessageWriter() {
|
||||
unprocessedMessagesBuffer = new LinkedList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final char[] cbuf, final int off, final int len) {
|
||||
final String line = new String(cbuf, off, len);
|
||||
addMessage(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the given message to the registered {@link LogMessageListener}. If no listener is registered, the string
|
||||
* is written to a buffer. When a listener is registered, the buffered text will be appended to the listener.
|
||||
*
|
||||
* @param message
|
||||
* the message to append.
|
||||
*/
|
||||
public void addMessage(final String message) {
|
||||
if (this.logListener != null) {
|
||||
this.logListener.addLogMessage(message);
|
||||
} else {
|
||||
unprocessedMessagesBuffer.add(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a {@link JTextArea}, so that all strings written to this writer are appended to the given text area.
|
||||
* After registration, all buffered strings are appended to the text area, so that no string is missed.
|
||||
*
|
||||
* @param textArea
|
||||
* the text area to wich to append the strings.
|
||||
*/
|
||||
public void registerListener(final LogMessageListener textArea) {
|
||||
this.logListener = textArea;
|
||||
|
||||
// append the buffered text to the text area.
|
||||
for (final String line : unprocessedMessagesBuffer) {
|
||||
this.logListener.addLogMessage(line);
|
||||
}
|
||||
// we do not need the buffer any more, all text will be appended
|
||||
// to the text area.
|
||||
this.unprocessedMessagesBuffer = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.logging;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.OutputStreamAppender;
|
||||
import ch.qos.logback.core.encoder.Encoder;
|
||||
|
||||
public class LogbackConfiguration {
|
||||
|
||||
private static final String PATTERN_LAYOUT = "%-5level %msg%n";
|
||||
private static final String OUTPUT_STREAM_APPENDER_NAME = "OUTPUT_STREAM";
|
||||
private static final String LOGGER_NAME = "ROOT";
|
||||
|
||||
private final LoggerContext loggerContext;
|
||||
|
||||
public LogbackConfiguration() {
|
||||
loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
}
|
||||
|
||||
public void registerOutputStream(final OutputStream logMessageOutputStream) {
|
||||
final Encoder<ILoggingEvent> encoder = createPatternLayoutEncoder(PATTERN_LAYOUT);
|
||||
final OutputStreamAppender<ILoggingEvent> appender = createAppender(logMessageOutputStream, encoder);
|
||||
configureLogger(appender);
|
||||
}
|
||||
|
||||
private void configureLogger(final OutputStreamAppender<ILoggingEvent> appender) {
|
||||
final Logger logbackLogger = getLogger();
|
||||
logbackLogger.addAppender(appender);
|
||||
logbackLogger.setAdditive(false);
|
||||
}
|
||||
|
||||
private Logger getLogger() {
|
||||
return (Logger) LoggerFactory.getLogger(LOGGER_NAME);
|
||||
}
|
||||
|
||||
private OutputStreamAppender<ILoggingEvent> createAppender(final OutputStream logMessageOutputStream,
|
||||
final Encoder<ILoggingEvent> encoder) {
|
||||
final OutputStreamAppender<ILoggingEvent> appender = new OutputStreamAppender<ILoggingEvent>();
|
||||
appender.setContext(loggerContext);
|
||||
appender.setEncoder(encoder);
|
||||
appender.setOutputStream(logMessageOutputStream);
|
||||
appender.setName(OUTPUT_STREAM_APPENDER_NAME);
|
||||
appender.start();
|
||||
return appender;
|
||||
}
|
||||
|
||||
private PatternLayoutEncoder createPatternLayoutEncoder(final String pattern) {
|
||||
final PatternLayoutEncoder encoder = new PatternLayoutEncoder();
|
||||
encoder.setContext(loggerContext);
|
||||
encoder.setPattern(pattern);
|
||||
encoder.start();
|
||||
return encoder;
|
||||
}
|
||||
|
||||
public void setLogLevel(final String logLevel) {
|
||||
final Level level = Level.toLevel(logLevel);
|
||||
getLogger().setLevel(level);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sbbi.upnp.messages.ActionResponse;
|
||||
|
||||
/**
|
||||
* This immutable class represents a port mapping / forwarding on a router.
|
||||
*/
|
||||
public class PortMapping implements Cloneable {
|
||||
|
||||
public static final String MAPPING_ENTRY_LEASE_DURATION = "NewLeaseDuration";
|
||||
public static final String MAPPING_ENTRY_ENABLED = "NewEnabled";
|
||||
public static final String MAPPING_ENTRY_REMOTE_HOST = "NewRemoteHost";
|
||||
public static final String MAPPING_ENTRY_INTERNAL_CLIENT = "NewInternalClient";
|
||||
public static final String MAPPING_ENTRY_PORT_MAPPING_DESCRIPTION = "NewPortMappingDescription";
|
||||
public static final String MAPPING_ENTRY_PROTOCOL = "NewProtocol";
|
||||
public static final String MAPPING_ENTRY_INTERNAL_PORT = "NewInternalPort";
|
||||
public static final String MAPPING_ENTRY_EXTERNAL_PORT = "NewExternalPort";
|
||||
|
||||
private static final long DEFAULT_LEASE_DURATION = 0;
|
||||
|
||||
private final int externalPort;
|
||||
private final Protocol protocol;
|
||||
private final int internalPort;
|
||||
private final String description;
|
||||
private final String internalClient;
|
||||
private final String remoteHost;
|
||||
private final boolean enabled;
|
||||
private final long leaseDuration;
|
||||
|
||||
public PortMapping(final Protocol protocol, final String remoteHost, final int externalPort,
|
||||
final String internalClient, final int internalPort, final String description) {
|
||||
this(protocol, remoteHost, externalPort, internalClient, internalPort, description, true,
|
||||
DEFAULT_LEASE_DURATION);
|
||||
}
|
||||
|
||||
public PortMapping(final Protocol protocol, final String remoteHost, final int externalPort,
|
||||
final String internalClient, final int internalPort, final String description, final boolean enabled,
|
||||
final long leaseDuration) {
|
||||
this.protocol = protocol;
|
||||
this.remoteHost = remoteHost;
|
||||
this.externalPort = externalPort;
|
||||
this.internalClient = internalClient;
|
||||
this.internalPort = internalPort;
|
||||
this.description = description;
|
||||
this.enabled = enabled;
|
||||
this.leaseDuration = leaseDuration;
|
||||
}
|
||||
|
||||
private PortMapping(final ActionResponse response) {
|
||||
final Map<String, String> values = new HashMap<>();
|
||||
|
||||
for (final Object argObj : response.getOutActionArgumentNames()) {
|
||||
final String argName = (String) argObj;
|
||||
values.put(argName, response.getOutActionArgumentValue(argName));
|
||||
}
|
||||
|
||||
externalPort = Integer.parseInt(values.get(MAPPING_ENTRY_EXTERNAL_PORT));
|
||||
internalPort = Integer.parseInt(values.get(MAPPING_ENTRY_INTERNAL_PORT));
|
||||
final String protocolString = values.get(MAPPING_ENTRY_PROTOCOL);
|
||||
protocol = (protocolString.equalsIgnoreCase("TCP") ? Protocol.TCP : Protocol.UDP);
|
||||
description = values.get(MAPPING_ENTRY_PORT_MAPPING_DESCRIPTION);
|
||||
internalClient = values.get(MAPPING_ENTRY_INTERNAL_CLIENT);
|
||||
remoteHost = values.get(MAPPING_ENTRY_REMOTE_HOST);
|
||||
final String enabledString = values.get(MAPPING_ENTRY_ENABLED);
|
||||
enabled = enabledString != null && enabledString.equals("1");
|
||||
leaseDuration = Long.parseLong(values.get(MAPPING_ENTRY_LEASE_DURATION));
|
||||
}
|
||||
|
||||
public static PortMapping create(final ActionResponse response) {
|
||||
final PortMapping mapping = new PortMapping(response);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the leaseDuration
|
||||
*/
|
||||
public long getLeaseDuration() {
|
||||
return leaseDuration;
|
||||
}
|
||||
|
||||
public int getExternalPort() {
|
||||
return externalPort;
|
||||
}
|
||||
|
||||
public Protocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public int getInternalPort() {
|
||||
return internalPort;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getInternalClient() {
|
||||
return internalClient;
|
||||
}
|
||||
|
||||
public String getRemoteHost() {
|
||||
return remoteHost;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public String getCompleteDescription() {
|
||||
final StringBuilder b = new StringBuilder();
|
||||
b.append(protocol);
|
||||
b.append(" ");
|
||||
if (remoteHost != null) {
|
||||
b.append(remoteHost);
|
||||
}
|
||||
b.append(":");
|
||||
b.append(externalPort);
|
||||
b.append(" -> ");
|
||||
b.append(internalClient);
|
||||
b.append(":");
|
||||
b.append(internalPort);
|
||||
b.append(" ");
|
||||
b.append(enabled ? "enabled" : "not enabled");
|
||||
b.append(" ");
|
||||
b.append(description);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
return new PortMapping(protocol, remoteHost, externalPort, internalClient, internalPort, description, enabled,
|
||||
leaseDuration);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.chris.portmapper.Settings;
|
||||
|
||||
/**
|
||||
* This class stores a port mapping preset containing a description, internal and remote host and a {@link List} of
|
||||
* {@link SinglePortMapping}s.
|
||||
*/
|
||||
public class PortMappingPreset implements Cloneable, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3749136884938395765L;
|
||||
|
||||
/**
|
||||
* The description of this preset.
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* The ip address of the internal client or <code>null</code> for localhost.
|
||||
*/
|
||||
private String internalClient;
|
||||
|
||||
/**
|
||||
* The host name of the remote host.
|
||||
*/
|
||||
private String remoteHost;
|
||||
|
||||
/**
|
||||
* The port mappings in this preset.
|
||||
*/
|
||||
private List<SinglePortMapping> ports;
|
||||
|
||||
/**
|
||||
* <code>true</code> if this preset has not been saved.
|
||||
*/
|
||||
private boolean isNew;
|
||||
|
||||
/**
|
||||
* Creates a new preset with the given default values.
|
||||
*/
|
||||
public PortMappingPreset(final String remoteHost, final String internalClient, final String description) {
|
||||
this.remoteHost = remoteHost;
|
||||
this.internalClient = internalClient;
|
||||
this.description = description;
|
||||
this.ports = new LinkedList<>();
|
||||
|
||||
this.isNew = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty preset.
|
||||
*/
|
||||
public PortMappingPreset() {
|
||||
this.ports = new LinkedList<>();
|
||||
this.isNew = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public List<PortMapping> getPortMappings(final String localhost) {
|
||||
if (this.useLocalhostAsInternalClient() && (localhost == null || localhost.length() == 0)) {
|
||||
throw new IllegalArgumentException("Got invalid localhost and internal host is not given.");
|
||||
}
|
||||
|
||||
final List<PortMapping> allPortMappings = new ArrayList<>(this.ports.size());
|
||||
for (final SinglePortMapping port : this.ports) {
|
||||
final String internalClientName = this.useLocalhostAsInternalClient() ? localhost : this.internalClient;
|
||||
|
||||
final PortMapping newMapping = new PortMapping(port.getProtocol(), remoteHost, port.getExternalPort(),
|
||||
internalClientName, port.getInternalPort(), description);
|
||||
|
||||
allPortMappings.add(newMapping);
|
||||
}
|
||||
|
||||
return allPortMappings;
|
||||
}
|
||||
|
||||
public String getCompleteDescription() {
|
||||
final StringBuffer b = new StringBuffer();
|
||||
|
||||
b.append(" ");
|
||||
b.append(remoteHost);
|
||||
b.append(":");
|
||||
|
||||
b.append(" -> ");
|
||||
b.append(internalClient);
|
||||
b.append(":");
|
||||
|
||||
b.append(" ");
|
||||
|
||||
b.append(" ");
|
||||
b.append(description);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public List<SinglePortMapping> getPorts() {
|
||||
return ports;
|
||||
}
|
||||
|
||||
public void setPorts(final List<SinglePortMapping> ports) {
|
||||
this.ports = ports;
|
||||
}
|
||||
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setRemoteHost(final String remoteHost) {
|
||||
this.remoteHost = remoteHost;
|
||||
}
|
||||
|
||||
public String getRemoteHost() {
|
||||
return remoteHost;
|
||||
}
|
||||
|
||||
public void setInternalClient(final String internalClient) {
|
||||
this.internalClient = internalClient;
|
||||
}
|
||||
|
||||
public String getInternalClient() {
|
||||
return internalClient;
|
||||
}
|
||||
|
||||
public boolean isNew() {
|
||||
return isNew;
|
||||
}
|
||||
|
||||
public void setNew(final boolean isNew) {
|
||||
this.isNew = isNew;
|
||||
}
|
||||
|
||||
public boolean useLocalhostAsInternalClient() {
|
||||
return this.getInternalClient() == null || this.getInternalClient().length() == 0;
|
||||
}
|
||||
|
||||
public void save(final Settings settings) {
|
||||
if (this.isNew) {
|
||||
settings.addPreset(this);
|
||||
} else {
|
||||
settings.savePreset(this);
|
||||
}
|
||||
this.isNew = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.chris.portmapper.model;
|
||||
|
||||
/**
|
||||
* This {@link Enum} represents the protocol of a {@link SinglePortMapping}, possible values are {@link #TCP} and
|
||||
* {@link #UDP}.
|
||||
*/
|
||||
public enum Protocol {
|
||||
|
||||
TCP("TCP"), UDP("UDP");
|
||||
|
||||
private final String name;
|
||||
|
||||
private Protocol(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static Protocol getProtocol(final String name) {
|
||||
if (name != null && name.equalsIgnoreCase("TCP")) {
|
||||
return TCP;
|
||||
}
|
||||
if (name != null && name.equalsIgnoreCase("UDP")) {
|
||||
return UDP;
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid protocol name '" + name + "'");
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.chris.portmapper.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* This class is used by {@link PortMapping} to store the information about a single port mapping, i.e. the protocol
|
||||
* (TCP or UDP) and internal and extern port.
|
||||
*/
|
||||
public class SinglePortMapping implements Cloneable, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7458514232916039775L;
|
||||
private int externalPort;
|
||||
private int internalPort;
|
||||
private Protocol protocol;
|
||||
|
||||
public SinglePortMapping() {
|
||||
this(Protocol.TCP, 1, 1);
|
||||
}
|
||||
|
||||
public SinglePortMapping(final Protocol protocol, final int internalPort, final int externalPort) {
|
||||
this.protocol = protocol;
|
||||
this.internalPort = internalPort;
|
||||
this.externalPort = externalPort;
|
||||
}
|
||||
|
||||
public int getExternalPort() {
|
||||
return externalPort;
|
||||
}
|
||||
|
||||
public void setExternalPort(final int externalPort) {
|
||||
this.externalPort = externalPort;
|
||||
}
|
||||
|
||||
public Protocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(final Protocol protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public int getInternalPort() {
|
||||
return internalPort;
|
||||
}
|
||||
|
||||
public void setInternalPort(final int internalPort) {
|
||||
this.internalPort = internalPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
return new SinglePortMapping(protocol, internalPort, externalPort);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.chris.portmapper.router;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This is the abstract super class for all routers.
|
||||
*/
|
||||
public abstract class AbstractRouter implements IRouter {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final String name;
|
||||
|
||||
public AbstractRouter(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the the ip of the local host.
|
||||
*/
|
||||
@Override
|
||||
public String getLocalHostAddress() throws RouterException {
|
||||
logger.debug("Get IP of localhost");
|
||||
|
||||
final InetAddress localHostIP = getLocalHostAddressFromSocket();
|
||||
|
||||
// We do not want an address like 127.0.0.1
|
||||
if (localHostIP.getHostAddress().startsWith("127.")) {
|
||||
throw new RouterException("Only found an address that begins with '127.' when retrieving IP of localhost");
|
||||
}
|
||||
|
||||
return localHostIP.getHostAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ip of the local host by connecting to the router and fetching the ip from the socket. This only works
|
||||
* when we are connected to the router and know its internal upnp port.
|
||||
*
|
||||
* @return the ip of the local host.
|
||||
* @throws RouterException
|
||||
*/
|
||||
private InetAddress getLocalHostAddressFromSocket() throws RouterException {
|
||||
InetAddress localHostIP = null;
|
||||
try {
|
||||
|
||||
// In order to use the socket method to get the address, we have to
|
||||
// be connected to the router.
|
||||
final int routerInternalPort = getInternalPort();
|
||||
logger.debug("Got internal router port {}", routerInternalPort);
|
||||
|
||||
// Check, if we got a correct port number
|
||||
if (routerInternalPort > 0) {
|
||||
logger.debug("Creating socket to router: {}:{}...", getInternalHostName(), routerInternalPort);
|
||||
try (Socket socket = new Socket(getInternalHostName(), routerInternalPort)) {
|
||||
localHostIP = socket.getLocalAddress();
|
||||
} catch (final UnknownHostException e) {
|
||||
throw new RouterException(
|
||||
"Could not create socked to " + getInternalHostName() + ":" + routerInternalPort, e);
|
||||
}
|
||||
|
||||
logger.debug("Got address {} from socket.", localHostIP);
|
||||
} else {
|
||||
logger.debug("Got invalid internal router port number {}", routerInternalPort);
|
||||
}
|
||||
|
||||
// We are not connected to the router or got an invalid port number,
|
||||
// so we have to use the traditional method.
|
||||
if (localHostIP == null) {
|
||||
|
||||
logger.debug(
|
||||
"Not connected to router or got invalid port number, can not use socket to determine the address of the localhost. "
|
||||
+ "If no address is found, please connect to the router.");
|
||||
|
||||
localHostIP = InetAddress.getLocalHost();
|
||||
|
||||
logger.debug("Got address {} via InetAddress.getLocalHost().", localHostIP);
|
||||
}
|
||||
|
||||
} catch (final IOException e) {
|
||||
throw new RouterException("Could not get IP of localhost.", e);
|
||||
}
|
||||
return localHostIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName() + " (" + getInternalHostName() + ")";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.chris.portmapper.PortMapperApp;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The base class for all router factories.
|
||||
*/
|
||||
public abstract class AbstractRouterFactory {
|
||||
|
||||
private static final String LOCATION_URL_SYSTEM_PROPERTY = "portmapper.locationUrl";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
protected final PortMapperApp app;
|
||||
|
||||
private final String name;
|
||||
|
||||
protected AbstractRouterFactory(final PortMapperApp app, final String name) {
|
||||
this.app = app;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the router factory that can be displayed to the user.
|
||||
*
|
||||
* @return the name of the router factory that can be displayed to the user.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<IRouter> findRouters() throws RouterException {
|
||||
final String locationUrl = System.getProperty(LOCATION_URL_SYSTEM_PROPERTY);
|
||||
if (locationUrl == null) {
|
||||
logger.debug("System property '{}' not defined: discover routers automatically.",
|
||||
LOCATION_URL_SYSTEM_PROPERTY);
|
||||
return findRoutersInternal();
|
||||
}
|
||||
logger.info("Trying to connect using location url {}", locationUrl);
|
||||
return asList(connect(locationUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for routers on the network.
|
||||
*
|
||||
* @return the found router or an empty {@link Collection} if no router was found.
|
||||
* @throws RouterException
|
||||
* if something goes wrong during discovery.
|
||||
*/
|
||||
protected abstract List<IRouter> findRoutersInternal() throws RouterException;
|
||||
|
||||
/**
|
||||
* Directly connect to a router using a location url like <code>http://192.168.179.1:49000/igddesc.xml</code>.
|
||||
*
|
||||
* @param locationUrl
|
||||
* a location url
|
||||
* @return a router if the connection was successful.
|
||||
* @throws RouterException
|
||||
* if something goes wrong during connection.
|
||||
*/
|
||||
protected abstract IRouter connect(final String locationUrl) throws RouterException;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.chris.portmapper.router;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.chris.portmapper.model.Protocol;
|
||||
|
||||
public interface IRouter {
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
/**
|
||||
* Get the IP address of the local host.
|
||||
*
|
||||
* @return IP address of the local host or <code>null</code>, if the address could not be determined.
|
||||
* @throws RouterException
|
||||
*/
|
||||
public String getLocalHostAddress() throws RouterException;
|
||||
|
||||
/**
|
||||
* Get the external IP of the router.
|
||||
*
|
||||
* @return the external IP of the router.
|
||||
*/
|
||||
public abstract String getExternalIPAddress() throws RouterException;
|
||||
|
||||
/**
|
||||
* Get the internal host name or IP of the router.
|
||||
*
|
||||
* @return the internal host name or IP of the router.
|
||||
* @throws RouterException
|
||||
*/
|
||||
public abstract String getInternalHostName();
|
||||
|
||||
/**
|
||||
* Get the internal port of the router.
|
||||
*
|
||||
* @return the internal port of the router.
|
||||
* @throws RouterException
|
||||
*/
|
||||
public abstract int getInternalPort() throws RouterException;
|
||||
|
||||
/**
|
||||
* Get all port mappings from the router.
|
||||
*
|
||||
* @return all port mappings from the router.
|
||||
* @throws RouterException
|
||||
* if something went wrong when getting the port mappings.
|
||||
*/
|
||||
public abstract Collection<PortMapping> getPortMappings() throws RouterException;
|
||||
|
||||
/**
|
||||
* Write information about the router to the log.
|
||||
*
|
||||
* @throws RouterException
|
||||
*/
|
||||
public abstract void logRouterInfo() throws RouterException;
|
||||
|
||||
/**
|
||||
* Add the given port mappings to the router.
|
||||
*
|
||||
* @param mappings
|
||||
* the port mappings to add.
|
||||
* @throws RouterException
|
||||
*/
|
||||
public abstract void addPortMappings(Collection<PortMapping> mappings) throws RouterException;
|
||||
|
||||
/**
|
||||
* Add the given port mapping to the router.
|
||||
*
|
||||
* @param mapping
|
||||
* the port mapping to add.
|
||||
* @throws RouterException
|
||||
*/
|
||||
public abstract void addPortMapping(PortMapping mapping) throws RouterException;
|
||||
|
||||
/**
|
||||
* Remove the given port mapping from the router.
|
||||
*
|
||||
* @param mapping
|
||||
* the port mapping to remove.
|
||||
* @throws RouterException
|
||||
*/
|
||||
public abstract void removeMapping(PortMapping mapping) throws RouterException;
|
||||
|
||||
/**
|
||||
* Remove the port mapping with the given data from the router.
|
||||
*
|
||||
* @param protocol
|
||||
* @param remoteHost
|
||||
* @param externalPort
|
||||
* @throws RouterException
|
||||
*/
|
||||
public abstract void removePortMapping(Protocol protocol, String remoteHost, int externalPort)
|
||||
throws RouterException;
|
||||
|
||||
/**
|
||||
* Disconnect from the router.
|
||||
*/
|
||||
public abstract void disconnect();
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router;
|
||||
|
||||
public class RouterException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public RouterException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public RouterException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.cling;
|
||||
|
||||
import org.fourthline.cling.model.message.control.IncomingActionResponseMessage;
|
||||
|
||||
public class ClingOperationFailedException extends ClingRouterException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final IncomingActionResponseMessage response;
|
||||
|
||||
public ClingOperationFailedException(final String message, final IncomingActionResponseMessage response) {
|
||||
super(message);
|
||||
assert response.getOperation().isFailed();
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public IncomingActionResponseMessage getResponse() {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.cling;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
import org.chris.portmapper.router.cling.action.ActionService;
|
||||
import org.chris.portmapper.router.cling.action.GetPortMappingEntryAction;
|
||||
import org.fourthline.cling.model.message.control.IncomingActionResponseMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sbbi.upnp.impls.InternetGatewayDevice;
|
||||
|
||||
/**
|
||||
* This class fetches all {@link PortMapping} from an {@link InternetGatewayDevice}.
|
||||
*/
|
||||
class ClingPortMappingExtractor {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final Collection<PortMapping> mappings;
|
||||
private boolean moreEntries;
|
||||
private int currentMappingNumber;
|
||||
|
||||
/**
|
||||
* The maximum number of port mappings that we will try to retrieve from the router.
|
||||
*/
|
||||
private final int maxNumPortMappings;
|
||||
private final ActionService actionService;
|
||||
|
||||
ClingPortMappingExtractor(final ActionService actionService, final int maxNumPortMappings) {
|
||||
this.actionService = actionService;
|
||||
this.maxNumPortMappings = maxNumPortMappings;
|
||||
this.mappings = new LinkedList<>();
|
||||
this.moreEntries = true;
|
||||
this.currentMappingNumber = 0;
|
||||
}
|
||||
|
||||
public Collection<PortMapping> getPortMappings() throws RouterException {
|
||||
|
||||
/*
|
||||
* This is a little trick to get all port mappings. There is a method that gets the number of available port
|
||||
* mappings (getNatMappingsCount()), but it seems, that this method just tries to get all port mappings and
|
||||
* checks, if an error is returned.
|
||||
*
|
||||
* In order to speed this up, we will do the same here, but stop, when the first exception is thrown.
|
||||
*/
|
||||
|
||||
while (morePortMappingsAvailable()) {
|
||||
logger.debug("Getting port mapping with entry number " + currentMappingNumber + "...");
|
||||
|
||||
try {
|
||||
final PortMapping portMapping = actionService
|
||||
.run(new GetPortMappingEntryAction(actionService.getService(), currentMappingNumber));
|
||||
mappings.add(portMapping);
|
||||
} catch (final ClingOperationFailedException e) {
|
||||
handleFailureResponse(e.getResponse());
|
||||
}
|
||||
currentMappingNumber++;
|
||||
}
|
||||
|
||||
checkMaxNumPortMappingsReached();
|
||||
|
||||
return mappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check, if the max number of entries is reached and print a warning message.
|
||||
*/
|
||||
private void checkMaxNumPortMappingsReached() {
|
||||
if (currentMappingNumber == maxNumPortMappings) {
|
||||
logger.warn(
|
||||
"Reached max number of port mappings to get ({}). Perhaps not all port mappings where retrieved.",
|
||||
maxNumPortMappings);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean morePortMappingsAvailable() {
|
||||
return moreEntries && currentMappingNumber < maxNumPortMappings;
|
||||
}
|
||||
|
||||
private void handleFailureResponse(final IncomingActionResponseMessage incomingActionResponseMessage) {
|
||||
if (isNoMoreMappingsException(incomingActionResponseMessage)) {
|
||||
moreEntries = false;
|
||||
logger.debug("Got no port mapping for entry number {} (status: {}). Stop getting more entries.",
|
||||
currentMappingNumber, incomingActionResponseMessage.getOperation().getStatusMessage());
|
||||
} else {
|
||||
moreEntries = false;
|
||||
logger.info(
|
||||
"Got error response when fetching port mapping for entry number {}: '{}'. Stop getting more entries.",
|
||||
currentMappingNumber, incomingActionResponseMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks, if the error code of the given exception means, that no more mappings are available.
|
||||
* <p>
|
||||
* The following error codes are recognized:
|
||||
* <ul>
|
||||
* <li>SpecifiedArrayIndexInvalid: 713</li>
|
||||
* <li>NoSuchEntryInArray: 714</li>
|
||||
* <li>Invalid Args: 402 (e.g. for DD-WRT, TP-LINK TL-R460 firmware 4.7.6 Build 100714 Rel.63134n)</li>
|
||||
* <li>Other errors, e.g. "The reference to entity "T" must end with the ';' delimiter" or
|
||||
* "Content is not allowed in prolog": 899 (e.g. ActionTec MI424-WR, Thomson TWG850-4U)</li>
|
||||
* </ul>
|
||||
* See bug reports
|
||||
* <ul>
|
||||
* <li><a href= "https://sourceforge.net/tracker/index.php?func=detail&aid=1939749&group_id=213879&atid=1027466" >
|
||||
* https://sourceforge.net/tracker/index.php?func=detail&aid= 1939749&group_id=213879&atid=1027466</a></li>
|
||||
* <li><a href="http://www.sbbi.net/forum/viewtopic.php?p=394">http://www.sbbi .net/forum/viewtopic.php?p=394</a>
|
||||
* </li>
|
||||
* <li><a href= "http://sourceforge.net/tracker/?func=detail&atid=1027466&aid=3325388&group_id=213879" >http://
|
||||
* sourceforge.net/tracker/?func=detail&atid=1027466&aid=3325388& group_id=213879</a></li>
|
||||
* <a href= "https://sourceforge.net/tracker2/?func=detail&aid=2540478&group_id=213879&atid=1027466" >https://
|
||||
* sourceforge.net/tracker2/?func=detail&aid=2540478&group_id= 213879&atid=1027466</a></li>
|
||||
* </ul>
|
||||
*
|
||||
* @param incomingActionResponseMessage
|
||||
* the exception to check
|
||||
* @return <code>true</code>, if the given exception means, that no more port mappings are available, else
|
||||
* <code>false</code>.
|
||||
*/
|
||||
private boolean isNoMoreMappingsException(final IncomingActionResponseMessage incomingActionResponseMessage) {
|
||||
final int errorCode = incomingActionResponseMessage.getOperation().getStatusCode();
|
||||
switch (errorCode) {
|
||||
case 713:
|
||||
case 714:
|
||||
case 402:
|
||||
case 899:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.cling;
|
||||
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.fourthline.cling.model.meta.Device;
|
||||
import org.fourthline.cling.model.meta.Service;
|
||||
import org.fourthline.cling.model.types.DeviceType;
|
||||
import org.fourthline.cling.model.types.ServiceType;
|
||||
import org.fourthline.cling.model.types.UDADeviceType;
|
||||
import org.fourthline.cling.model.types.UDAServiceType;
|
||||
import org.fourthline.cling.registry.DefaultRegistryListener;
|
||||
import org.fourthline.cling.registry.Registry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ClingRegistryListener extends DefaultRegistryListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
public static final DeviceType IGD_DEVICE_TYPE = new UDADeviceType("InternetGatewayDevice", 1);
|
||||
public static final DeviceType CONNECTION_DEVICE_TYPE = new UDADeviceType("WANConnectionDevice", 1);
|
||||
|
||||
public static final ServiceType IP_SERVICE_TYPE = new UDAServiceType("WANIPConnection", 1);
|
||||
public static final ServiceType PPP_SERVICE_TYPE = new UDAServiceType("WANPPPConnection", 1);
|
||||
|
||||
private final SynchronousQueue<Service<?, ?>> foundServices;
|
||||
|
||||
public ClingRegistryListener() {
|
||||
this.foundServices = new SynchronousQueue<>();
|
||||
}
|
||||
|
||||
public Service<?, ?> waitForServiceFound(final long timeout, final TimeUnit unit) {
|
||||
try {
|
||||
return foundServices.poll(timeout, unit);
|
||||
} catch (final InterruptedException e) {
|
||||
logger.warn("Interrupted when waiting for a service");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deviceAdded(final Registry registry, @SuppressWarnings("rawtypes") final Device device) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Service<?, ?> connectionService = discoverConnectionService(device);
|
||||
if (connectionService == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Found connection service {}", connectionService);
|
||||
foundServices.offer(connectionService);
|
||||
}
|
||||
|
||||
protected Service<?, ?> discoverConnectionService(@SuppressWarnings("rawtypes") final Device<?, Device, ?> device) {
|
||||
if (!device.getType().equals(IGD_DEVICE_TYPE)) {
|
||||
logger.debug("Found service of wrong type {}, expected {}.", device.getType(), IGD_DEVICE_TYPE);
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
final Device[] connectionDevices = device.findDevices(CONNECTION_DEVICE_TYPE);
|
||||
if (connectionDevices.length == 0) {
|
||||
logger.debug("IGD doesn't support '{}': {}", CONNECTION_DEVICE_TYPE, device);
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.debug("Found {} devices", connectionDevices.length);
|
||||
|
||||
return findConnectionService(connectionDevices);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Service<?, ?> findConnectionService(final Device[] connectionDevices) {
|
||||
for (final Device connectionDevice : connectionDevices) {
|
||||
|
||||
final Service ipConnectionService = connectionDevice.findService(IP_SERVICE_TYPE);
|
||||
final Service pppConnectionService = connectionDevice.findService(PPP_SERVICE_TYPE);
|
||||
|
||||
if (ipConnectionService != null) {
|
||||
logger.debug("Device {} supports ip service type: {}", connectionDevice, ipConnectionService);
|
||||
return ipConnectionService;
|
||||
}
|
||||
if (pppConnectionService != null) {
|
||||
logger.debug("Device {} supports ppp service type: {}", connectionDevice, pppConnectionService);
|
||||
return pppConnectionService;
|
||||
}
|
||||
|
||||
logger.debug("IGD {} doesn't support IP or PPP WAN connection service", connectionDevice);
|
||||
}
|
||||
logger.debug("None of the {} devices supports IP or PPP WAN connections", connectionDevices.length);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.cling;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.chris.portmapper.model.Protocol;
|
||||
import org.chris.portmapper.router.AbstractRouter;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
import org.chris.portmapper.router.cling.action.ActionService;
|
||||
import org.chris.portmapper.router.cling.action.AddPortMappingAction;
|
||||
import org.chris.portmapper.router.cling.action.DeletePortMappingAction;
|
||||
import org.chris.portmapper.router.cling.action.GetExternalIpAction;
|
||||
import org.fourthline.cling.controlpoint.ControlPoint;
|
||||
import org.fourthline.cling.model.meta.RemoteService;
|
||||
import org.fourthline.cling.model.meta.Service;
|
||||
import org.fourthline.cling.model.meta.UDAVersion;
|
||||
import org.fourthline.cling.registry.Registry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ClingRouter extends AbstractRouter {
|
||||
|
||||
/**
|
||||
* The maximum number of port mappings that we will try to retrieve from the router.
|
||||
*/
|
||||
private final static int MAX_NUM_PORTMAPPINGS = 500;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final RemoteService service;
|
||||
|
||||
private final Registry registry;
|
||||
|
||||
private final ActionService actionService;
|
||||
|
||||
public ClingRouter(final RemoteService service, final Registry registry, final ControlPoint controlPoint) {
|
||||
super(getName(service));
|
||||
this.service = service;
|
||||
this.registry = registry;
|
||||
actionService = new ActionService(service, controlPoint);
|
||||
}
|
||||
|
||||
private static String getName(final Service<?, ?> service) {
|
||||
return service.getDevice().getDisplayString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExternalIPAddress() throws RouterException {
|
||||
return actionService.run(new GetExternalIpAction(service));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalHostName() {
|
||||
final URI uri = getUri();
|
||||
return uri != null ? uri.getHost() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalPort() throws RouterException {
|
||||
final URI uri = getUri();
|
||||
return uri != null ? uri.getPort() : null;
|
||||
}
|
||||
|
||||
private URI getUri() {
|
||||
if (service.getDevice().getDetails().getPresentationURI() != null) {
|
||||
return service.getDevice().getDetails().getPresentationURI();
|
||||
}
|
||||
if (service.getControlURI() != null) {
|
||||
return service.getControlURI();
|
||||
}
|
||||
if (service.getDescriptorURI() != null) {
|
||||
return service.getDescriptorURI();
|
||||
}
|
||||
if (service.getEventSubscriptionURI() != null) {
|
||||
return service.getEventSubscriptionURI();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PortMapping> getPortMappings() throws RouterException {
|
||||
return new ClingPortMappingExtractor(actionService, MAX_NUM_PORTMAPPINGS).getPortMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logRouterInfo() throws RouterException {
|
||||
logger.info("Service id: " + service.getServiceId());
|
||||
logger.info("Reference: " + service.getReference());
|
||||
logger.info("Display name: " + service.getDevice().getDisplayString());
|
||||
final UDAVersion version = service.getDevice().getVersion();
|
||||
logger.info("Version: " + version.getMajor() + "." + version.getMinor());
|
||||
logger.info("Control uri: {}", service.getControlURI());
|
||||
logger.info("Descriptor uri: {}", service.getDescriptorURI());
|
||||
logger.info("Event subscription uri: {}", service.getEventSubscriptionURI());
|
||||
logger.info("Device base url: {}", service.getDevice().getDetails().getBaseURL());
|
||||
logger.info("Device presentation uri: {}", service.getDevice().getDetails().getPresentationURI());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPortMappings(final Collection<PortMapping> mappings) throws RouterException {
|
||||
for (final PortMapping portMapping : mappings) {
|
||||
addPortMapping(portMapping);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPortMapping(final PortMapping mapping) throws RouterException {
|
||||
actionService.run(new AddPortMappingAction(service, mapping));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMapping(final PortMapping mapping) throws RouterException {
|
||||
actionService.run(new DeletePortMappingAction(service, mapping));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePortMapping(final Protocol protocol, final String remoteHost, final int externalPort)
|
||||
throws RouterException {
|
||||
removeMapping(new PortMapping(protocol, remoteHost, externalPort, null, 0, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
logger.debug("Shutdown registry");
|
||||
registry.shutdown();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.chris.portmapper.router.cling;
|
||||
|
||||
public class ClingRouterException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ClingRouterException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ClingRouterException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.cling;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EventObject;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.chris.portmapper.PortMapperApp;
|
||||
import org.chris.portmapper.router.AbstractRouterFactory;
|
||||
import org.chris.portmapper.router.IRouter;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
import org.fourthline.cling.DefaultUpnpServiceConfiguration;
|
||||
import org.fourthline.cling.UpnpService;
|
||||
import org.fourthline.cling.UpnpServiceConfiguration;
|
||||
import org.fourthline.cling.UpnpServiceImpl;
|
||||
import org.fourthline.cling.model.meta.RemoteService;
|
||||
import org.jdesktop.application.Application.ExitListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ClingRouterFactory extends AbstractRouterFactory {
|
||||
|
||||
private static final long DISCOVERY_TIMEOUT_SECONDS = 5;
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
public ClingRouterFactory(final PortMapperApp app) {
|
||||
super(app, "Cling lib");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<IRouter> findRoutersInternal() throws RouterException {
|
||||
final UpnpServiceConfiguration config = new DefaultUpnpServiceConfiguration();
|
||||
final ClingRegistryListener clingRegistryListener = new ClingRegistryListener();
|
||||
final UpnpService upnpService = new UpnpServiceImpl(config, clingRegistryListener);
|
||||
shutdownServiceOnExit(upnpService);
|
||||
|
||||
log.debug("Start searching using upnp service");
|
||||
upnpService.getControlPoint().search();
|
||||
final RemoteService service = (RemoteService) clingRegistryListener
|
||||
.waitForServiceFound(DISCOVERY_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
|
||||
if (service == null) {
|
||||
log.debug("Did not find a service after {} seconds", DISCOVERY_TIMEOUT_SECONDS);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
log.debug("Found service {}", service);
|
||||
return Arrays
|
||||
.<IRouter> asList(new ClingRouter(service, upnpService.getRegistry(), upnpService.getControlPoint()));
|
||||
}
|
||||
|
||||
private void shutdownServiceOnExit(final UpnpService upnpService) {
|
||||
app.addExitListener(new ExitListener() {
|
||||
@Override
|
||||
public void willExit(final EventObject event) {
|
||||
log.debug("Shutdown upnp service");
|
||||
upnpService.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExit(final EventObject event) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IRouter connect(final String locationUrl) throws RouterException {
|
||||
throw new UnsupportedOperationException("Direct connection is not supported for Cling library.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.cling.action;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.chris.portmapper.router.cling.ClingRouterException;
|
||||
import org.fourthline.cling.model.action.ActionArgumentValue;
|
||||
import org.fourthline.cling.model.action.ActionInvocation;
|
||||
import org.fourthline.cling.model.meta.Action;
|
||||
import org.fourthline.cling.model.meta.ActionArgument;
|
||||
import org.fourthline.cling.model.meta.ActionArgument.Direction;
|
||||
import org.fourthline.cling.model.meta.RemoteDevice;
|
||||
import org.fourthline.cling.model.meta.RemoteService;
|
||||
import org.fourthline.cling.model.meta.Service;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
abstract class AbstractClingAction<T> implements ClingAction<T> {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final Service<RemoteDevice, RemoteService> service;
|
||||
private final String actionName;
|
||||
|
||||
public AbstractClingAction(final Service<RemoteDevice, RemoteService> service, final String actionName) {
|
||||
this.service = service;
|
||||
this.actionName = actionName;
|
||||
}
|
||||
|
||||
public Map<String, Object> getArgumentValues() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ActionInvocation<RemoteService> getActionInvocation() {
|
||||
final Action<RemoteService> action = service.getAction(actionName);
|
||||
if (action == null) {
|
||||
throw new ClingRouterException("No action found for name '" + actionName + "'. Available actions: "
|
||||
+ Arrays.toString(service.getActions()));
|
||||
}
|
||||
@SuppressWarnings("rawtypes")
|
||||
final ActionArgumentValue[] argumentArray = getArguments(action);
|
||||
return new ActionInvocation<RemoteService>(action, argumentArray);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private ActionArgumentValue[] getArguments(final Action<RemoteService> action) {
|
||||
final ActionArgument[] actionArguments = action.getArguments();
|
||||
final Map<String, Object> argumentValues = getArgumentValues();
|
||||
final List<ActionArgumentValue<RemoteService>> actionArgumentValues = new ArrayList<>(actionArguments.length);
|
||||
|
||||
for (final ActionArgument<RemoteService> actionArgument : actionArguments) {
|
||||
if (actionArgument.getDirection() == Direction.IN) {
|
||||
final Object value = argumentValues.get(actionArgument.getName());
|
||||
logger.trace("Action {}: add arg value for {}: {} (expected datatype: {})", action.getName(),
|
||||
actionArgument, value, actionArgument.getDatatype().getDisplayString());
|
||||
actionArgumentValues.add(new ActionArgumentValue<>(actionArgument, value));
|
||||
}
|
||||
}
|
||||
return actionArgumentValues.toArray(new ActionArgumentValue[actionArgumentValues.size()]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.cling.action;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import org.chris.portmapper.router.cling.ClingOperationFailedException;
|
||||
import org.chris.portmapper.router.cling.ClingRouterException;
|
||||
import org.fourthline.cling.controlpoint.ControlPoint;
|
||||
import org.fourthline.cling.model.action.ActionInvocation;
|
||||
import org.fourthline.cling.model.message.control.IncomingActionResponseMessage;
|
||||
import org.fourthline.cling.model.meta.RemoteService;
|
||||
import org.fourthline.cling.protocol.sync.SendingAction;
|
||||
|
||||
public class ActionService {
|
||||
private final RemoteService remoteService;
|
||||
private final ControlPoint controlPoint;
|
||||
|
||||
public ActionService(final RemoteService remoteService, final ControlPoint controlPoint) {
|
||||
this.remoteService = remoteService;
|
||||
this.controlPoint = controlPoint;
|
||||
}
|
||||
|
||||
public <T> T run(final ClingAction<T> action) {
|
||||
// Figure out the remote URL where we'd like to send the action request to
|
||||
final URL controLURL = remoteService.getDevice().normalizeURI(remoteService.getControlURI());
|
||||
|
||||
final ActionInvocation<RemoteService> actionInvocation = action.getActionInvocation();
|
||||
final SendingAction prot = controlPoint.getProtocolFactory().createSendingAction(actionInvocation, controLURL);
|
||||
prot.run();
|
||||
|
||||
final IncomingActionResponseMessage response = prot.getOutputMessage();
|
||||
if (response == null) {
|
||||
throw new ClingRouterException("Got null response for action " + actionInvocation);
|
||||
} else if (response.getOperation().isFailed()) {
|
||||
throw new ClingOperationFailedException("Invocation " + actionInvocation + " failed with operation '"
|
||||
+ response.getOperation() + "', body '" + response.getBodyString() + "'", response);
|
||||
}
|
||||
return action.convert(actionInvocation);
|
||||
}
|
||||
|
||||
public RemoteService getService() {
|
||||
return remoteService;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.cling.action;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.fourthline.cling.model.action.ActionInvocation;
|
||||
import org.fourthline.cling.model.meta.RemoteDevice;
|
||||
import org.fourthline.cling.model.meta.RemoteService;
|
||||
import org.fourthline.cling.model.meta.Service;
|
||||
import org.fourthline.cling.model.types.UnsignedIntegerFourBytes;
|
||||
import org.fourthline.cling.model.types.UnsignedIntegerTwoBytes;
|
||||
|
||||
public class AddPortMappingAction extends AbstractClingAction<Void> {
|
||||
|
||||
private final PortMapping portMapping;
|
||||
|
||||
public AddPortMappingAction(final Service<RemoteDevice, RemoteService> service, final PortMapping portMapping) {
|
||||
super(service, "AddPortMapping");
|
||||
this.portMapping = portMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getArgumentValues() {
|
||||
final HashMap<String, Object> args = new HashMap<>();
|
||||
args.put("NewExternalPort", new UnsignedIntegerTwoBytes(portMapping.getExternalPort()));
|
||||
args.put("NewProtocol", portMapping.getProtocol());
|
||||
args.put("NewInternalClient", portMapping.getInternalClient());
|
||||
args.put("NewInternalPort", new UnsignedIntegerTwoBytes(portMapping.getInternalPort()));
|
||||
args.put("NewLeaseDuration", new UnsignedIntegerFourBytes(portMapping.getLeaseDuration()));
|
||||
args.put("NewEnabled", portMapping.isEnabled());
|
||||
args.put("NewRemoteHost", portMapping.getRemoteHost());
|
||||
args.put("NewPortMappingDescription", portMapping.getDescription());
|
||||
return args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void convert(final ActionInvocation<RemoteService> response) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.cling.action;
|
||||
|
||||
import org.fourthline.cling.model.action.ActionInvocation;
|
||||
import org.fourthline.cling.model.meta.RemoteService;
|
||||
|
||||
public interface ClingAction<T> {
|
||||
|
||||
ActionInvocation<RemoteService> getActionInvocation();
|
||||
|
||||
T convert(ActionInvocation<RemoteService> response);
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.cling.action;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.fourthline.cling.model.action.ActionInvocation;
|
||||
import org.fourthline.cling.model.meta.RemoteService;
|
||||
import org.fourthline.cling.model.types.UnsignedIntegerTwoBytes;
|
||||
|
||||
public class DeletePortMappingAction extends AbstractClingAction<Void> {
|
||||
|
||||
private final int externalPort;
|
||||
private final String protocol;
|
||||
private final String remoteHost;
|
||||
|
||||
public DeletePortMappingAction(final RemoteService service, final PortMapping portMapping) {
|
||||
super(service, "DeletePortMapping");
|
||||
this.externalPort = portMapping.getExternalPort();
|
||||
this.protocol = portMapping.getProtocol().getName();
|
||||
this.remoteHost = portMapping.getRemoteHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getArgumentValues() {
|
||||
final HashMap<String, Object> args = new HashMap<>();
|
||||
args.put("NewExternalPort", new UnsignedIntegerTwoBytes(externalPort));
|
||||
args.put("NewProtocol", protocol);
|
||||
args.put("NewRemoteHost", remoteHost);
|
||||
return args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void convert(final ActionInvocation<RemoteService> response) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.chris.portmapper.router.cling.action;
|
||||
|
||||
import org.fourthline.cling.model.action.ActionInvocation;
|
||||
import org.fourthline.cling.model.meta.RemoteService;
|
||||
|
||||
public class GetExternalIpAction extends AbstractClingAction<String> {
|
||||
|
||||
public GetExternalIpAction(final RemoteService service) {
|
||||
super(service, "GetExternalIPAddress");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convert(final ActionInvocation<RemoteService> invocation) {
|
||||
return (String) invocation.getOutput("NewExternalIPAddress").getValue();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.cling.action;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.chris.portmapper.model.Protocol;
|
||||
import org.fourthline.cling.model.action.ActionInvocation;
|
||||
import org.fourthline.cling.model.meta.RemoteDevice;
|
||||
import org.fourthline.cling.model.meta.RemoteService;
|
||||
import org.fourthline.cling.model.meta.Service;
|
||||
import org.fourthline.cling.model.types.UnsignedIntegerFourBytes;
|
||||
import org.fourthline.cling.model.types.UnsignedIntegerTwoBytes;
|
||||
|
||||
public class GetPortMappingEntryAction extends AbstractClingAction<PortMapping> {
|
||||
|
||||
private final int index;
|
||||
|
||||
public GetPortMappingEntryAction(final Service<RemoteDevice, RemoteService> service, final int index) {
|
||||
super(service, "GetGenericPortMappingEntry");
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getArgumentValues() {
|
||||
return Collections.<String, Object> singletonMap("NewPortMappingIndex", new UnsignedIntegerTwoBytes(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PortMapping convert(final ActionInvocation<RemoteService> response) {
|
||||
final Protocol protocol = Protocol.getProtocol(getStringValue(response, "NewProtocol"));
|
||||
final String remoteHost = getStringValue(response, "NewRemoteHost");
|
||||
final int externalPort = getIntValue(response, "NewExternalPort");
|
||||
final String internalClient = getStringValue(response, "NewInternalClient");
|
||||
final int internalPort = getIntValue(response, "NewInternalPort");
|
||||
final String description = getStringValue(response, "NewPortMappingDescription");
|
||||
final boolean enabled = getBooleanValue(response, "NewEnabled");
|
||||
final long leaseDuration = getLongValue(response, "NewLeaseDuration");
|
||||
return new PortMapping(protocol, remoteHost, externalPort, internalClient, internalPort, description, enabled,
|
||||
leaseDuration);
|
||||
}
|
||||
|
||||
private boolean getBooleanValue(final ActionInvocation<RemoteService> response, final String argumentName) {
|
||||
return (boolean) response.getOutput(argumentName).getValue();
|
||||
}
|
||||
|
||||
protected int getIntValue(final ActionInvocation<?> response, final String argumentName) {
|
||||
return ((UnsignedIntegerTwoBytes) response.getOutput(argumentName).getValue()).getValue().intValue();
|
||||
}
|
||||
|
||||
protected long getLongValue(final ActionInvocation<?> response, final String argumentName) {
|
||||
return ((UnsignedIntegerFourBytes) response.getOutput(argumentName).getValue()).getValue().longValue();
|
||||
}
|
||||
|
||||
protected String getStringValue(final ActionInvocation<?> response, final String argumentName) {
|
||||
return (String) response.getOutput(argumentName).getValue();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.dummy;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.chris.portmapper.model.Protocol;
|
||||
import org.chris.portmapper.router.AbstractRouter;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class DummyRouter extends AbstractRouter {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final Collection<PortMapping> mappings;
|
||||
|
||||
public DummyRouter(final String name) {
|
||||
super(name);
|
||||
logger.debug("Created new DummyRouter");
|
||||
mappings = new LinkedList<>();
|
||||
mappings.add(new PortMapping(Protocol.TCP, "remoteHost1", 1, "internalClient1", 1,
|
||||
getName() + ": dummy port mapping 1"));
|
||||
mappings.add(
|
||||
new PortMapping(Protocol.UDP, null, 2, "internalClient2", 2, getName() + ": dummy port mapping 2"));
|
||||
mappings.add(
|
||||
new PortMapping(Protocol.TCP, null, 3, "internalClient3", 3, getName() + ": dummy port mapping 3"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPortMapping(final PortMapping mapping) {
|
||||
logger.debug("Adding mapping " + mapping);
|
||||
mappings.add(mapping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPortMappings(final Collection<PortMapping> mappingsToAdd) {
|
||||
logger.debug("Adding {} mappings: {}", mappingsToAdd.size(), mappingsToAdd);
|
||||
this.mappings.addAll(mappingsToAdd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
logger.debug("Disconnect");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExternalIPAddress() {
|
||||
return "DummyExternalIP";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalHostName() {
|
||||
return "DummyInternalHostName";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalPort() {
|
||||
return 42;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PortMapping> getPortMappings() {
|
||||
try {
|
||||
logger.debug("Sleep 3s to simulate delay when fetching port mappings.");
|
||||
Thread.sleep(3000);
|
||||
} catch (final InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logRouterInfo() {
|
||||
logger.info("DummyRouter " + getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMapping(final PortMapping mapping) {
|
||||
mappings.remove(mapping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePortMapping(final Protocol protocol, final String remoteHost, final int externalPort) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalHostAddress() throws RouterException {
|
||||
return "DummyLocalhostAddress";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.chris.portmapper.router.dummy;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.chris.portmapper.PortMapperApp;
|
||||
import org.chris.portmapper.router.AbstractRouterFactory;
|
||||
import org.chris.portmapper.router.IRouter;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
|
||||
/**
|
||||
* Router factory for testing without a real router.
|
||||
*/
|
||||
public class DummyRouterFactory extends AbstractRouterFactory {
|
||||
|
||||
public DummyRouterFactory(final PortMapperApp app) {
|
||||
super(app, "Dummy library");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<IRouter> findRoutersInternal() throws RouterException {
|
||||
final List<IRouter> routers = new LinkedList<>();
|
||||
routers.add(new DummyRouter("DummyRouter1"));
|
||||
routers.add(new DummyRouter("DummyRouter2"));
|
||||
return routers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IRouter connect(final String locationUrl) throws RouterException {
|
||||
return new DummyRouter("DummyRouter @ " + locationUrl);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.sbbi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sbbi.upnp.impls.InternetGatewayDevice;
|
||||
import net.sbbi.upnp.messages.ActionResponse;
|
||||
import net.sbbi.upnp.messages.UPNPResponseException;
|
||||
|
||||
/**
|
||||
* This class fetches all {@link PortMapping} from an {@link InternetGatewayDevice}.
|
||||
*/
|
||||
class SBBIPortMappingExtractor {
|
||||
|
||||
private final Logger logger;
|
||||
private final InternetGatewayDevice router;
|
||||
private final Collection<PortMapping> mappings;
|
||||
private boolean moreEntries;
|
||||
private int currentMappingNumber;
|
||||
private int nullPortMappings;
|
||||
|
||||
/**
|
||||
* The maximum number of port mappings that we will try to retrieve from the router.
|
||||
*/
|
||||
private final int maxNumPortMappings;
|
||||
|
||||
SBBIPortMappingExtractor(final InternetGatewayDevice router, final int maxNumPortMappings) {
|
||||
this(router, maxNumPortMappings, LoggerFactory.getLogger(SBBIPortMappingExtractor.class));
|
||||
}
|
||||
|
||||
SBBIPortMappingExtractor(final InternetGatewayDevice router, final int maxNumPortMappings, final Logger logger) {
|
||||
this.router = router;
|
||||
this.maxNumPortMappings = maxNumPortMappings;
|
||||
this.logger = logger;
|
||||
this.mappings = new LinkedList<>();
|
||||
this.moreEntries = true;
|
||||
this.currentMappingNumber = 0;
|
||||
this.nullPortMappings = 0;
|
||||
}
|
||||
|
||||
public Collection<PortMapping> getPortMappings() throws RouterException {
|
||||
|
||||
try {
|
||||
|
||||
/*
|
||||
* This is a little trick to get all port mappings. There is a method that gets the number of available port
|
||||
* mappings (getNatMappingsCount()), but it seems, that this method just tries to get all port mappings and
|
||||
* checks, if an error is returned.
|
||||
*
|
||||
* In order to speed this up, we will do the same here, but stop, when the first exception is thrown.
|
||||
*/
|
||||
|
||||
while (morePortMappingsAvailable()) {
|
||||
logger.debug("Getting port mapping with entry number {}...", currentMappingNumber);
|
||||
|
||||
try {
|
||||
final ActionResponse response = router.getGenericPortMappingEntry(currentMappingNumber);
|
||||
addResponse(response);
|
||||
} catch (final UPNPResponseException e) {
|
||||
handleUPNPResponseException(e);
|
||||
}
|
||||
|
||||
currentMappingNumber++;
|
||||
}
|
||||
|
||||
checkMaxNumPortMappingsReached();
|
||||
|
||||
} catch (final IOException e) {
|
||||
throw new RouterException("Could not get NAT mappings: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
logger.debug("Found {} mappings, {} mappings returned as null.", mappings.size(), nullPortMappings);
|
||||
return mappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check, if the max number of entries is reached and print a warning message.
|
||||
*/
|
||||
private void checkMaxNumPortMappingsReached() {
|
||||
if (currentMappingNumber == maxNumPortMappings) {
|
||||
logger.warn(
|
||||
"Reached max number of port mappings to get ({}). Perhaps not all port mappings where retrieved.",
|
||||
maxNumPortMappings);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean morePortMappingsAvailable() {
|
||||
return moreEntries && currentMappingNumber < maxNumPortMappings;
|
||||
}
|
||||
|
||||
private void addResponse(final ActionResponse response) {
|
||||
// Create a port mapping for the response.
|
||||
if (response != null) {
|
||||
final PortMapping newMapping = PortMapping.create(response);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Got port mapping #{}: {}", currentMappingNumber, newMapping.getCompleteDescription());
|
||||
}
|
||||
mappings.add(newMapping);
|
||||
} else {
|
||||
nullPortMappings++;
|
||||
logger.trace("Got a null port mapping for number {} ({} so far)", currentMappingNumber, nullPortMappings);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUPNPResponseException(final UPNPResponseException e) {
|
||||
if (isNoMoreMappingsException(e)) {
|
||||
moreEntries = false;
|
||||
logger.debug(
|
||||
"Got no port mapping for entry number {} (error code: {}, error description: {}). Stop getting more entries.",
|
||||
currentMappingNumber, e.getDetailErrorCode(), e.getDetailErrorDescription());
|
||||
} else {
|
||||
moreEntries = false;
|
||||
logger.error("Got exception when fetching port mapping for entry number " + currentMappingNumber
|
||||
+ ". Stop getting more entries.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks, if the error code of the given exception means, that no more mappings are available.
|
||||
* <p>
|
||||
* The following error codes are recognized:
|
||||
* <ul>
|
||||
* <li>SpecifiedArrayIndexInvalid: 713</li>
|
||||
* <li>NoSuchEntryInArray: 714</li>
|
||||
* <li>Invalid Args: 402 (e.g. for DD-WRT, TP-LINK TL-R460 firmware 4.7.6 Build 100714 Rel.63134n)</li>
|
||||
* <li>Other errors, e.g. "The reference to entity "T" must end with the ';' delimiter" or
|
||||
* "Content is not allowed in prolog": 899 (e.g. ActionTec MI424-WR, Thomson TWG850-4U)</li>
|
||||
* </ul>
|
||||
* See bug reports
|
||||
* <ul>
|
||||
* <li><a href= "https://sourceforge.net/tracker/index.php?func=detail&aid=1939749&group_id=213879&atid=1027466" >
|
||||
* https://sourceforge.net/tracker/index.php?func=detail&aid= 1939749&group_id=213879&atid=1027466</a></li>
|
||||
* <li><a href="http://www.sbbi.net/forum/viewtopic.php?p=394">http://www.sbbi .net/forum/viewtopic.php?p=394</a>
|
||||
* </li>
|
||||
* <li><a href= "http://sourceforge.net/tracker/?func=detail&atid=1027466&aid=3325388&group_id=213879" >http://
|
||||
* sourceforge.net/tracker/?func=detail&atid=1027466&aid=3325388& group_id=213879</a></li>
|
||||
* <a href= "https://sourceforge.net/tracker2/?func=detail&aid=2540478&group_id=213879&atid=1027466" >https://
|
||||
* sourceforge.net/tracker2/?func=detail&aid=2540478&group_id= 213879&atid=1027466</a></li>
|
||||
* </ul>
|
||||
*
|
||||
* @param e
|
||||
* the exception to check
|
||||
* @return <code>true</code>, if the given exception means, that no more port mappings are available, else
|
||||
* <code>false</code>.
|
||||
*/
|
||||
private boolean isNoMoreMappingsException(final UPNPResponseException e) {
|
||||
final int errorCode = e.getDetailErrorCode();
|
||||
switch (errorCode) {
|
||||
case 713:
|
||||
case 714:
|
||||
case 402:
|
||||
case 899:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,233 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.sbbi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.chris.portmapper.PortMapperApp;
|
||||
import org.chris.portmapper.Settings;
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.chris.portmapper.model.Protocol;
|
||||
import org.chris.portmapper.router.AbstractRouter;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
import org.chris.portmapper.util.EncodingUtilities;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sbbi.upnp.devices.UPNPRootDevice;
|
||||
import net.sbbi.upnp.impls.InternetGatewayDevice;
|
||||
import net.sbbi.upnp.messages.UPNPResponseException;
|
||||
|
||||
/**
|
||||
* This class represents a router device and provides methods for managing port mappings and getting information about
|
||||
* the router. It useses the SBBI library's {@link InternetGatewayDevice}.
|
||||
*/
|
||||
public class SBBIRouter extends AbstractRouter {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* The wrapped router device.
|
||||
*/
|
||||
final private InternetGatewayDevice router;
|
||||
|
||||
/**
|
||||
* The maximum number of port mappings that we will try to retrieve from the router.
|
||||
*/
|
||||
private final static int MAX_NUM_PORTMAPPINGS = 500;
|
||||
|
||||
private final PortMapperApp app;
|
||||
|
||||
SBBIRouter(final PortMapperApp app, final InternetGatewayDevice router) {
|
||||
super(router.getIGDRootDevice().getModelName());
|
||||
this.app = app;
|
||||
this.router = router;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExternalIPAddress() throws RouterException {
|
||||
logger.debug("Get external IP address...");
|
||||
String ipAddress;
|
||||
try {
|
||||
ipAddress = router.getExternalIPAddress();
|
||||
} catch (final UPNPResponseException e) {
|
||||
throw new RouterException("Could not get external IP", e);
|
||||
} catch (final IOException e) {
|
||||
throw new RouterException("Could not get external IP", e);
|
||||
}
|
||||
logger.info("Got external IP address " + ipAddress + " for router.");
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalHostName() {
|
||||
logger.debug("Get internal IP address...");
|
||||
final URL presentationURL = router.getIGDRootDevice().getPresentationURL();
|
||||
if (presentationURL == null) {
|
||||
logger.warn("Did not get presentation url");
|
||||
return null;
|
||||
}
|
||||
final String ipAddress = presentationURL.getHost();
|
||||
logger.info("Got internal host name '{}' for router.", ipAddress);
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalPort() {
|
||||
logger.debug("Get internal port of router...");
|
||||
final URL presentationURL = router.getIGDRootDevice().getPresentationURL();
|
||||
// Presentation URL may be null in some situations.
|
||||
if (presentationURL != null) {
|
||||
final int presentationUrlPort = presentationURL.getPort();
|
||||
// https://sourceforge.net/tracker/?func=detail&aid=3198378&group_id=213879&atid=1027466
|
||||
// Some routers send an invalid presentationURL, in this case use
|
||||
// URLBase.
|
||||
if (presentationUrlPort > 0) {
|
||||
logger.debug("Got valid internal port {} from presentation URL '{}'", presentationUrlPort,
|
||||
presentationURL);
|
||||
return presentationUrlPort;
|
||||
} else {
|
||||
logger.debug("Got invalid port {} from presentation url '{}'", presentationUrlPort, presentationURL);
|
||||
}
|
||||
} else {
|
||||
logger.debug("Presentation url is null");
|
||||
}
|
||||
final URL urlBase = router.getIGDRootDevice().getURLBase();
|
||||
final int urlBasePort = urlBase.getPort();
|
||||
logger.debug("Presentation URL is null or returns invalid port: using port {} of base url '{}'", urlBasePort,
|
||||
urlBase);
|
||||
|
||||
return urlBasePort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PortMapping> getPortMappings() throws RouterException {
|
||||
return new SBBIPortMappingExtractor(router, MAX_NUM_PORTMAPPINGS).getPortMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logRouterInfo() throws RouterException {
|
||||
final Map<String, String> info = new HashMap<>();
|
||||
final UPNPRootDevice rootDevice = router.getIGDRootDevice();
|
||||
info.put("friendlyName", rootDevice.getFriendlyName());
|
||||
info.put("manufacturer", rootDevice.getManufacturer());
|
||||
info.put("modelDescription", rootDevice.getModelDescription());
|
||||
info.put("modelName", rootDevice.getModelName());
|
||||
info.put("serialNumber", rootDevice.getSerialNumber());
|
||||
info.put("vendorFirmware", rootDevice.getVendorFirmware());
|
||||
|
||||
info.put("modelNumber", rootDevice.getModelNumber());
|
||||
info.put("modelURL", rootDevice.getModelURL());
|
||||
info.put("manufacturerURL", rootDevice.getManufacturerURL().toExternalForm());
|
||||
info.put("presentationURL",
|
||||
rootDevice.getPresentationURL() != null ? rootDevice.getPresentationURL().toExternalForm() : null);
|
||||
info.put("urlBase", rootDevice.getURLBase().toExternalForm());
|
||||
|
||||
final SortedSet<String> sortedKeys = new TreeSet<>(info.keySet());
|
||||
|
||||
for (final String key : sortedKeys) {
|
||||
final String value = info.get(key);
|
||||
logger.info("Router Info: {} \t= {}", key, value);
|
||||
}
|
||||
|
||||
logger.info("def loc: {}", rootDevice.getDeviceDefLoc());
|
||||
logger.trace("def loc data: {}", rootDevice.getDeviceDefLocData());
|
||||
logger.info("icons: {}", rootDevice.getDeviceIcons());
|
||||
logger.info("device type: {}", rootDevice.getDeviceType());
|
||||
logger.info("direct parent: {}", rootDevice.getDirectParent());
|
||||
logger.info("disc udn: {}", rootDevice.getDiscoveryUDN());
|
||||
logger.info("disc usn: {}", rootDevice.getDiscoveryUSN());
|
||||
logger.info("udn: {}", rootDevice.getUDN());
|
||||
}
|
||||
|
||||
private boolean addPortMapping(final String description, final Protocol protocol, final String remoteHost,
|
||||
final int externalPort, final String internalClient, final int internalPort, final int leaseDuration)
|
||||
throws RouterException {
|
||||
|
||||
final String protocolString = protocol == Protocol.TCP ? "TCP" : "UDP";
|
||||
|
||||
final String encodedDescription = encodeIfNecessary(description);
|
||||
|
||||
try {
|
||||
final boolean success = router.addPortMapping(encodedDescription, null, internalPort, externalPort,
|
||||
internalClient, leaseDuration, protocolString);
|
||||
return success;
|
||||
} catch (final IOException e) {
|
||||
throw new RouterException("Could not add port mapping: " + e.getMessage(), e);
|
||||
} catch (final UPNPResponseException e) {
|
||||
throw new RouterException("Could not add port mapping: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String encodeIfNecessary(final String description) {
|
||||
final Settings settings = app.getSettings();
|
||||
if (settings == null || settings.isUseEntityEncoding()) {
|
||||
return EncodingUtilities.htmlEntityEncode(description);
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPortMappings(final Collection<PortMapping> mappings) throws RouterException {
|
||||
for (final PortMapping portMapping : mappings) {
|
||||
logger.info("Adding port mapping {}", portMapping);
|
||||
addPortMapping(portMapping);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPortMapping(final PortMapping mapping) throws RouterException {
|
||||
logger.info("Adding port mapping ()", mapping.getCompleteDescription());
|
||||
addPortMapping(mapping.getDescription(), mapping.getProtocol(), mapping.getRemoteHost(),
|
||||
mapping.getExternalPort(), mapping.getInternalClient(), mapping.getInternalPort(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMapping(final PortMapping mapping) throws RouterException {
|
||||
removePortMapping(mapping.getProtocol(), mapping.getRemoteHost(), mapping.getExternalPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePortMapping(final Protocol protocol, final String remoteHost, final int externalPort)
|
||||
throws RouterException {
|
||||
final String protocolString = (protocol.equals(Protocol.TCP) ? "TCP" : "UDP");
|
||||
try {
|
||||
router.deletePortMapping(remoteHost, externalPort, protocolString);
|
||||
} catch (final IOException e) {
|
||||
throw new RouterException("Could not remove port mapping", e);
|
||||
} catch (final UPNPResponseException e) {
|
||||
throw new RouterException("Could not remove port mapping", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
// Nothing to do right now.
|
||||
}
|
||||
|
||||
public long getUpTime() {
|
||||
// The SBBI library does not provide a method for getting the uptime.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.chris.portmapper.router.sbbi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.sbbi.upnp.impls.InternetGatewayDevice;
|
||||
|
||||
import org.chris.portmapper.PortMapperApp;
|
||||
import org.chris.portmapper.router.AbstractRouterFactory;
|
||||
import org.chris.portmapper.router.IRouter;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
|
||||
/**
|
||||
* Router factory using the SBBI UPnP library.
|
||||
*/
|
||||
public class SBBIRouterFactory extends AbstractRouterFactory {
|
||||
|
||||
/**
|
||||
* The timeout in milliseconds for finding a router device.
|
||||
*/
|
||||
private final static int DISCOVERY_TIMEOUT = 5000;
|
||||
|
||||
public SBBIRouterFactory(final PortMapperApp app) {
|
||||
super(app, "SBBI UPnP lib");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<IRouter> findRoutersInternal() throws RouterException {
|
||||
|
||||
final InternetGatewayDevice[] devices;
|
||||
try {
|
||||
devices = InternetGatewayDevice.getDevices(DISCOVERY_TIMEOUT);
|
||||
} catch (final IOException e) {
|
||||
throw new RouterException("Could not find devices", e);
|
||||
}
|
||||
|
||||
if (devices == null || devices.length == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<IRouter> routers = new ArrayList<>(devices.length);
|
||||
|
||||
for (final InternetGatewayDevice device : devices) {
|
||||
routers.add(new SBBIRouter(app, device));
|
||||
}
|
||||
|
||||
return routers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IRouter connect(final String locationUrl) throws RouterException {
|
||||
throw new UnsupportedOperationException("Direct connection is not implemented for SBBI library.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.chris.portmapper.router.weupnp;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.bitlet.weupnp.GatewayDevice;
|
||||
import org.bitlet.weupnp.PortMappingEntry;
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.chris.portmapper.model.Protocol;
|
||||
import org.chris.portmapper.router.AbstractRouter;
|
||||
import org.chris.portmapper.router.IRouter;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class is an implements an {@link IRouter} using the weupnp library's {@link GatewayDevice}.
|
||||
*/
|
||||
public class WeUPnPRouter extends AbstractRouter {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final GatewayDevice device;
|
||||
|
||||
WeUPnPRouter(final GatewayDevice device) {
|
||||
super(device.getFriendlyName());
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPortMapping(final PortMapping mapping) throws RouterException {
|
||||
try {
|
||||
device.addPortMapping(mapping.getExternalPort(), mapping.getInternalPort(), mapping.getInternalClient(),
|
||||
mapping.getProtocol().getName(), mapping.getDescription());
|
||||
} catch (final Exception e) {
|
||||
throw new RouterException("Could not add portmapping", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPortMappings(final Collection<PortMapping> mappings) throws RouterException {
|
||||
for (final PortMapping mapping : mappings) {
|
||||
this.addPortMapping(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
// noting to do right now
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExternalIPAddress() throws RouterException {
|
||||
try {
|
||||
return device.getExternalIPAddress();
|
||||
} catch (final Exception e) {
|
||||
throw new RouterException("Could not get external IP address", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalHostName() {
|
||||
final String url = device.getPresentationURL();
|
||||
if (url == null || url.trim().length() == 0) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new URL(url).getHost();
|
||||
} catch (final MalformedURLException e) {
|
||||
logger.warn("Could not get URL for internal host name '" + url + "'", e);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalPort() throws RouterException {
|
||||
String url = device.getPresentationURL();
|
||||
if (url == null) {
|
||||
url = device.getURLBase();
|
||||
logger.info("Presentation url is null: use url base '{}'", url);
|
||||
}
|
||||
if (url == null) {
|
||||
throw new RouterException("Presentation URL and URL base are null");
|
||||
}
|
||||
|
||||
try {
|
||||
return new URL(url).getPort();
|
||||
} catch (final MalformedURLException e) {
|
||||
throw new RouterException("Could not get internal port from URL '" + url + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PortMapping> getPortMappings() throws RouterException {
|
||||
final Collection<PortMapping> mappings = new LinkedList<>();
|
||||
boolean morePortMappings = true;
|
||||
int index = 0;
|
||||
while (morePortMappings) {
|
||||
final PortMappingEntry entry = new PortMappingEntry();
|
||||
try {
|
||||
logger.debug("Getting port mapping {}...", index);
|
||||
if (!device.getGenericPortMappingEntry(index, entry)) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
logger.debug("Got port mapping {}: {}", index, entry);
|
||||
} catch (final Exception e) {
|
||||
morePortMappings = false;
|
||||
logger.debug("Got an exception with message '{}‘ for index {}, stop getting more mappings",
|
||||
e.getMessage(), index);
|
||||
}
|
||||
|
||||
if (entry.getProtocol() != null) {
|
||||
final Protocol protocol = entry.getProtocol().equalsIgnoreCase("TCP") ? Protocol.TCP : Protocol.UDP;
|
||||
final PortMapping m = new PortMapping(protocol, entry.getRemoteHost(), entry.getExternalPort(),
|
||||
entry.getInternalClient(), entry.getInternalPort(), entry.getPortMappingDescription());
|
||||
mappings.add(m);
|
||||
} else {
|
||||
logger.debug("Got null port mapping for index {}", index);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logRouterInfo() throws RouterException {
|
||||
final Map<String, String> info = new HashMap<>();
|
||||
info.put("friendlyName", device.getFriendlyName());
|
||||
info.put("manufacturer", device.getManufacturer());
|
||||
info.put("modelDescription", device.getModelDescription());
|
||||
|
||||
final SortedSet<String> sortedKeys = new TreeSet<>(info.keySet());
|
||||
|
||||
for (final String key : sortedKeys) {
|
||||
final String value = info.get(key);
|
||||
logger.info("Router Info: {} \t= {}", key, value);
|
||||
}
|
||||
|
||||
logger.info("def loc: {}", device.getLocation());
|
||||
logger.info("device type: {}", device.getDeviceType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMapping(final PortMapping mapping) throws RouterException {
|
||||
this.removePortMapping(mapping.getProtocol(), mapping.getRemoteHost(), mapping.getExternalPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePortMapping(final Protocol protocol, final String remoteHost, final int externalPort)
|
||||
throws RouterException {
|
||||
try {
|
||||
device.deletePortMapping(externalPort, protocol.getName());
|
||||
} catch (final Exception e) {
|
||||
throw new RouterException("Could not delete port mapping", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.chris.portmapper.router.weupnp;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bitlet.weupnp.GatewayDevice;
|
||||
import org.bitlet.weupnp.GatewayDiscover;
|
||||
import org.chris.portmapper.PortMapperApp;
|
||||
import org.chris.portmapper.router.AbstractRouterFactory;
|
||||
import org.chris.portmapper.router.IRouter;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A router factoring using the weupnp library.
|
||||
*/
|
||||
public class WeUPnPRouterFactory extends AbstractRouterFactory {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final GatewayDiscover discover = new GatewayDiscover();
|
||||
|
||||
public WeUPnPRouterFactory(final PortMapperApp app) {
|
||||
super(app, "weupnp lib");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<IRouter> findRoutersInternal() throws RouterException {
|
||||
logger.debug("Searching for gateway devices...");
|
||||
final Map<InetAddress, GatewayDevice> devices;
|
||||
try {
|
||||
devices = discover.discover();
|
||||
} catch (final Exception e) {
|
||||
throw new RouterException("Could not discover a valid gateway device: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (devices == null || devices.size() == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<IRouter> routers = new ArrayList<>(devices.size());
|
||||
for (final GatewayDevice device : devices.values()) {
|
||||
routers.add(new WeUPnPRouter(device));
|
||||
}
|
||||
return routers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IRouter connect(final String locationUrl) throws RouterException {
|
||||
|
||||
final GatewayDevice device = new GatewayDevice();
|
||||
device.setLocation(locationUrl);
|
||||
device.setSt("urn:schemas-upnp-org:device:InternetGatewayDevice:1");
|
||||
try {
|
||||
device.setLocalAddress(InetAddress.getLocalHost());
|
||||
} catch (final UnknownHostException e) {
|
||||
throw new RouterException("Could not get ip of localhost: " + e.getMessage(), e);
|
||||
}
|
||||
try {
|
||||
device.loadDescription();
|
||||
} catch (final Exception e) {
|
||||
throw new RouterException(
|
||||
"Could not load description of device for location url " + locationUrl + " : " + e.getMessage(), e);
|
||||
}
|
||||
return new WeUPnPRouter(device);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.chris.portmapper.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EncodingUtilities {
|
||||
|
||||
private static Map<Character, String> knownEncodings;
|
||||
|
||||
static {
|
||||
knownEncodings = new HashMap<>();
|
||||
knownEncodings.put('<', "<");
|
||||
knownEncodings.put('>', ">");
|
||||
knownEncodings.put('&', "&");
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all special characters with their html entities.
|
||||
*
|
||||
* @param s
|
||||
* the string in which to replace the special characters.
|
||||
* @return the result of the replacement.
|
||||
*/
|
||||
public static String htmlEntityEncode(final String s) {
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
final char c = s.charAt(i);
|
||||
if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9') {
|
||||
buf.append(c);
|
||||
} else {
|
||||
if (knownEncodings.containsKey(c)) {
|
||||
buf.append(knownEncodings.get(c));
|
||||
} else {
|
||||
buf.append("&#" + (int) c + ";");
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<!--
|
||||
|
||||
UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
|
||||
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 3 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/>.
|
||||
|
||||
-->
|
||||
<configuration debug="false" scan="false">
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="debug">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
# UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
# Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
#
|
||||
# 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 3 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/>.
|
||||
#
|
||||
|
||||
title = Meine Aufgabe
|
||||
description = Verbinden zum Router.
|
||||
startMessage = Verbinde...
|
||||
errorMessage = Fehler: Verbindung zu %s konnte nicht aufgebaut werden
|
||||
finishedMessage = Verbindung zu %s aufgebaut
|
||||
|
||||
updateAddresses = Adressen werden aktualisiert
|
||||
updatePortMappings = Port Mappings werden aktualisiert
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
# UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
# Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
#
|
||||
# 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 3 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/>.
|
||||
#
|
||||
|
||||
title = My Task
|
||||
description = Connect to router.
|
||||
startMessage = Connecting to router
|
||||
errorMessage = Error: Could not connect to router: %s
|
||||
finishedMessage = Connected to router %s
|
||||
|
||||
updateAddresses = Updating Addresses
|
||||
updatePortMappings = Updating Port Mappings
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
# UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
# Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
#
|
||||
# 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 3 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/>.
|
||||
#
|
||||
|
||||
title = Min Oppgave
|
||||
description = Koble til ruter.
|
||||
startMessage = Kobler til ruter...
|
||||
errorMessage = Feil: Kunne ikke koble til ruter: %s
|
||||
finishedMessage = Koblet til ruter %s
|
||||
|
||||
updateAddresses = Oppdaterer adresser
|
||||
updatePortMappings = Oppdaterer portoppf<70>ringer
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
#
|
||||
# UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
# Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
#
|
||||
# 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 3 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/>.
|
||||
#
|
||||
|
||||
Application.id=PortMapper
|
||||
Application.title=PortMapper
|
||||
Application.version=@VERSION_NUMBER@
|
||||
|
||||
Application.lookAndFeel=system
|
||||
|
||||
mainFrame.title=${Application.title} ${Application.version}
|
||||
|
||||
messages.error_getting_localhost_address=Fehler beim Ermitteln der lokalen IP-Addresse.\nBenutzen Sie den 'Hinzuf<75>gen...' Button um eine Weiterleitung zu erzeugen\nund geben Sie ihre IP-Addresse manuell ein.
|
||||
messages.error=Fehler
|
||||
|
||||
messages.select_router.title=Router ausw<73>hlen
|
||||
messages.select_router.message=Es wurde mehr als ein Router gefunden.\nBitte w<>hlen Sie einen aus.
|
||||
|
||||
mainFrame.router.title=Router
|
||||
mainFrame.router.not_connected=(nicht verbunden)
|
||||
mainFrame.router.updating=(aktualisieren...)
|
||||
mainFrame.router.external_address=Externe IP-Addresse
|
||||
mainFrame.router.internal_address=Interne IP-Addresse
|
||||
mainFrame.log_messages.title=Log-Meldungen
|
||||
mainFrame.port_mappings.title=Portweiterleitungen
|
||||
|
||||
|
||||
mainFrame.mappings.protocol=Protokoll
|
||||
mainFrame.mappings.remote_host=Entfernter Host
|
||||
mainFrame.mappings.external_port=Externer Port
|
||||
mainFrame.mappings.internal_client=Interne Addresse
|
||||
mainFrame.mappings.internal_port=Interner Port
|
||||
mainFrame.mappings.description=Beschreibung
|
||||
|
||||
mainFrame.port_mapping_presets.title=Vorlagen
|
||||
|
||||
# Actions
|
||||
|
||||
mainFrame.showAboutDialog.Action.text=&<26>ber...
|
||||
mainFrame.showAboutDialog.Action.shortDescription=Zeigt das <20>ber... Fenster
|
||||
|
||||
mainFrame.router.updateAddresses.Action.text=&Aktualisieren
|
||||
mainFrame.router.updateAddresses.Action.shortDescription=Aktualisiere die IP-Addressen des Router
|
||||
|
||||
mainFrame.router.info.Action.text=&Info
|
||||
mainFrame.router.info.Action.shortDescription=Zeige Informationen <20>ber den Router an
|
||||
|
||||
mainFrame.router.connect.Action.text=&Verbinden
|
||||
mainFrame.router.connect.Action.shortDescription=Verbindung zum Router aufbauen
|
||||
|
||||
mainFrame.router.disconnect.Action.text=&Trennen
|
||||
mainFrame.router.disconnect.Action.shortDescription=Verbindung zum Router trennen
|
||||
|
||||
mainFrame.router.copyInternalAddress.Action.text=Kopieren
|
||||
mainFrame.router.copyInternalAddress.Action.shortDescription=Kopiere die interne Addresse des Routers in die Zwischenablage
|
||||
|
||||
mainFrame.router.copyExternalAddress.Action.text=Kopieren
|
||||
mainFrame.router.copyExternalAddress.Action.shortDescription=Kopiere die externe Addresse des Routers in die Zwischenablage
|
||||
|
||||
mainFrame.mappings.update.Action.text=Aktualisiere
|
||||
mainFrame.mappings.update.Action.shortDescription=Aktualisiere die Portweiterleitungen
|
||||
|
||||
mainFrame.mappings.remove.Action.text=&Entfernen
|
||||
mainFrame.mappings.remove.Action.shortDescription=Entferne die ausgew<65>hlte Portweiterleitungen
|
||||
|
||||
mainFrame.preset_mappings.create.Action.text=&Hinzuf<75>gen...
|
||||
mainFrame.preset_mappings.create.Action.shortDescription=F<EFBFBD>ge eine neue Portweiterleitung hinzu
|
||||
|
||||
mainFrame.preset_mappings.edit.Action.text=Bearbeiten
|
||||
mainFrame.preset_mappings.edit.Action.shortDescription=Bearbeite die ausgew<65>hlte Vorlage
|
||||
|
||||
mainFrame.preset_mappings.remove.Action.text=&L<>schen
|
||||
mainFrame.preset_mappings.remove.Action.shortDescription=L<EFBFBD>sche die ausgew<65>hlte Vorlage
|
||||
|
||||
mainFrame.preset_mappings.use.Action.text=&Benutze
|
||||
mainFrame.preset_mappings.use.Action.shortDescription=Benutze die ausgew<65>hlte Vorlage
|
||||
|
||||
mainFrame.portmapper.settings.Action.text=Einstellungen...
|
||||
mainFrame.portmapper.settings.Action.shortDescription=Einstellungen von PortMapper <20>ndern
|
||||
|
||||
# About dialog
|
||||
|
||||
about_dialog.close.Action.text=Schlie<EFBFBD>en
|
||||
about_dialog.close.Action.shortDescription=Schlie<EFBFBD>e den Dialog
|
||||
|
||||
about_dialog.title=<EFBFBD>ber ${Application.title} ${Application.version}
|
||||
|
||||
about_dialog.label1.text=${Application.title} Version ${Application.version}
|
||||
about_dialog.label2.text=Verwalten der Portweiterleitungen eines Routers mit Universal Plug and Play.
|
||||
about_dialog.label3.text=Created by Christoph Pirkl
|
||||
about_dialog.label4.text=Folgende Bibiliotheken wurden benutzt
|
||||
|
||||
|
||||
about_dialog.tooltip.click_here=Hier klicken um die URL
|
||||
about_dialog.tooltip.in_browser=in einem Browser zu <20>ffnen
|
||||
|
||||
about_dialog.upnplib_label.label=SBBI UPNPLib
|
||||
about_dialog.upnplib_label.url=https://sourceforge.net/projects/upnplibmobile/
|
||||
about_dialog.upnplib_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.upnplib_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.weupnp_label.label=weupnp
|
||||
about_dialog.weupnp_label.url=http://code.google.com/p/weupnp/
|
||||
about_dialog.weupnp_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.weupnp_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.cling_label.label=Cling
|
||||
about_dialog.cling_label.url=http://4thline.org/projects/cling/
|
||||
about_dialog.cling_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.cling_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.app_framework_label.label=Better Swing Application Framework
|
||||
about_dialog.app_framework_label.url=https://kenai.com/projects/bsaf/pages/Home
|
||||
about_dialog.app_framework_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.app_framework_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.slf4j_label.label=slf4j
|
||||
about_dialog.slf4j_label.url=http://www.slf4j.org/
|
||||
about_dialog.slf4j_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.slf4j_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.logback_label.label=logback
|
||||
about_dialog.logback_label.url=http://logback.qos.ch/
|
||||
about_dialog.logback_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.logback_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.miglayout_label.label=MiGLayout
|
||||
about_dialog.miglayout_label.url=http://www.miglayout.com/
|
||||
about_dialog.miglayout_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.miglayout_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.label5.text=Besuchen Sie die ${Application.title} Homepage
|
||||
|
||||
about_dialog.homepage_label.label=https://github.com/kaklakariada/portmapper
|
||||
about_dialog.homepage_label.url=https://github.com/kaklakariada/portmapper
|
||||
about_dialog.homepage_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.homepage_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
# Edit preset mapping dialog
|
||||
|
||||
|
||||
preset_dialog.title=Bearbeiten der Vorlagen
|
||||
|
||||
preset_dialog.add_port.Action.text=Hinzuf<EFBFBD>gen
|
||||
preset_dialog.add_port.Action.shortDescription=F<EFBFBD>ge einen neuen Port zur Liste hinzu
|
||||
|
||||
preset_dialog.add_port_range.Action.text=Bereich hinzuf<75>gen...
|
||||
preset_dialog.add_port_range.Action.shortDescription=F<EFBFBD>ge mehrere Ports zur Liste hinzu
|
||||
|
||||
preset_dialog.remove_port.Action.text=Entfernen
|
||||
preset_dialog.remove_port.Action.shortDescription=Entferne einen Port aus der Liste
|
||||
|
||||
preset_dialog.save.Action.text=Speichern
|
||||
preset_dialog.save.Action.shortDescription=Speichere die <20>nderungen an den Vorlagen
|
||||
|
||||
preset_dialog.cancel.Action.text=Abbrechen
|
||||
preset_dialog.cancel.Action.shortDescription=Die <20>nderungen an den Vorlagen nicht speichern
|
||||
|
||||
preset_dialog.ports.title=Ports
|
||||
|
||||
preset_dialog.ports.protocol=Protokoll
|
||||
preset_dialog.ports.internal=Interner Port
|
||||
preset_dialog.ports.external=Externer Port
|
||||
|
||||
preset_dialog.preset.text=Vorlagen
|
||||
preset_dialog.protocol.text=Protokoll
|
||||
preset_dialog.description.text=Beschreibung
|
||||
preset_dialog.protocol_tcp.text=TCP
|
||||
preset_dialog.protocol_udp.text=UDP
|
||||
preset_dialog.remote_host.text=Entfernter Host
|
||||
preset_dialog.remote_host_empty_for_all.text=(leer f<>r alle)
|
||||
preset_dialog.external_port.text=Externer Port
|
||||
preset_dialog.internal_client.text=Interner Client
|
||||
preset_dialog.internal_client_use_local_host.text=Benutze localhost
|
||||
preset_dialog.internal_port.text=Interner Port
|
||||
|
||||
preset_dialog.error.title=Fehler
|
||||
preset_dialog.error.no_description=Bitte eine Beschreibung eingeben.
|
||||
preset_dialog.error.no_ports=Bitte mindestens einen Port hinzuf<75>gen.
|
||||
preset_dialog.error.duplicate_name=Eine Vorlage mit dieser Beschreibung existiert bereits, bitte eine andere Beschreibung eingeben.
|
||||
|
||||
# Add port range dialog
|
||||
|
||||
add_port_range_dialog.title=Mehrere Ports hinzuf<75>gen
|
||||
|
||||
add_port_range_dialog.cancel.Action.text=Abbrechen
|
||||
add_port_range_dialog.cancel.Action.shortDescription=Ports nicht hinzuf<75>gen
|
||||
|
||||
add_port_range_dialog.add.Action.text=Hinzuf<EFBFBD>gen
|
||||
add_port_range_dialog.add.Action.shortDescription=Ports zur Liste hinzuf<75>gen
|
||||
|
||||
add_port_range_dialog.protocol.text=Protokoll
|
||||
add_port_range_dialog.internal_ports_from.text=Interne Ports:
|
||||
add_port_range_dialog.internal_ports_to.text=bis
|
||||
add_port_range_dialog.external_ports_from.text=Externe Ports:
|
||||
add_port_range_dialog.external_ports_to.text=bis
|
||||
|
||||
add_port_range_dialog.external_equal_internal.text=Externe Ports sind identisch mit internen Ports
|
||||
add_port_range_dialog.invalid_number.title=Ung<EFBFBD>ltige Port-Nummer
|
||||
add_port_range_dialog.invalid_number.message=Bitte geben Sie Zahlen von 1 bis 65535 ein.
|
||||
|
||||
add_port_range_dialog.invalid_internal_range.title=Ung<EFBFBD>ltiger Zahlenbereich f<>r internen Port
|
||||
add_port_range_dialog.invalid_internal_range.message=Der 'bis'-Port muss gr<67><72>er als der 'von'-Port sein.
|
||||
|
||||
add_port_range_dialog.invalid_external_range.title=Ung<EFBFBD>ltiger Zahlenbereich f<>r externen Port
|
||||
add_port_range_dialog.invalid_external_range.message=Der 'bis'-Port muss gr<67><72>er als der 'von'-Port sein.
|
||||
|
||||
add_port_range_dialog.invalid_range_length.title=Ung<EFBFBD>ltiger Bereich
|
||||
add_port_range_dialog.invalid_range_length.message=Der Bereich der externen Ports muss genauso lang sein wie der Bereich der internen Ports.
|
||||
|
||||
|
||||
# Settings dialog
|
||||
|
||||
settings_dialog.title=UPnP PortMapper Einstellungen
|
||||
|
||||
settings_dialog.save.Action.text=Speichern
|
||||
settings_dialog.save.Action.shortDescription=Einstellungen speichern
|
||||
|
||||
settings_dialog.cancel.Action.text=Abbrechen
|
||||
settings_dialog.cancel.Action.shortDescription=Einstellungen nicht speichern
|
||||
|
||||
settings_dialog.use_entity_encoding.text=Verwende Entity Encoding f<>r Beschreibungen
|
||||
|
||||
settings_dialog.log_level.text=Log Granularit<69>t
|
||||
settings_dialog.upnp_lib.text=UPnP Bibliothek
|
||||
|
|
@ -0,0 +1,230 @@
|
|||
#
|
||||
# UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
# Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
#
|
||||
# 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 3 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/>.
|
||||
#
|
||||
|
||||
Application.id=PortMapper
|
||||
Application.title=PortMapper
|
||||
Application.version=@VERSION_NUMBER@
|
||||
|
||||
Application.lookAndFeel=system
|
||||
|
||||
mainFrame.title=${Application.title} ${Application.version}
|
||||
|
||||
messages.error_getting_localhost_address=Could not retrieve address of local host.\nPlease use 'Add...' button to create a mapping\nand enter address of local host manually.
|
||||
messages.error=Error
|
||||
|
||||
messages.select_router.title=Select router
|
||||
messages.select_router.message=More than one router was found.\nPlease select one to connect to.
|
||||
|
||||
mainFrame.router.title=Router
|
||||
mainFrame.router.not_connected=(not connected)
|
||||
mainFrame.router.updating=(updating)
|
||||
mainFrame.router.external_address=External address
|
||||
mainFrame.router.internal_address=Internal address
|
||||
mainFrame.log_messages.title=Log messages
|
||||
mainFrame.port_mappings.title=Port mappings
|
||||
|
||||
|
||||
mainFrame.mappings.protocol=Protocol
|
||||
mainFrame.mappings.remote_host=Remote Host
|
||||
mainFrame.mappings.external_port=External Port
|
||||
mainFrame.mappings.internal_client=Internal Client
|
||||
mainFrame.mappings.internal_port=Internal Port
|
||||
mainFrame.mappings.description=Description
|
||||
|
||||
mainFrame.port_mapping_presets.title=Port mapping presets
|
||||
|
||||
# Actions
|
||||
|
||||
mainFrame.showAboutDialog.Action.text=&About...
|
||||
mainFrame.showAboutDialog.Action.shortDescription=Show about dialog
|
||||
|
||||
mainFrame.router.updateAddresses.Action.text=&Update
|
||||
mainFrame.router.updateAddresses.Action.shortDescription=Update router addresses
|
||||
|
||||
mainFrame.router.info.Action.text=&Info
|
||||
mainFrame.router.info.Action.shortDescription=Display router information
|
||||
|
||||
mainFrame.router.connect.Action.text=&Connect
|
||||
mainFrame.router.connect.Action.shortDescription=Connect to router
|
||||
|
||||
mainFrame.router.disconnect.Action.text=&Disconnect
|
||||
mainFrame.router.disconnect.Action.shortDescription=Disconnect from router
|
||||
|
||||
mainFrame.router.copyInternalAddress.Action.text=Copy
|
||||
mainFrame.router.copyInternalAddress.Action.shortDescription=Copy internal address of router to clipboard
|
||||
|
||||
mainFrame.router.copyExternalAddress.Action.text=Copy
|
||||
mainFrame.router.copyExternalAddress.Action.shortDescription=Copy external address of router to clipboard
|
||||
|
||||
mainFrame.mappings.update.Action.text=Update
|
||||
mainFrame.mappings.update.Action.shortDescription=Update port mappings
|
||||
|
||||
mainFrame.mappings.remove.Action.text=&Remove
|
||||
mainFrame.mappings.remove.Action.shortDescription=Remove selected port mappings
|
||||
|
||||
mainFrame.preset_mappings.create.Action.text=Create
|
||||
mainFrame.preset_mappings.create.Action.shortDescription=Create a new port mapping preset
|
||||
|
||||
mainFrame.preset_mappings.edit.Action.text=Edit
|
||||
mainFrame.preset_mappings.edit.Action.shortDescription=Edit the selected port mapping preset
|
||||
|
||||
mainFrame.preset_mappings.remove.Action.text=Delete
|
||||
mainFrame.preset_mappings.remove.Action.shortDescription=Delete the selected port mapping preset
|
||||
|
||||
mainFrame.preset_mappings.use.Action.text=Use
|
||||
mainFrame.preset_mappings.use.Action.shortDescription=Use the selected port mapping preset
|
||||
|
||||
mainFrame.portmapper.settings.Action.text=PortMapper Settings...
|
||||
mainFrame.portmapper.settings.Action.shortDescription=Edit the settings of UPnP PortMapper
|
||||
|
||||
|
||||
# About dialog
|
||||
|
||||
about_dialog.close.Action.text=Close
|
||||
about_dialog.close.Action.shortDescription=Close about dialog
|
||||
|
||||
about_dialog.title=About ${Application.title} ${Application.version}
|
||||
|
||||
about_dialog.label1.text=${Application.title} Version ${Application.version}
|
||||
about_dialog.label2.text=Manage port mappings of a router using Universal Plug and Play.
|
||||
about_dialog.label3.text=Created by Christoph Pirkl
|
||||
about_dialog.label4.text=Using the following libraries
|
||||
|
||||
|
||||
about_dialog.tooltip.click_here=Click here to open URL
|
||||
about_dialog.tooltip.in_browser=in an external browser
|
||||
|
||||
about_dialog.upnplib_label.label=SBBI UPNPLib
|
||||
about_dialog.upnplib_label.url=https://sourceforge.net/projects/upnplibmobile/
|
||||
about_dialog.upnplib_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.upnplib_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.weupnp_label.label=weupnp
|
||||
about_dialog.weupnp_label.url=http://code.google.com/p/weupnp/
|
||||
about_dialog.weupnp_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.weupnp_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.cling_label.label=Cling
|
||||
about_dialog.cling_label.url=http://4thline.org/projects/cling/
|
||||
about_dialog.cling_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.cling_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.app_framework_label.label=Better Swing Application Framework
|
||||
about_dialog.app_framework_label.url=https://kenai.com/projects/bsaf/pages/Home
|
||||
about_dialog.app_framework_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.app_framework_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.slf4j_label.label=slf4j
|
||||
about_dialog.slf4j_label.url=http://www.slf4j.org/
|
||||
about_dialog.slf4j_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.slf4j_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.logback_label.label=logback
|
||||
about_dialog.logback_label.url=http://logback.qos.ch/
|
||||
about_dialog.logback_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.logback_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.miglayout_label.label=MiGLayout
|
||||
about_dialog.miglayout_label.url=http://www.miglayout.com/
|
||||
about_dialog.miglayout_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.miglayout_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.label5.text=Visit our homepage at
|
||||
|
||||
about_dialog.homepage_label.label=https://github.com/kaklakariada/portmapper
|
||||
about_dialog.homepage_label.url=https://github.com/kaklakariada/portmapper
|
||||
about_dialog.homepage_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.homepage_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
# Edit preset mapping dialog
|
||||
|
||||
preset_dialog.title=Edit Port Mapping Preset
|
||||
|
||||
preset_dialog.add_port.Action.text=Add
|
||||
preset_dialog.add_port.Action.shortDescription=Add a new port to the list
|
||||
|
||||
preset_dialog.add_port_range.Action.text=Add port range...
|
||||
preset_dialog.add_port_range.Action.shortDescription=Add a range of ports to the list
|
||||
|
||||
preset_dialog.remove_port.Action.text=Remove
|
||||
preset_dialog.remove_port.Action.shortDescription=Remove selected port from the list
|
||||
|
||||
preset_dialog.save.Action.text=Save
|
||||
preset_dialog.save.Action.shortDescription=Save the changed port mapping preset
|
||||
|
||||
preset_dialog.cancel.Action.text=Cancel
|
||||
preset_dialog.cancel.Action.shortDescription=Do not save the changed port mapping preset
|
||||
|
||||
preset_dialog.ports.title=Ports
|
||||
|
||||
preset_dialog.ports.protocol=Protocol
|
||||
preset_dialog.ports.internal=Internal Port
|
||||
preset_dialog.ports.external=External Port
|
||||
|
||||
preset_dialog.preset.text=Preset
|
||||
preset_dialog.protocol.text=Protocol
|
||||
preset_dialog.description.text=Description
|
||||
preset_dialog.protocol_tcp.text=TCP
|
||||
preset_dialog.protocol_udp.text=UDP
|
||||
preset_dialog.remote_host.text=Remote Host
|
||||
preset_dialog.remote_host_empty_for_all.text=(empty for all)
|
||||
preset_dialog.external_port.text=External Port
|
||||
preset_dialog.internal_client.text=Internal Client
|
||||
preset_dialog.internal_client_use_local_host.text=Use local host
|
||||
preset_dialog.internal_port.text=Internal Port
|
||||
|
||||
preset_dialog.error.title=Error
|
||||
preset_dialog.error.no_description=Please enter a description.
|
||||
preset_dialog.error.no_ports=Please add at least one port mapping.
|
||||
preset_dialog.error.duplicate_name=A preset with this already exists, please enter another description.
|
||||
|
||||
# Add port range dialog
|
||||
|
||||
add_port_range_dialog.title=Add port range
|
||||
|
||||
add_port_range_dialog.cancel.Action.text=Cancel
|
||||
add_port_range_dialog.cancel.Action.shortDescription=Do not add the port range
|
||||
|
||||
add_port_range_dialog.add.Action.text=Add
|
||||
add_port_range_dialog.add.Action.shortDescription=Add the port range to the list
|
||||
|
||||
add_port_range_dialog.protocol.text=Protocol
|
||||
add_port_range_dialog.internal_ports_from.text=Internal ports:
|
||||
add_port_range_dialog.internal_ports_to.text=to
|
||||
add_port_range_dialog.external_ports_from.text=External ports:
|
||||
add_port_range_dialog.external_ports_to.text=to
|
||||
|
||||
add_port_range_dialog.external_equal_internal.text=External ports are equal to internal ports
|
||||
add_port_range_dialog.invalid_number.title=Invalid port number
|
||||
add_port_range_dialog.invalid_number.message=Please enter numbers from 1 to 65535.
|
||||
|
||||
add_port_range_dialog.invalid_internal_range.title=Invalid internal port range
|
||||
add_port_range_dialog.invalid_internal_range.message=The 'to' internal port must be higher than the 'from' internal port.
|
||||
|
||||
add_port_range_dialog.invalid_external_range.title=Invalid external port range
|
||||
add_port_range_dialog.invalid_external_range.message=The 'to' external port must be higher than the 'from' external port.
|
||||
|
||||
add_port_range_dialog.invalid_range_length.title=Invalid range length
|
||||
add_port_range_dialog.invalid_range_length.message=The external port range must contain the same number of ports\nas the internal port range.
|
||||
|
||||
# Settings dialog
|
||||
|
||||
settings_dialog.title=UPnP PortMapper Settings
|
||||
|
||||
settings_dialog.save.Action.text=Save
|
||||
settings_dialog.save.Action.shortDescription=Save the settings
|
||||
|
||||
settings_dialog.cancel.Action.text=Cancel
|
||||
settings_dialog.cancel.Action.shortDescription=Do not save the settings
|
||||
|
||||
settings_dialog.use_entity_encoding.text=Use entity encoding for port mapping names
|
||||
|
||||
settings_dialog.log_level.text=Log level
|
||||
settings_dialog.upnp_lib.text=UPnP library
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
#
|
||||
# UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
# Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
#
|
||||
# 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 3 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/>.
|
||||
#
|
||||
|
||||
Application.id=PortMapper
|
||||
Application.title=PortMapper
|
||||
Application.version=@VERSION_NUMBER@
|
||||
|
||||
Application.lookAndFeel=system
|
||||
|
||||
mainFrame.title=${Application.title} ${Application.version}
|
||||
|
||||
messages.error_getting_localhost_address=Fant ikke adressen til den lokal verten.\nTrykk p<> "Legg til"-knappen for <20> opprette en oppf<70>ring\nog manuelt legge in adressen til den lokale verten.
|
||||
messages.error=Feil
|
||||
|
||||
mainFrame.router.title=Ruter
|
||||
mainFrame.router.not_connected=(ikke tilkoblet)
|
||||
mainFrame.router.updating=(oppdaterer)
|
||||
mainFrame.router.external_address=Ekstern adresse
|
||||
mainFrame.router.internal_address=Intern adresse
|
||||
mainFrame.log_messages.title=Loggf<EFBFBD>rte beskjeder
|
||||
mainFrame.port_mappings.title=Portoppf<EFBFBD>ringer
|
||||
|
||||
|
||||
mainFrame.mappings.protocol=Protokoll
|
||||
mainFrame.mappings.remote_host=Ekstern vert
|
||||
mainFrame.mappings.external_port=Ekstern port
|
||||
mainFrame.mappings.internal_client=Intern klient
|
||||
mainFrame.mappings.internal_port=Intern port
|
||||
mainFrame.mappings.description=Beskrivelse
|
||||
|
||||
mainFrame.port_mapping_presets.title=Portoppf<EFBFBD>ringsmaler
|
||||
|
||||
# Actions
|
||||
|
||||
mainFrame.showAboutDialog.Action.text=&Om...
|
||||
mainFrame.showAboutDialog.Action.shortDescription=Vis Om vinduet
|
||||
|
||||
mainFrame.router.updateAddresses.Action.text=&Oppdater
|
||||
mainFrame.router.updateAddresses.Action.shortDescription=Oppdater ruter adressen
|
||||
|
||||
mainFrame.router.info.Action.text=&Info
|
||||
mainFrame.router.info.Action.shortDescription=Vis ruter informasjon
|
||||
|
||||
mainFrame.router.connect.Action.text=&Koble til
|
||||
mainFrame.router.connect.Action.shortDescription=Koble til ruter
|
||||
|
||||
mainFrame.router.disconnect.Action.text=&Koble fra
|
||||
mainFrame.router.disconnect.Action.shortDescription=Koble fra ruter
|
||||
|
||||
mainFrame.router.copyInternalAddress.Action.text=Kopier
|
||||
mainFrame.router.copyInternalAddress.Action.shortDescription=Kopier ruterens interne adresse til utklippstavlen
|
||||
|
||||
mainFrame.router.copyExternalAddress.Action.text=Kopier
|
||||
mainFrame.router.copyExternalAddress.Action.shortDescription=Kopier ruterens Eksterne adresse til utklippstavlen
|
||||
|
||||
mainFrame.mappings.update.Action.text=Oppdater
|
||||
mainFrame.mappings.update.Action.shortDescription=Oppdater portoppf<70>ringer
|
||||
|
||||
mainFrame.mappings.remove.Action.text=&Fjern
|
||||
mainFrame.mappings.remove.Action.shortDescription=Fjern valgte portoppf<70>ringer
|
||||
|
||||
mainFrame.preset_mappings.create.Action.text=Opprett
|
||||
mainFrame.preset_mappings.create.Action.shortDescription=Opprett en ny portoppf<70>ringsmal
|
||||
|
||||
mainFrame.preset_mappings.edit.Action.text=Rediger
|
||||
mainFrame.preset_mappings.edit.Action.shortDescription=Rediger valgt portoppf<70>ringsmal
|
||||
|
||||
mainFrame.preset_mappings.remove.Action.text=Slett
|
||||
mainFrame.preset_mappings.remove.Action.shortDescription=Slett valgt portoppf<70>ringsmal
|
||||
|
||||
mainFrame.preset_mappings.use.Action.text=Bruk
|
||||
mainFrame.preset_mappings.use.Action.shortDescription=Bruk valgt portoppf<70>ringsmal
|
||||
|
||||
|
||||
# About dialog
|
||||
|
||||
about_dialog.close.Action.text=Lukk
|
||||
about_dialog.close.Action.shortDescription=Lukk Om vinduet
|
||||
|
||||
about_dialog.title=Om ${Application.title} ${Application.version}
|
||||
|
||||
about_dialog.label1.text=${Application.title} versjon ${Application.version}
|
||||
about_dialog.label2.text=Administer en ruters portoppf<70>ringer ved bruk av Universal Plug and Play
|
||||
about_dialog.label3.text=Utviklet av Christoph Pirkl
|
||||
about_dialog.label4.text=F<EFBFBD>lgene biblioteker er i bruk
|
||||
|
||||
|
||||
about_dialog.tooltip.click_here=Klikk her for <20> <20>pne adressen
|
||||
about_dialog.tooltip.in_browser=i nettleseren
|
||||
|
||||
about_dialog.upnplib_label.label=SBBI UPNPLib
|
||||
about_dialog.upnplib_label.url=https://sourceforge.net/projects/upnplibmobile/
|
||||
about_dialog.upnplib_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.upnplib_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.weupnp_label.label=weupnp
|
||||
about_dialog.weupnp_label.url=http://code.google.com/p/weupnp/
|
||||
about_dialog.weupnp_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.weupnp_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.cling_label.label=Cling
|
||||
about_dialog.cling_label.url=http://4thline.org/projects/cling/
|
||||
about_dialog.cling_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.cling_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.app_framework_label.label=Better Swing Application Framework
|
||||
about_dialog.app_framework_label.url=https://kenai.com/projects/bsaf/pages/Home
|
||||
about_dialog.app_framework_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.app_framework_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.slf4j_label.label=slf4j
|
||||
about_dialog.slf4j_label.url=http://www.slf4j.org/
|
||||
about_dialog.slf4j_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.slf4j_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.logback_label.label=logback
|
||||
about_dialog.logback_label.url=http://logback.qos.ch/
|
||||
about_dialog.logback_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.logback_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.miglayout_label.label=MiGLayout
|
||||
about_dialog.miglayout_label.url=http://www.miglayout.com/
|
||||
about_dialog.miglayout_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.miglayout_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
about_dialog.label5.text=Bes<EFBFBD>k v<>r hjemmeside p<>
|
||||
|
||||
about_dialog.homepage_label.label=https://github.com/kaklakariada/portmapper
|
||||
about_dialog.homepage_label.url=https://github.com/kaklakariada/portmapper
|
||||
about_dialog.homepage_label.toolTipText=${about_dialog.tooltip.click_here} ${about_dialog.homepage_label.url} ${about_dialog.tooltip.in_browser}
|
||||
|
||||
# Edit preset mapping dialog
|
||||
|
||||
|
||||
preset_dialog.title=Rediger portoppf<70>ringsmal
|
||||
|
||||
preset_dialog.add_port.Action.text=Legg til
|
||||
preset_dialog.add_port.Action.shortDescription=Legg til en ny port til listen
|
||||
|
||||
preset_dialog.remove_port.Action.text=Fjern
|
||||
preset_dialog.remove_port.Action.shortDescription=Fjern valgt port fra listen
|
||||
|
||||
|
||||
preset_dialog.save.Action.text=Lagre
|
||||
preset_dialog.save.Action.shortDescription=Lagre endringene i portoppf<70>ringsmalen
|
||||
|
||||
preset_dialog.cancel.Action.text=Avbryt
|
||||
preset_dialog.cancel.Action.shortDescription=Forkast forandringene gjort til portoppf<70>ringsmalen
|
||||
|
||||
preset_dialog.ports.title=Porter
|
||||
|
||||
preset_dialog.ports.protocol=Protokoll
|
||||
preset_dialog.ports.internal=Intern port
|
||||
preset_dialog.ports.external=Ekstern port
|
||||
|
||||
preset_dialog.preset.text=Mal
|
||||
preset_dialog.protocol.text=Protokoll
|
||||
preset_dialog.description.text=Beskrivelse
|
||||
preset_dialog.protocol_tcp.text=TCP
|
||||
preset_dialog.protocol_udp.text=UDP
|
||||
preset_dialog.remote_host.text=Ekstern vert
|
||||
preset_dialog.remote_host_empty_for_all.text=(la st<73> tom for alle)
|
||||
preset_dialog.external_port.text=Ekstern port
|
||||
preset_dialog.internal_client.text=Intern klient
|
||||
preset_dialog.internal_client_use_local_host.text=Bruk den lokale verten
|
||||
preset_dialog.internal_port.text=Intern port
|
||||
|
||||
|
||||
preset_dialog.error.title=Feil
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* UPnP PortMapper - A tool for managing port forwardings via UPnP
|
||||
* Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net>
|
||||
*
|
||||
* 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 3 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/>.
|
||||
*/
|
||||
package org.chris.portmapper.router.sbbi;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.chris.portmapper.model.PortMapping;
|
||||
import org.chris.portmapper.router.RouterException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import net.sbbi.upnp.impls.InternetGatewayDevice;
|
||||
import net.sbbi.upnp.messages.ActionResponse;
|
||||
import net.sbbi.upnp.messages.UPNPResponseException;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SBBIPortMappingExtractor}.
|
||||
*/
|
||||
public class TestPortMappingExtractor {
|
||||
|
||||
@Mock
|
||||
private InternetGatewayDevice routerMock;
|
||||
@Mock
|
||||
private Logger loggerMock;
|
||||
private SBBIPortMappingExtractor portMappingExtractor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
portMappingExtractor = new SBBIPortMappingExtractor(routerMock, 5, loggerMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allMappingsNull() throws RouterException, IOException, UPNPResponseException {
|
||||
simulateUPNPException(5, 713);
|
||||
assertEquals(0, portMappingExtractor.getPortMappings().size());
|
||||
verify(loggerMock, times(1)).warn(anyString(), anyInt());
|
||||
verify(loggerMock, never()).error(anyString());
|
||||
assertNumMappingsFound(0, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allMappingsNullMaxNumReached() throws RouterException {
|
||||
assertEquals(0, portMappingExtractor.getPortMappings().size());
|
||||
verify(loggerMock, times(1)).warn(anyString(), anyInt());
|
||||
verify(loggerMock, never()).error(anyString());
|
||||
assertNumMappingsFound(0, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noMapping() throws RouterException, IOException, UPNPResponseException {
|
||||
simulateUPNPException(0, 713);
|
||||
assertEquals(0, portMappingExtractor.getPortMappings().size());
|
||||
assertNoWarningOrErrorLogged();
|
||||
assertNumMappingsFound(0, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongErrorCode() throws RouterException, IOException, UPNPResponseException {
|
||||
simulateUPNPException(0, 42);
|
||||
assertEquals(0, portMappingExtractor.getPortMappings().size());
|
||||
verify(loggerMock, never()).warn(anyString());
|
||||
verify(loggerMock, never()).error(anyString());
|
||||
verify(loggerMock, never()).warn(anyString(), any(Throwable.class));
|
||||
verify(loggerMock).error(anyString(), any(Throwable.class));
|
||||
assertNumMappingsFound(0, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oneMapping() throws RouterException, IOException, UPNPResponseException {
|
||||
simulateMapping(0);
|
||||
simulateUPNPException(1, 713);
|
||||
assertEquals(1, portMappingExtractor.getPortMappings().size());
|
||||
assertNoWarningOrErrorLogged();
|
||||
assertNumMappingsFound(1, 0);
|
||||
}
|
||||
|
||||
private void assertNumMappingsFound(final int numFound, final int numNull) {
|
||||
verify(loggerMock).debug("Found {} mappings, {} mappings returned as null.", numFound, numNull);
|
||||
}
|
||||
|
||||
private void assertNoWarningOrErrorLogged() {
|
||||
verify(loggerMock, never()).warn(anyString());
|
||||
verify(loggerMock, never()).error(anyString());
|
||||
verify(loggerMock, never()).warn(anyString(), any(Throwable.class));
|
||||
verify(loggerMock, never()).error(anyString(), any(Throwable.class));
|
||||
}
|
||||
|
||||
private void simulateMapping(final int mappingEntry) throws IOException, UPNPResponseException {
|
||||
final ActionResponse response = mock(ActionResponse.class);
|
||||
when(response.getOutActionArgumentNames()).thenReturn(
|
||||
new HashSet<Object>(asList(PortMapping.MAPPING_ENTRY_ENABLED, PortMapping.MAPPING_ENTRY_EXTERNAL_PORT,
|
||||
PortMapping.MAPPING_ENTRY_INTERNAL_CLIENT, PortMapping.MAPPING_ENTRY_INTERNAL_PORT,
|
||||
PortMapping.MAPPING_ENTRY_LEASE_DURATION, PortMapping.MAPPING_ENTRY_PORT_MAPPING_DESCRIPTION,
|
||||
PortMapping.MAPPING_ENTRY_PROTOCOL, PortMapping.MAPPING_ENTRY_REMOTE_HOST)));
|
||||
when(response.getOutActionArgumentValue(PortMapping.MAPPING_ENTRY_ENABLED)).thenReturn("1");
|
||||
when(response.getOutActionArgumentValue(PortMapping.MAPPING_ENTRY_EXTERNAL_PORT)).thenReturn("2");
|
||||
when(response.getOutActionArgumentValue(PortMapping.MAPPING_ENTRY_INTERNAL_CLIENT)).thenReturn("internal");
|
||||
when(response.getOutActionArgumentValue(PortMapping.MAPPING_ENTRY_INTERNAL_PORT)).thenReturn("3");
|
||||
when(response.getOutActionArgumentValue(PortMapping.MAPPING_ENTRY_LEASE_DURATION)).thenReturn("4");
|
||||
when(response.getOutActionArgumentValue(PortMapping.MAPPING_ENTRY_PORT_MAPPING_DESCRIPTION))
|
||||
.thenReturn("description");
|
||||
when(response.getOutActionArgumentValue(PortMapping.MAPPING_ENTRY_PROTOCOL)).thenReturn("TCP");
|
||||
when(response.getOutActionArgumentValue(PortMapping.MAPPING_ENTRY_REMOTE_HOST)).thenReturn("remote");
|
||||
when(routerMock.getGenericPortMappingEntry(mappingEntry)).thenReturn(response);
|
||||
}
|
||||
|
||||
private void simulateUPNPException(final int mappingEntry, final int errorCode)
|
||||
throws IOException, UPNPResponseException {
|
||||
when(routerMock.getGenericPortMappingEntry(mappingEntry)).thenThrow(new UPNPResponseException(errorCode,
|
||||
"exception for entry " + mappingEntry + ", error code " + errorCode));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue