add in portmapper source

U P N P BABY
This commit is contained in:
Quacky 2017-08-07 17:43:21 -05:00
parent 11b452df03
commit 9cc824cb5d
61 changed files with 5757 additions and 0 deletions

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

2
UPnP/build.bat Normal file
View File

@ -0,0 +1,2 @@
./gradlew build
java -jar build/libs/portmapper-*.jar

92
UPnP/build.gradle Normal file
View File

@ -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)
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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/>.

BIN
UPnP/gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -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

172
UPnP/gradlew vendored Normal file
View File

@ -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" "$@"

84
UPnP/gradlew.bat vendored Normal file
View File

@ -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.

View File

@ -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;
}
}

View File

@ -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");
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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() + ")";
}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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.");
}
}

View File

@ -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()]);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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";
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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.");
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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('<', "&lt;");
knownEncodings.put('>', "&gt;");
knownEncodings.put('&', "&amp;");
}
/**
* 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();
}
}

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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));
}
}