Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Administrator
arthas-master
Commits
7c094a26
Commit
7c094a26
authored
Dec 18, 2023
by
liang.tang
Browse files
arthas-master
parents
Pipeline
#220
failed with stages
in 0 seconds
Changes
361
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
4793 additions
and
0 deletions
+4793
-0
boot/src/main/java/com/taobao/arthas/boot/ProcessUtils.java
boot/src/main/java/com/taobao/arthas/boot/ProcessUtils.java
+465
-0
boot/src/test/java/com/taobao/arthas/boot/DownloadUtilsTest.java
...c/test/java/com/taobao/arthas/boot/DownloadUtilsTest.java
+56
-0
client/pom.xml
client/pom.xml
+75
-0
client/src/main/java/com/taobao/arthas/client/IOUtil.java
client/src/main/java/com/taobao/arthas/client/IOUtil.java
+75
-0
client/src/main/java/com/taobao/arthas/client/TelnetConsole.java
...src/main/java/com/taobao/arthas/client/TelnetConsole.java
+453
-0
client/src/main/java/org/apache/commons/net/DatagramSocketClient.java
...ain/java/org/apache/commons/net/DatagramSocketClient.java
+316
-0
client/src/main/java/org/apache/commons/net/DatagramSocketFactory.java
...in/java/org/apache/commons/net/DatagramSocketFactory.java
+69
-0
client/src/main/java/org/apache/commons/net/DefaultDatagramSocketFactory.java
.../org/apache/commons/net/DefaultDatagramSocketFactory.java
+79
-0
client/src/main/java/org/apache/commons/net/DefaultSocketFactory.java
...ain/java/org/apache/commons/net/DefaultSocketFactory.java
+230
-0
client/src/main/java/org/apache/commons/net/MalformedServerReplyException.java
...org/apache/commons/net/MalformedServerReplyException.java
+56
-0
client/src/main/java/org/apache/commons/net/PrintCommandListener.java
...ain/java/org/apache/commons/net/PrintCommandListener.java
+200
-0
client/src/main/java/org/apache/commons/net/ProtocolCommandEvent.java
...ain/java/org/apache/commons/net/ProtocolCommandEvent.java
+148
-0
client/src/main/java/org/apache/commons/net/ProtocolCommandListener.java
.../java/org/apache/commons/net/ProtocolCommandListener.java
+58
-0
client/src/main/java/org/apache/commons/net/ProtocolCommandSupport.java
...n/java/org/apache/commons/net/ProtocolCommandSupport.java
+135
-0
client/src/main/java/org/apache/commons/net/SocketClient.java
...nt/src/main/java/org/apache/commons/net/SocketClient.java
+888
-0
client/src/main/java/org/apache/commons/net/telnet/EchoOptionHandler.java
...java/org/apache/commons/net/telnet/EchoOptionHandler.java
+52
-0
client/src/main/java/org/apache/commons/net/telnet/InvalidTelnetOptionException.java
...ache/commons/net/telnet/InvalidTelnetOptionException.java
+62
-0
client/src/main/java/org/apache/commons/net/telnet/SimpleOptionHandler.java
...va/org/apache/commons/net/telnet/SimpleOptionHandler.java
+59
-0
client/src/main/java/org/apache/commons/net/telnet/SuppressGAOptionHandler.java
...rg/apache/commons/net/telnet/SuppressGAOptionHandler.java
+52
-0
client/src/main/java/org/apache/commons/net/telnet/Telnet.java
...t/src/main/java/org/apache/commons/net/telnet/Telnet.java
+1265
-0
No files found.
Too many changes to show.
To preserve performance only
361 of 361+
files are displayed.
Plain diff
Email patch
boot/src/main/java/com/taobao/arthas/boot/ProcessUtils.java
0 → 100644
View file @
7c094a26
package
com.taobao.arthas.boot
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.PrintStream
;
import
java.lang.reflect.Method
;
import
java.net.URL
;
import
java.net.URLClassLoader
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.Iterator
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.Scanner
;
import
java.util.InputMismatchException
;
import
com.taobao.arthas.common.AnsiLog
;
import
com.taobao.arthas.common.ExecutingCommand
;
import
com.taobao.arthas.common.IOUtils
;
import
com.taobao.arthas.common.JavaVersionUtils
;
import
com.taobao.arthas.common.PidUtils
;
/**
*
* @author hengyunabc 2018-11-06
*
*/
public
class
ProcessUtils
{
private
static
String
FOUND_JAVA_HOME
=
null
;
//status code from com.taobao.arthas.client.TelnetConsole
/**
* Process success
*/
public
static
final
int
STATUS_OK
=
0
;
/**
* Generic error
*/
public
static
final
int
STATUS_ERROR
=
1
;
/**
* Execute commands timeout
*/
public
static
final
int
STATUS_EXEC_TIMEOUT
=
100
;
/**
* Execute commands error
*/
public
static
final
int
STATUS_EXEC_ERROR
=
101
;
@SuppressWarnings
(
"resource"
)
public
static
long
select
(
boolean
v
,
long
telnetPortPid
,
String
select
)
throws
InputMismatchException
{
Map
<
Long
,
String
>
processMap
=
listProcessByJps
(
v
);
// Put the port that is already listening at the first
if
(
telnetPortPid
>
0
&&
processMap
.
containsKey
(
telnetPortPid
))
{
String
telnetPortProcess
=
processMap
.
get
(
telnetPortPid
);
processMap
.
remove
(
telnetPortPid
);
Map
<
Long
,
String
>
newProcessMap
=
new
LinkedHashMap
<
Long
,
String
>();
newProcessMap
.
put
(
telnetPortPid
,
telnetPortProcess
);
newProcessMap
.
putAll
(
processMap
);
processMap
=
newProcessMap
;
}
if
(
processMap
.
isEmpty
())
{
AnsiLog
.
info
(
"Can not find java process. Try to run `jps` command lists the instrumented Java HotSpot VMs on the target system."
);
return
-
1
;
}
// select target process by the '--select' option when match only one process
if
(
select
!=
null
&&
!
select
.
trim
().
isEmpty
())
{
int
matchedSelectCount
=
0
;
Long
matchedPid
=
null
;
for
(
Entry
<
Long
,
String
>
entry
:
processMap
.
entrySet
())
{
if
(
entry
.
getValue
().
contains
(
select
))
{
matchedSelectCount
++;
matchedPid
=
entry
.
getKey
();
}
}
if
(
matchedSelectCount
==
1
)
{
return
matchedPid
;
}
}
AnsiLog
.
info
(
"Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER."
);
// print list
int
count
=
1
;
for
(
String
process
:
processMap
.
values
())
{
if
(
count
==
1
)
{
System
.
out
.
println
(
"* ["
+
count
+
"]: "
+
process
);
}
else
{
System
.
out
.
println
(
" ["
+
count
+
"]: "
+
process
);
}
count
++;
}
// read choice
String
line
=
new
Scanner
(
System
.
in
).
nextLine
();
if
(
line
.
trim
().
isEmpty
())
{
// get the first process id
return
processMap
.
keySet
().
iterator
().
next
();
}
int
choice
=
new
Scanner
(
line
).
nextInt
();
if
(
choice
<=
0
||
choice
>
processMap
.
size
())
{
return
-
1
;
}
Iterator
<
Long
>
idIter
=
processMap
.
keySet
().
iterator
();
for
(
int
i
=
1
;
i
<=
choice
;
++
i
)
{
if
(
i
==
choice
)
{
return
idIter
.
next
();
}
idIter
.
next
();
}
return
-
1
;
}
private
static
Map
<
Long
,
String
>
listProcessByJps
(
boolean
v
)
{
Map
<
Long
,
String
>
result
=
new
LinkedHashMap
<
Long
,
String
>();
String
jps
=
"jps"
;
File
jpsFile
=
findJps
();
if
(
jpsFile
!=
null
)
{
jps
=
jpsFile
.
getAbsolutePath
();
}
AnsiLog
.
debug
(
"Try use jps to lis java process, jps: "
+
jps
);
String
[]
command
=
null
;
if
(
v
)
{
command
=
new
String
[]
{
jps
,
"-v"
,
"-l"
};
}
else
{
command
=
new
String
[]
{
jps
,
"-l"
};
}
List
<
String
>
lines
=
ExecutingCommand
.
runNative
(
command
);
AnsiLog
.
debug
(
"jps result: "
+
lines
);
long
currentPid
=
Long
.
parseLong
(
PidUtils
.
currentPid
());
for
(
String
line
:
lines
)
{
String
[]
strings
=
line
.
trim
().
split
(
"\\s+"
);
if
(
strings
.
length
<
1
)
{
continue
;
}
try
{
long
pid
=
Long
.
parseLong
(
strings
[
0
]);
if
(
pid
==
currentPid
)
{
continue
;
}
if
(
strings
.
length
>=
2
&&
isJpsProcess
(
strings
[
1
]))
{
// skip jps
continue
;
}
result
.
put
(
pid
,
line
);
}
catch
(
Throwable
e
)
{
// https://github.com/alibaba/arthas/issues/970
// ignore
}
}
return
result
;
}
/**
* <pre>
* 1. Try to find java home from System Property java.home
* 2. If jdk > 8, FOUND_JAVA_HOME set to java.home
* 3. If jdk <= 8, try to find tools.jar under java.home
* 4. If tools.jar do not exists under java.home, try to find System env JAVA_HOME
* 5. If jdk <= 8 and tools.jar do not exists under JAVA_HOME, throw IllegalArgumentException
* </pre>
*
* @return
*/
public
static
String
findJavaHome
()
{
if
(
FOUND_JAVA_HOME
!=
null
)
{
return
FOUND_JAVA_HOME
;
}
String
javaHome
=
System
.
getProperty
(
"java.home"
);
if
(
JavaVersionUtils
.
isLessThanJava9
())
{
File
toolsJar
=
new
File
(
javaHome
,
"lib/tools.jar"
);
if
(!
toolsJar
.
exists
())
{
toolsJar
=
new
File
(
javaHome
,
"../lib/tools.jar"
);
}
if
(!
toolsJar
.
exists
())
{
// maybe jre
toolsJar
=
new
File
(
javaHome
,
"../../lib/tools.jar"
);
}
if
(
toolsJar
.
exists
())
{
FOUND_JAVA_HOME
=
javaHome
;
return
FOUND_JAVA_HOME
;
}
if
(!
toolsJar
.
exists
())
{
AnsiLog
.
debug
(
"Can not find tools.jar under java.home: "
+
javaHome
);
String
javaHomeEnv
=
System
.
getenv
(
"JAVA_HOME"
);
if
(
javaHomeEnv
!=
null
&&
!
javaHomeEnv
.
isEmpty
())
{
AnsiLog
.
debug
(
"Try to find tools.jar in System Env JAVA_HOME: "
+
javaHomeEnv
);
// $JAVA_HOME/lib/tools.jar
toolsJar
=
new
File
(
javaHomeEnv
,
"lib/tools.jar"
);
if
(!
toolsJar
.
exists
())
{
// maybe jre
toolsJar
=
new
File
(
javaHomeEnv
,
"../lib/tools.jar"
);
}
}
if
(
toolsJar
.
exists
())
{
AnsiLog
.
info
(
"Found java home from System Env JAVA_HOME: "
+
javaHomeEnv
);
FOUND_JAVA_HOME
=
javaHomeEnv
;
return
FOUND_JAVA_HOME
;
}
throw
new
IllegalArgumentException
(
"Can not find tools.jar under java home: "
+
javaHome
+
", please try to start arthas-boot with full path java. Such as /opt/jdk/bin/java -jar arthas-boot.jar"
);
}
}
else
{
FOUND_JAVA_HOME
=
javaHome
;
}
return
FOUND_JAVA_HOME
;
}
public
static
void
startArthasCore
(
long
targetPid
,
List
<
String
>
attachArgs
)
{
// find java/java.exe, then try to find tools.jar
String
javaHome
=
findJavaHome
();
// find java/java.exe
File
javaPath
=
findJava
(
javaHome
);
if
(
javaPath
==
null
)
{
throw
new
IllegalArgumentException
(
"Can not find java/java.exe executable file under java home: "
+
javaHome
);
}
File
toolsJar
=
findToolsJar
(
javaHome
);
if
(
JavaVersionUtils
.
isLessThanJava9
())
{
if
(
toolsJar
==
null
||
!
toolsJar
.
exists
())
{
throw
new
IllegalArgumentException
(
"Can not find tools.jar under java home: "
+
javaHome
);
}
}
List
<
String
>
command
=
new
ArrayList
<
String
>();
command
.
add
(
javaPath
.
getAbsolutePath
());
if
(
toolsJar
!=
null
&&
toolsJar
.
exists
())
{
command
.
add
(
"-Xbootclasspath/a:"
+
toolsJar
.
getAbsolutePath
());
}
command
.
addAll
(
attachArgs
);
// "${JAVA_HOME}"/bin/java \
// ${opts} \
// -jar "${arthas_lib_dir}/arthas-core.jar" \
// -pid ${TARGET_PID} \
// -target-ip ${TARGET_IP} \
// -telnet-port ${TELNET_PORT} \
// -http-port ${HTTP_PORT} \
// -core "${arthas_lib_dir}/arthas-core.jar" \
// -agent "${arthas_lib_dir}/arthas-agent.jar"
ProcessBuilder
pb
=
new
ProcessBuilder
(
command
);
try
{
final
Process
proc
=
pb
.
start
();
Thread
redirectStdout
=
new
Thread
(
new
Runnable
()
{
@Override
public
void
run
()
{
InputStream
inputStream
=
proc
.
getInputStream
();
try
{
IOUtils
.
copy
(
inputStream
,
System
.
out
);
}
catch
(
IOException
e
)
{
IOUtils
.
close
(
inputStream
);
}
}
});
Thread
redirectStderr
=
new
Thread
(
new
Runnable
()
{
@Override
public
void
run
()
{
InputStream
inputStream
=
proc
.
getErrorStream
();
try
{
IOUtils
.
copy
(
inputStream
,
System
.
err
);
}
catch
(
IOException
e
)
{
IOUtils
.
close
(
inputStream
);
}
}
});
redirectStdout
.
start
();
redirectStderr
.
start
();
redirectStdout
.
join
();
redirectStderr
.
join
();
int
exitValue
=
proc
.
exitValue
();
if
(
exitValue
!=
0
)
{
AnsiLog
.
error
(
"attach fail, targetPid: "
+
targetPid
);
System
.
exit
(
1
);
}
}
catch
(
Throwable
e
)
{
// ignore
}
}
public
static
int
startArthasClient
(
String
arthasHomeDir
,
List
<
String
>
telnetArgs
,
OutputStream
out
)
throws
Throwable
{
// start java telnet client
// find arthas-client.jar
URLClassLoader
classLoader
=
new
URLClassLoader
(
new
URL
[]{
new
File
(
arthasHomeDir
,
"arthas-client.jar"
).
toURI
().
toURL
()});
Class
<?>
telnetConsoleClass
=
classLoader
.
loadClass
(
"com.taobao.arthas.client.TelnetConsole"
);
Method
processMethod
=
telnetConsoleClass
.
getMethod
(
"process"
,
String
[].
class
);
//redirect System.out/System.err
PrintStream
originSysOut
=
System
.
out
;
PrintStream
originSysErr
=
System
.
err
;
PrintStream
newOut
=
new
PrintStream
(
out
);
PrintStream
newErr
=
new
PrintStream
(
out
);
// call TelnetConsole.process()
// fix https://github.com/alibaba/arthas/issues/833
ClassLoader
tccl
=
Thread
.
currentThread
().
getContextClassLoader
();
try
{
System
.
setOut
(
newOut
);
System
.
setErr
(
newErr
);
Thread
.
currentThread
().
setContextClassLoader
(
classLoader
);
return
(
Integer
)
processMethod
.
invoke
(
null
,
new
Object
[]{
telnetArgs
.
toArray
(
new
String
[
0
])});
}
catch
(
Throwable
e
)
{
//java.lang.reflect.InvocationTargetException : java.net.ConnectException
e
=
e
.
getCause
();
if
(
e
instanceof
IOException
||
e
instanceof
InterruptedException
)
{
// ignore connection error and interrupted error
return
STATUS_ERROR
;
}
else
{
// process error
AnsiLog
.
error
(
"process error: {}"
,
e
.
toString
());
AnsiLog
.
error
(
e
);
return
STATUS_EXEC_ERROR
;
}
}
finally
{
Thread
.
currentThread
().
setContextClassLoader
(
tccl
);
//reset System.out/System.err
System
.
setOut
(
originSysOut
);
System
.
setErr
(
originSysErr
);
//flush output
newOut
.
flush
();
newErr
.
flush
();
}
}
private
static
File
findJava
(
String
javaHome
)
{
String
[]
paths
=
{
"bin/java"
,
"bin/java.exe"
,
"../bin/java"
,
"../bin/java.exe"
};
List
<
File
>
javaList
=
new
ArrayList
<
File
>();
for
(
String
path
:
paths
)
{
File
javaFile
=
new
File
(
javaHome
,
path
);
if
(
javaFile
.
exists
())
{
AnsiLog
.
debug
(
"Found java: "
+
javaFile
.
getAbsolutePath
());
javaList
.
add
(
javaFile
);
}
}
if
(
javaList
.
isEmpty
())
{
AnsiLog
.
debug
(
"Can not find java/java.exe under current java home: "
+
javaHome
);
return
null
;
}
// find the shortest path, jre path longer than jdk path
if
(
javaList
.
size
()
>
1
)
{
Collections
.
sort
(
javaList
,
new
Comparator
<
File
>()
{
@Override
public
int
compare
(
File
file1
,
File
file2
)
{
try
{
return
file1
.
getCanonicalPath
().
length
()
-
file2
.
getCanonicalPath
().
length
();
}
catch
(
IOException
e
)
{
// ignore
}
return
-
1
;
}
});
}
return
javaList
.
get
(
0
);
}
private
static
File
findToolsJar
(
String
javaHome
)
{
if
(
JavaVersionUtils
.
isGreaterThanJava8
())
{
return
null
;
}
File
toolsJar
=
new
File
(
javaHome
,
"lib/tools.jar"
);
if
(!
toolsJar
.
exists
())
{
toolsJar
=
new
File
(
javaHome
,
"../lib/tools.jar"
);
}
if
(!
toolsJar
.
exists
())
{
// maybe jre
toolsJar
=
new
File
(
javaHome
,
"../../lib/tools.jar"
);
}
if
(!
toolsJar
.
exists
())
{
throw
new
IllegalArgumentException
(
"Can not find tools.jar under java home: "
+
javaHome
);
}
AnsiLog
.
debug
(
"Found tools.jar: "
+
toolsJar
.
getAbsolutePath
());
return
toolsJar
;
}
private
static
File
findJps
()
{
// Try to find jps under java.home and System env JAVA_HOME
String
javaHome
=
System
.
getProperty
(
"java.home"
);
String
[]
paths
=
{
"bin/jps"
,
"bin/jps.exe"
,
"../bin/jps"
,
"../bin/jps.exe"
};
List
<
File
>
jpsList
=
new
ArrayList
<
File
>();
for
(
String
path
:
paths
)
{
File
jpsFile
=
new
File
(
javaHome
,
path
);
if
(
jpsFile
.
exists
())
{
AnsiLog
.
debug
(
"Found jps: "
+
jpsFile
.
getAbsolutePath
());
jpsList
.
add
(
jpsFile
);
}
}
if
(
jpsList
.
isEmpty
())
{
AnsiLog
.
debug
(
"Can not find jps under :"
+
javaHome
);
String
javaHomeEnv
=
System
.
getenv
(
"JAVA_HOME"
);
AnsiLog
.
debug
(
"Try to find jps under env JAVA_HOME :"
+
javaHomeEnv
);
for
(
String
path
:
paths
)
{
File
jpsFile
=
new
File
(
javaHomeEnv
,
path
);
if
(
jpsFile
.
exists
())
{
AnsiLog
.
debug
(
"Found jps: "
+
jpsFile
.
getAbsolutePath
());
jpsList
.
add
(
jpsFile
);
}
}
}
if
(
jpsList
.
isEmpty
())
{
AnsiLog
.
debug
(
"Can not find jps under current java home: "
+
javaHome
);
return
null
;
}
// find the shortest path, jre path longer than jdk path
if
(
jpsList
.
size
()
>
1
)
{
Collections
.
sort
(
jpsList
,
new
Comparator
<
File
>()
{
@Override
public
int
compare
(
File
file1
,
File
file2
)
{
try
{
return
file1
.
getCanonicalPath
().
length
()
-
file2
.
getCanonicalPath
().
length
();
}
catch
(
IOException
e
)
{
// ignore
}
return
-
1
;
}
});
}
return
jpsList
.
get
(
0
);
}
private
static
boolean
isJpsProcess
(
String
mainClassName
)
{
return
"sun.tools.jps.Jps"
.
equals
(
mainClassName
)
||
"jdk.jcmd/sun.tools.jps.Jps"
.
equals
(
mainClassName
);
}
}
boot/src/test/java/com/taobao/arthas/boot/DownloadUtilsTest.java
0 → 100644
View file @
7c094a26
package
com.taobao.arthas.boot
;
import
java.io.File
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.TimeZone
;
import
java.util.concurrent.TimeUnit
;
import
org.junit.Assert
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.rules.TemporaryFolder
;
public
class
DownloadUtilsTest
{
@Rule
public
TemporaryFolder
rootFolder
=
new
TemporaryFolder
();
@Test
public
void
testReadReleaseVersion
()
{
String
releaseVersion
=
DownloadUtils
.
readLatestReleaseVersion
();
Assert
.
assertNotNull
(
releaseVersion
);
Assert
.
assertNotEquals
(
"releaseVersion is empty"
,
""
,
releaseVersion
.
trim
());
System
.
err
.
println
(
releaseVersion
);
}
@Test
public
void
testReadAllVersions
()
{
List
<
String
>
versions
=
DownloadUtils
.
readRemoteVersions
();
Assert
.
assertEquals
(
""
,
true
,
versions
.
contains
(
"3.1.7"
));
}
@Test
public
void
testAliyunDownload
()
throws
IOException
{
// fix travis-ci failed problem
if
(
TimeUnit
.
MILLISECONDS
.
toHours
(
TimeZone
.
getDefault
().
getOffset
(
System
.
currentTimeMillis
()))
==
8
)
{
String
version
=
"3.3.7"
;
File
folder
=
rootFolder
.
newFolder
();
System
.
err
.
println
(
folder
.
getAbsolutePath
());
DownloadUtils
.
downArthasPackaging
(
"aliyun"
,
false
,
version
,
folder
.
getAbsolutePath
());
File
as
=
new
File
(
folder
,
version
+
File
.
separator
+
"arthas"
+
File
.
separator
+
"as.sh"
);
Assert
.
assertTrue
(
as
.
exists
());
}
}
@Test
public
void
testCenterDownload
()
throws
IOException
{
String
version
=
"3.1.7"
;
File
folder
=
rootFolder
.
newFolder
();
System
.
err
.
println
(
folder
.
getAbsolutePath
());
DownloadUtils
.
downArthasPackaging
(
"center"
,
false
,
version
,
folder
.
getAbsolutePath
());
File
as
=
new
File
(
folder
,
version
+
File
.
separator
+
"arthas"
+
File
.
separator
+
"as.sh"
);
Assert
.
assertTrue
(
as
.
exists
());
}
}
client/pom.xml
0 → 100644
View file @
7c094a26
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<parent>
<artifactId>
arthas-all
</artifactId>
<groupId>
com.taobao.arthas
</groupId>
<version>
${revision}
</version>
<relativePath>
../pom.xml
</relativePath>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<artifactId>
arthas-client
</artifactId>
<name>
arthas-client
</name>
<build>
<finalName>
arthas-client
</finalName>
<plugins>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-compiler-plugin
</artifactId>
<configuration>
<source>
1.6
</source>
<target>
1.6
</target>
<encoding>
UTF-8
</encoding>
<showDeprecation>
true
</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-assembly-plugin
</artifactId>
<executions>
<execution>
<goals>
<goal>
single
</goal>
</goals>
<phase>
package
</phase>
<configuration>
<descriptorRefs>
<descriptorRef>
jar-with-dependencies
</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>
com.taobao.arthas.client.TelnetConsole
</mainClass>
</manifest>
<manifestEntries>
<Created-By>
core engine team, middleware group, alibaba inc.
</Created-By>
<Specification-Title>
${project.name}
</Specification-Title>
<Specification-Version>
${project.version}
</Specification-Version>
<Implementation-Title>
${project.name}
</Implementation-Title>
<Implementation-Version>
${project.version}
</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>
com.taobao.arthas
</groupId>
<artifactId>
arthas-common
</artifactId>
<version>
${project.version}
</version>
</dependency>
<dependency>
<groupId>
com.alibaba.middleware
</groupId>
<artifactId>
cli
</artifactId>
</dependency>
<dependency>
<groupId>
jline
</groupId>
<artifactId>
jline
</artifactId>
</dependency>
</dependencies>
</project>
client/src/main/java/com/taobao/arthas/client/IOUtil.java
0 → 100644
View file @
7c094a26
package
com.taobao.arthas.client
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.io.OutputStream
;
import
java.io.Writer
;
/***
* This is a utility class providing a reader/writer capability required by the
* weatherTelnet, rexec, rshell, and rlogin example programs. The only point of
* the class is to hold the static method readWrite which spawns a reader thread
* and a writer thread. The reader thread reads from a local input source
* (presumably stdin) and writes the data to a remote output destination. The
* writer thread reads from a remote input source and writes to a local output
* destination. The threads terminate when the remote input source closes.
***/
public
final
class
IOUtil
{
public
static
final
void
readWrite
(
final
InputStream
remoteInput
,
final
OutputStream
remoteOutput
,
final
InputStream
localInput
,
final
Writer
localOutput
)
{
Thread
reader
,
writer
;
reader
=
new
Thread
()
{
@Override
public
void
run
()
{
int
ch
;
try
{
while
(!
interrupted
()
&&
(
ch
=
localInput
.
read
())
!=
-
1
)
{
remoteOutput
.
write
(
ch
);
remoteOutput
.
flush
();
}
}
catch
(
IOException
e
)
{
// e.printStackTrace();
}
}
};
writer
=
new
Thread
()
{
@Override
public
void
run
()
{
try
{
InputStreamReader
reader
=
new
InputStreamReader
(
remoteInput
);
while
(
true
)
{
int
singleChar
=
reader
.
read
();
if
(
singleChar
==
-
1
)
{
break
;
}
localOutput
.
write
(
singleChar
);
localOutput
.
flush
();
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
};
writer
.
setPriority
(
Thread
.
currentThread
().
getPriority
()
+
1
);
writer
.
start
();
reader
.
setDaemon
(
true
);
reader
.
start
();
try
{
writer
.
join
();
reader
.
interrupt
();
}
catch
(
InterruptedException
e
)
{
// Ignored
}
}
}
\ No newline at end of file
client/src/main/java/com/taobao/arthas/client/TelnetConsole.java
0 → 100644
View file @
7c094a26
package
com.taobao.arthas.client
;
import
java.awt.event.ActionEvent
;
import
java.awt.event.ActionListener
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.FileReader
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.io.OutputStream
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.concurrent.BlockingQueue
;
import
java.util.concurrent.LinkedBlockingQueue
;
import
java.util.concurrent.TimeUnit
;
import
org.apache.commons.net.telnet.InvalidTelnetOptionException
;
import
org.apache.commons.net.telnet.TelnetClient
;
import
org.apache.commons.net.telnet.TelnetOptionHandler
;
import
org.apache.commons.net.telnet.WindowSizeOptionHandler
;
import
com.taobao.arthas.common.OSUtils
;
import
com.taobao.arthas.common.UsageRender
;
import
com.taobao.middleware.cli.CLI
;
import
com.taobao.middleware.cli.CommandLine
;
import
com.taobao.middleware.cli.UsageMessageFormatter
;
import
com.taobao.middleware.cli.annotations.Argument
;
import
com.taobao.middleware.cli.annotations.CLIConfigurator
;
import
com.taobao.middleware.cli.annotations.Description
;
import
com.taobao.middleware.cli.annotations.Name
;
import
com.taobao.middleware.cli.annotations.Option
;
import
com.taobao.middleware.cli.annotations.Summary
;
import
jline.Terminal
;
import
jline.TerminalSupport
;
import
jline.UnixTerminal
;
import
jline.console.ConsoleReader
;
import
jline.console.KeyMap
;
/**
* @author ralf0131 2016-12-29 11:55.
* @author hengyunabc 2018-11-01
*/
@Name
(
"arthas-client"
)
@Summary
(
"Arthas Telnet Client"
)
@Description
(
"EXAMPLES:\n"
+
" java -jar arthas-client.jar 127.0.0.1 3658\n"
+
" java -jar arthas-client.jar -c 'dashboard -n 1' \n"
+
" java -jar arthas-client.jar -f batch.as 127.0.0.1\n"
)
public
class
TelnetConsole
{
private
static
final
String
PROMPT
=
"[arthas@"
;
// [arthas@49603]$
private
static
final
int
DEFAULT_CONNECTION_TIMEOUT
=
5000
;
// 5000 ms
private
static
final
byte
CTRL_C
=
0x03
;
// ------- Status codes ------- //
/**
* Process success
*/
public
static
final
int
STATUS_OK
=
0
;
/**
* Generic error
*/
public
static
final
int
STATUS_ERROR
=
1
;
/**
* Execute commands timeout
*/
public
static
final
int
STATUS_EXEC_TIMEOUT
=
100
;
/**
* Execute commands error
*/
public
static
final
int
STATUS_EXEC_ERROR
=
101
;
private
boolean
help
=
false
;
private
String
targetIp
=
"127.0.0.1"
;
private
int
port
=
3658
;
private
String
command
;
private
String
batchFile
;
private
int
executionTimeout
=
-
1
;
private
Integer
width
=
null
;
private
Integer
height
=
null
;
@Argument
(
argName
=
"target-ip"
,
index
=
0
,
required
=
false
)
@Description
(
"Target ip"
)
public
void
setTargetIp
(
String
targetIp
)
{
this
.
targetIp
=
targetIp
;
}
@Argument
(
argName
=
"port"
,
index
=
1
,
required
=
false
)
@Description
(
"The remote server port"
)
public
void
setPort
(
int
port
)
{
this
.
port
=
port
;
}
@Option
(
longName
=
"help"
,
flag
=
true
)
@Description
(
"Print usage"
)
public
void
setHelp
(
boolean
help
)
{
this
.
help
=
help
;
}
@Option
(
shortName
=
"c"
,
longName
=
"command"
)
@Description
(
"Command to execute, multiple commands separated by ;"
)
public
void
setCommand
(
String
command
)
{
this
.
command
=
command
;
}
@Option
(
shortName
=
"f"
,
longName
=
"batch-file"
)
@Description
(
"The batch file to execute"
)
public
void
setBatchFile
(
String
batchFile
)
{
this
.
batchFile
=
batchFile
;
}
@Option
(
shortName
=
"t"
,
longName
=
"execution-timeout"
)
@Description
(
"The timeout (ms) of execute commands or batch file "
)
public
void
setExecutionTimeout
(
int
executionTimeout
)
{
this
.
executionTimeout
=
executionTimeout
;
}
@Option
(
shortName
=
"w"
,
longName
=
"width"
)
@Description
(
"The terminal width"
)
public
void
setWidth
(
int
width
)
{
this
.
width
=
width
;
}
@Option
(
shortName
=
"h"
,
longName
=
"height"
)
@Description
(
"The terminal height"
)
public
void
setheight
(
int
height
)
{
this
.
height
=
height
;
}
public
TelnetConsole
()
{
}
private
static
List
<
String
>
readLines
(
File
batchFile
)
{
List
<
String
>
list
=
new
ArrayList
<
String
>();
BufferedReader
br
=
null
;
try
{
br
=
new
BufferedReader
(
new
FileReader
(
batchFile
));
String
line
=
br
.
readLine
();
while
(
line
!=
null
)
{
list
.
add
(
line
);
line
=
br
.
readLine
();
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
finally
{
if
(
br
!=
null
)
{
try
{
br
.
close
();
}
catch
(
IOException
e
)
{
// ignore
}
}
}
return
list
;
}
public
static
void
main
(
String
[]
args
)
throws
Exception
{
try
{
int
status
=
process
(
args
,
new
ActionListener
()
{
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
System
.
exit
(
STATUS_OK
);
}
});
System
.
exit
(
status
);
}
catch
(
Throwable
e
)
{
e
.
printStackTrace
();
CLI
cli
=
CLIConfigurator
.
define
(
TelnetConsole
.
class
);
System
.
out
.
println
(
usage
(
cli
));
System
.
exit
(
STATUS_ERROR
);
}
}
/**
* 提供给arthas-boot使用的主处理函数
*
* @param args
* @return status code
* @throws IOException
* @throws InterruptedException
*/
public
static
int
process
(
String
[]
args
)
throws
IOException
,
InterruptedException
{
return
process
(
args
,
null
);
}
/**
* arthas client 主函数
* 注意: process()函数提供给arthas-boot使用,内部不能调用System.exit()结束进程的方法
*
* @param args
* @param eotEventCallback Ctrl+D signals an End of Transmission (EOT) event
* @return status code
* @throws IOException
*/
public
static
int
process
(
String
[]
args
,
ActionListener
eotEventCallback
)
throws
IOException
{
// support mingw/cygw jline color
if
(
OSUtils
.
isCygwinOrMinGW
())
{
System
.
setProperty
(
"jline.terminal"
,
System
.
getProperty
(
"jline.terminal"
,
"jline.UnixTerminal"
));
}
TelnetConsole
telnetConsole
=
new
TelnetConsole
();
CLI
cli
=
CLIConfigurator
.
define
(
TelnetConsole
.
class
);
CommandLine
commandLine
=
cli
.
parse
(
Arrays
.
asList
(
args
));
CLIConfigurator
.
inject
(
commandLine
,
telnetConsole
);
if
(
telnetConsole
.
isHelp
())
{
System
.
out
.
println
(
usage
(
cli
));
return
STATUS_ERROR
;
}
// Try to read cmds
List
<
String
>
cmds
=
new
ArrayList
<
String
>();
if
(
telnetConsole
.
getCommand
()
!=
null
)
{
for
(
String
c
:
telnetConsole
.
getCommand
().
split
(
";"
))
{
cmds
.
add
(
c
.
trim
());
}
}
else
if
(
telnetConsole
.
getBatchFile
()
!=
null
)
{
File
file
=
new
File
(
telnetConsole
.
getBatchFile
());
if
(!
file
.
exists
())
{
throw
new
IllegalArgumentException
(
"batch file do not exist: "
+
telnetConsole
.
getBatchFile
());
}
else
{
cmds
.
addAll
(
readLines
(
file
));
}
}
final
ConsoleReader
consoleReader
=
new
ConsoleReader
(
System
.
in
,
System
.
out
);
consoleReader
.
setHandleUserInterrupt
(
true
);
Terminal
terminal
=
consoleReader
.
getTerminal
();
// support catch ctrl+c event
terminal
.
disableInterruptCharacter
();
if
(
terminal
instanceof
UnixTerminal
)
{
((
UnixTerminal
)
terminal
).
disableLitteralNextCharacter
();
}
try
{
int
width
=
TerminalSupport
.
DEFAULT_WIDTH
;
int
height
=
TerminalSupport
.
DEFAULT_HEIGHT
;
if
(!
cmds
.
isEmpty
())
{
// batch mode
if
(
telnetConsole
.
getWidth
()
!=
null
)
{
width
=
telnetConsole
.
getWidth
();
}
if
(
telnetConsole
.
getheight
()
!=
null
)
{
height
=
telnetConsole
.
getheight
();
}
}
else
{
// normal telnet client, get current terminal size
if
(
telnetConsole
.
getWidth
()
!=
null
)
{
width
=
telnetConsole
.
getWidth
();
}
else
{
width
=
terminal
.
getWidth
();
// hack for windows dos
if
(
OSUtils
.
isWindows
())
{
width
--;
}
}
if
(
telnetConsole
.
getheight
()
!=
null
)
{
height
=
telnetConsole
.
getheight
();
}
else
{
height
=
terminal
.
getHeight
();
}
}
final
TelnetClient
telnet
=
new
TelnetClient
();
telnet
.
setConnectTimeout
(
DEFAULT_CONNECTION_TIMEOUT
);
// send init terminal size
TelnetOptionHandler
sizeOpt
=
new
WindowSizeOptionHandler
(
width
,
height
,
true
,
true
,
false
,
false
);
try
{
telnet
.
addOptionHandler
(
sizeOpt
);
}
catch
(
InvalidTelnetOptionException
e
)
{
// ignore
}
// ctrl + c event callback
consoleReader
.
getKeys
().
bind
(
Character
.
toString
((
char
)
CTRL_C
),
new
ActionListener
()
{
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
try
{
consoleReader
.
getCursorBuffer
().
clear
();
// clear current line
telnet
.
getOutputStream
().
write
(
CTRL_C
);
telnet
.
getOutputStream
().
flush
();
}
catch
(
Exception
e1
)
{
e1
.
printStackTrace
();
}
}
});
// ctrl + d event call back
consoleReader
.
getKeys
().
bind
(
Character
.
toString
(
KeyMap
.
CTRL_D
),
eotEventCallback
);
try
{
telnet
.
connect
(
telnetConsole
.
getTargetIp
(),
telnetConsole
.
getPort
());
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
"Connect to telnet server error: "
+
telnetConsole
.
getTargetIp
()
+
" "
+
telnetConsole
.
getPort
());
throw
e
;
}
if
(
cmds
.
isEmpty
())
{
IOUtil
.
readWrite
(
telnet
.
getInputStream
(),
telnet
.
getOutputStream
(),
consoleReader
.
getInput
(),
consoleReader
.
getOutput
());
}
else
{
try
{
return
batchModeRun
(
telnet
,
cmds
,
telnetConsole
.
getExecutionTimeout
());
}
catch
(
Throwable
e
)
{
System
.
out
.
println
(
"Execute commands error: "
+
e
.
getMessage
());
e
.
printStackTrace
();
return
STATUS_EXEC_ERROR
;
}
finally
{
try
{
telnet
.
disconnect
();
}
catch
(
IOException
e
)
{
//ignore ex
}
}
}
return
STATUS_OK
;
}
finally
{
//reset terminal setting, fix https://github.com/alibaba/arthas/issues/1412
try
{
terminal
.
restore
();
}
catch
(
Throwable
e
)
{
System
.
out
.
println
(
"Restore terminal settings failure: "
+
e
.
getMessage
());
e
.
printStackTrace
();
}
}
}
private
static
int
batchModeRun
(
TelnetClient
telnet
,
List
<
String
>
commands
,
final
int
executionTimeout
)
throws
IOException
,
InterruptedException
{
if
(
commands
.
size
()
==
0
)
{
return
STATUS_OK
;
}
long
startTime
=
System
.
currentTimeMillis
();
final
InputStream
inputStream
=
telnet
.
getInputStream
();
final
OutputStream
outputStream
=
telnet
.
getOutputStream
();
final
BlockingQueue
<
String
>
receviedPromptQueue
=
new
LinkedBlockingQueue
<
String
>(
1
);
Thread
printResultThread
=
new
Thread
(
new
Runnable
()
{
@Override
public
void
run
()
{
try
{
StringBuilder
line
=
new
StringBuilder
();
BufferedReader
in
=
new
BufferedReader
(
new
InputStreamReader
(
inputStream
,
"UTF-8"
));
int
b
=
-
1
;
while
(
true
)
{
b
=
in
.
read
();
if
(
b
==
-
1
)
{
break
;
}
line
.
appendCodePoint
(
b
);
// 检查到有 [arthas@ 时,意味着可以执行下一个命令了
int
index
=
line
.
indexOf
(
PROMPT
);
if
(
index
>
0
)
{
line
.
delete
(
0
,
index
+
PROMPT
.
length
());
receviedPromptQueue
.
put
(
""
);
}
System
.
out
.
print
(
Character
.
toChars
(
b
));
}
}
catch
(
Exception
e
)
{
// ignore
}
}
});
printResultThread
.
start
();
// send commands to arthas server
for
(
String
command
:
commands
)
{
if
(
command
.
trim
().
isEmpty
())
{
continue
;
}
// try poll prompt and check timeout
while
(
receviedPromptQueue
.
poll
(
100
,
TimeUnit
.
MILLISECONDS
)
==
null
)
{
if
(
executionTimeout
>
0
)
{
long
now
=
System
.
currentTimeMillis
();
if
(
now
-
startTime
>
executionTimeout
)
{
return
STATUS_EXEC_TIMEOUT
;
}
}
}
// send command to server
outputStream
.
write
((
command
+
" | plaintext\n"
).
getBytes
());
outputStream
.
flush
();
}
// 读到最后一个命令执行后的 prompt ,可以直接发 quit命令了。
receviedPromptQueue
.
take
();
outputStream
.
write
(
"quit\n"
.
getBytes
());
outputStream
.
flush
();
System
.
out
.
println
();
return
STATUS_OK
;
}
private
static
String
usage
(
CLI
cli
)
{
StringBuilder
usageStringBuilder
=
new
StringBuilder
();
UsageMessageFormatter
usageMessageFormatter
=
new
UsageMessageFormatter
();
usageMessageFormatter
.
setOptionComparator
(
null
);
cli
.
usage
(
usageStringBuilder
,
usageMessageFormatter
);
return
UsageRender
.
render
(
usageStringBuilder
.
toString
());
}
public
String
getTargetIp
()
{
return
targetIp
;
}
public
int
getPort
()
{
return
port
;
}
public
String
getCommand
()
{
return
command
;
}
public
String
getBatchFile
()
{
return
batchFile
;
}
public
int
getExecutionTimeout
()
{
return
executionTimeout
;
}
public
Integer
getWidth
()
{
return
width
;
}
public
Integer
getheight
()
{
return
height
;
}
public
boolean
isHelp
()
{
return
help
;
}
}
client/src/main/java/org/apache/commons/net/DatagramSocketClient.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net
;
import
java.net.DatagramSocket
;
import
java.net.InetAddress
;
import
java.net.SocketException
;
import
java.nio.charset.Charset
;
/***
* The DatagramSocketClient provides the basic operations that are required
* of client objects accessing datagram sockets. It is meant to be
* subclassed to avoid having to rewrite the same code over and over again
* to open a socket, close a socket, set timeouts, etc. Of special note
* is the {@link #setDatagramSocketFactory setDatagramSocketFactory }
* method, which allows you to control the type of DatagramSocket the
* DatagramSocketClient creates for network communications. This is
* especially useful for adding things like proxy support as well as better
* support for applets. For
* example, you could create a
* {@link org.apache.commons.net.DatagramSocketFactory}
* that
* requests browser security capabilities before creating a socket.
* All classes derived from DatagramSocketClient should use the
* {@link #_socketFactory_ _socketFactory_ } member variable to
* create DatagramSocket instances rather than instantiating
* them by directly invoking a constructor. By honoring this contract
* you guarantee that a user will always be able to provide his own
* Socket implementations by substituting his own SocketFactory.
*
*
* @see DatagramSocketFactory
***/
public
abstract
class
DatagramSocketClient
{
/***
* The default DatagramSocketFactory shared by all DatagramSocketClient
* instances.
***/
private
static
final
DatagramSocketFactory
__DEFAULT_SOCKET_FACTORY
=
new
DefaultDatagramSocketFactory
();
/**
* Charset to use for byte IO.
*/
private
Charset
charset
=
Charset
.
defaultCharset
();
/*** The timeout to use after opening a socket. ***/
protected
int
_timeout_
;
/*** The datagram socket used for the connection. ***/
protected
DatagramSocket
_socket_
;
/***
* A status variable indicating if the client's socket is currently open.
***/
protected
boolean
_isOpen_
;
/*** The datagram socket's DatagramSocketFactory. ***/
protected
DatagramSocketFactory
_socketFactory_
;
/***
* Default constructor for DatagramSocketClient. Initializes
* _socket_ to null, _timeout_ to 0, and _isOpen_ to false.
***/
public
DatagramSocketClient
()
{
_socket_
=
null
;
_timeout_
=
0
;
_isOpen_
=
false
;
_socketFactory_
=
__DEFAULT_SOCKET_FACTORY
;
}
/***
* Opens a DatagramSocket on the local host at the first available port.
* Also sets the timeout on the socket to the default timeout set
* by {@link #setDefaultTimeout setDefaultTimeout() }.
* <p>
* _isOpen_ is set to true after calling this method and _socket_
* is set to the newly opened socket.
*
* @exception SocketException If the socket could not be opened or the
* timeout could not be set.
***/
public
void
open
()
throws
SocketException
{
_socket_
=
_socketFactory_
.
createDatagramSocket
();
_socket_
.
setSoTimeout
(
_timeout_
);
_isOpen_
=
true
;
}
/***
* Opens a DatagramSocket on the local host at a specified port.
* Also sets the timeout on the socket to the default timeout set
* by {@link #setDefaultTimeout setDefaultTimeout() }.
* <p>
* _isOpen_ is set to true after calling this method and _socket_
* is set to the newly opened socket.
*
* @param port The port to use for the socket.
* @exception SocketException If the socket could not be opened or the
* timeout could not be set.
***/
public
void
open
(
int
port
)
throws
SocketException
{
_socket_
=
_socketFactory_
.
createDatagramSocket
(
port
);
_socket_
.
setSoTimeout
(
_timeout_
);
_isOpen_
=
true
;
}
/***
* Opens a DatagramSocket at the specified address on the local host
* at a specified port.
* Also sets the timeout on the socket to the default timeout set
* by {@link #setDefaultTimeout setDefaultTimeout() }.
* <p>
* _isOpen_ is set to true after calling this method and _socket_
* is set to the newly opened socket.
*
* @param port The port to use for the socket.
* @param laddr The local address to use.
* @exception SocketException If the socket could not be opened or the
* timeout could not be set.
***/
public
void
open
(
int
port
,
InetAddress
laddr
)
throws
SocketException
{
_socket_
=
_socketFactory_
.
createDatagramSocket
(
port
,
laddr
);
_socket_
.
setSoTimeout
(
_timeout_
);
_isOpen_
=
true
;
}
/***
* Closes the DatagramSocket used for the connection.
* You should call this method after you've finished using the class
* instance and also before you call {@link #open open() }
* again. _isOpen_ is set to false and _socket_ is set to null.
* If you call this method when the client socket is not open,
* a NullPointerException is thrown.
***/
public
void
close
()
{
if
(
_socket_
!=
null
)
{
_socket_
.
close
();
}
_socket_
=
null
;
_isOpen_
=
false
;
}
/***
* Returns true if the client has a currently open socket.
*
* @return True if the client has a curerntly open socket, false otherwise.
***/
public
boolean
isOpen
()
{
return
_isOpen_
;
}
/***
* Set the default timeout in milliseconds to use when opening a socket.
* After a call to open, the timeout for the socket is set using this value.
* This method should be used prior to a call to {@link #open open()}
* and should not be confused with {@link #setSoTimeout setSoTimeout()}
* which operates on the currently open socket. _timeout_ contains
* the new timeout value.
*
* @param timeout The timeout in milliseconds to use for the datagram socket
* connection.
***/
public
void
setDefaultTimeout
(
int
timeout
)
{
_timeout_
=
timeout
;
}
/***
* Returns the default timeout in milliseconds that is used when
* opening a socket.
*
* @return The default timeout in milliseconds that is used when
* opening a socket.
***/
public
int
getDefaultTimeout
()
{
return
_timeout_
;
}
/***
* Set the timeout in milliseconds of a currently open connection.
* Only call this method after a connection has been opened
* by {@link #open open()}.
*
* @param timeout The timeout in milliseconds to use for the currently
* open datagram socket connection.
* @throws SocketException if an error setting the timeout
***/
public
void
setSoTimeout
(
int
timeout
)
throws
SocketException
{
_socket_
.
setSoTimeout
(
timeout
);
}
/***
* Returns the timeout in milliseconds of the currently opened socket.
* If you call this method when the client socket is not open,
* a NullPointerException is thrown.
*
* @return The timeout in milliseconds of the currently opened socket.
* @throws SocketException if an error getting the timeout
***/
public
int
getSoTimeout
()
throws
SocketException
{
return
_socket_
.
getSoTimeout
();
}
/***
* Returns the port number of the open socket on the local host used
* for the connection. If you call this method when the client socket
* is not open, a NullPointerException is thrown.
*
* @return The port number of the open socket on the local host used
* for the connection.
***/
public
int
getLocalPort
()
{
return
_socket_
.
getLocalPort
();
}
/***
* Returns the local address to which the client's socket is bound.
* If you call this method when the client socket is not open, a
* NullPointerException is thrown.
*
* @return The local address to which the client's socket is bound.
***/
public
InetAddress
getLocalAddress
()
{
return
_socket_
.
getLocalAddress
();
}
/***
* Sets the DatagramSocketFactory used by the DatagramSocketClient
* to open DatagramSockets. If the factory value is null, then a default
* factory is used (only do this to reset the factory after having
* previously altered it).
*
* @param factory The new DatagramSocketFactory the DatagramSocketClient
* should use.
***/
public
void
setDatagramSocketFactory
(
DatagramSocketFactory
factory
)
{
if
(
factory
==
null
)
{
_socketFactory_
=
__DEFAULT_SOCKET_FACTORY
;
}
else
{
_socketFactory_
=
factory
;
}
}
/**
* Gets the charset name.
*
* @return the charset name.
* @since 3.3
* TODO Will be deprecated once the code requires Java 1.6 as a mininmum
*/
public
String
getCharsetName
()
{
return
charset
.
name
();
}
/**
* Gets the charset.
*
* @return the charset.
* @since 3.3
*/
public
Charset
getCharset
()
{
return
charset
;
}
/**
* Sets the charset.
*
* @param charset the charset.
* @since 3.3
*/
public
void
setCharset
(
Charset
charset
)
{
this
.
charset
=
charset
;
}
}
client/src/main/java/org/apache/commons/net/DatagramSocketFactory.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net
;
import
java.net.DatagramSocket
;
import
java.net.InetAddress
;
import
java.net.SocketException
;
/***
* The DatagramSocketFactory interface provides a means for the
* programmer to control the creation of datagram sockets and
* provide his own DatagramSocket implementations for use by all
* classes derived from
* {@link org.apache.commons.net.DatagramSocketClient}
* .
* This allows you to provide your own DatagramSocket implementations and
* to perform security checks or browser capability requests before
* creating a DatagramSocket.
*
*
***/
public
interface
DatagramSocketFactory
{
/***
* Creates a DatagramSocket on the local host at the first available port.
* @return the socket
*
* @exception SocketException If the socket could not be created.
***/
public
DatagramSocket
createDatagramSocket
()
throws
SocketException
;
/***
* Creates a DatagramSocket on the local host at a specified port.
*
* @param port The port to use for the socket.
* @return the socket
* @exception SocketException If the socket could not be created.
***/
public
DatagramSocket
createDatagramSocket
(
int
port
)
throws
SocketException
;
/***
* Creates a DatagramSocket at the specified address on the local host
* at a specified port.
*
* @param port The port to use for the socket.
* @param laddr The local address to use.
* @return the socket
* @exception SocketException If the socket could not be created.
***/
public
DatagramSocket
createDatagramSocket
(
int
port
,
InetAddress
laddr
)
throws
SocketException
;
}
client/src/main/java/org/apache/commons/net/DefaultDatagramSocketFactory.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net
;
import
java.net.DatagramSocket
;
import
java.net.InetAddress
;
import
java.net.SocketException
;
/***
* DefaultDatagramSocketFactory implements the DatagramSocketFactory
* interface by simply wrapping the java.net.DatagramSocket
* constructors. It is the default DatagramSocketFactory used by
* {@link org.apache.commons.net.DatagramSocketClient}
* implementations.
*
*
* @see DatagramSocketFactory
* @see DatagramSocketClient
* @see DatagramSocketClient#setDatagramSocketFactory
***/
public
class
DefaultDatagramSocketFactory
implements
DatagramSocketFactory
{
/***
* Creates a DatagramSocket on the local host at the first available port.
* @return a new DatagramSocket
* @exception SocketException If the socket could not be created.
***/
@Override
public
DatagramSocket
createDatagramSocket
()
throws
SocketException
{
return
new
DatagramSocket
();
}
/***
* Creates a DatagramSocket on the local host at a specified port.
*
* @param port The port to use for the socket.
* @return a new DatagramSocket
* @exception SocketException If the socket could not be created.
***/
@Override
public
DatagramSocket
createDatagramSocket
(
int
port
)
throws
SocketException
{
return
new
DatagramSocket
(
port
);
}
/***
* Creates a DatagramSocket at the specified address on the local host
* at a specified port.
*
* @param port The port to use for the socket.
* @param laddr The local address to use.
* @return a new DatagramSocket
* @exception SocketException If the socket could not be created.
***/
@Override
public
DatagramSocket
createDatagramSocket
(
int
port
,
InetAddress
laddr
)
throws
SocketException
{
return
new
DatagramSocket
(
port
,
laddr
);
}
}
client/src/main/java/org/apache/commons/net/DefaultSocketFactory.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net
;
import
java.io.IOException
;
import
java.net.InetAddress
;
import
java.net.InetSocketAddress
;
import
java.net.Proxy
;
import
java.net.ServerSocket
;
import
java.net.Socket
;
import
java.net.UnknownHostException
;
import
javax.net.SocketFactory
;
/***
* DefaultSocketFactory implements the SocketFactory interface by
* simply wrapping the java.net.Socket and java.net.ServerSocket
* constructors. It is the default SocketFactory used by
* {@link org.apache.commons.net.SocketClient}
* implementations.
*
*
* @see SocketFactory
* @see SocketClient
* @see SocketClient#setSocketFactory
***/
public
class
DefaultSocketFactory
extends
SocketFactory
{
/** The proxy to use when creating new sockets. */
private
final
Proxy
connProxy
;
/**
* The default constructor.
*/
public
DefaultSocketFactory
()
{
this
(
null
);
}
/**
* A constructor for sockets with proxy support.
*
* @param proxy The Proxy to use when creating new Sockets.
* @since 3.2
*/
public
DefaultSocketFactory
(
Proxy
proxy
)
{
connProxy
=
proxy
;
}
/**
* Creates an unconnected Socket.
*
* @return A new unconnected Socket.
* @exception IOException If an I/O error occurs while creating the Socket.
* @since 3.2
*/
@Override
public
Socket
createSocket
()
throws
IOException
{
if
(
connProxy
!=
null
)
{
return
new
Socket
(
connProxy
);
}
return
new
Socket
();
}
/***
* Creates a Socket connected to the given host and port.
*
* @param host The hostname to connect to.
* @param port The port to connect to.
* @return A Socket connected to the given host and port.
* @exception UnknownHostException If the hostname cannot be resolved.
* @exception IOException If an I/O error occurs while creating the Socket.
***/
@Override
public
Socket
createSocket
(
String
host
,
int
port
)
throws
UnknownHostException
,
IOException
{
if
(
connProxy
!=
null
)
{
Socket
s
=
new
Socket
(
connProxy
);
s
.
connect
(
new
InetSocketAddress
(
host
,
port
));
return
s
;
}
return
new
Socket
(
host
,
port
);
}
/***
* Creates a Socket connected to the given host and port.
*
* @param address The address of the host to connect to.
* @param port The port to connect to.
* @return A Socket connected to the given host and port.
* @exception IOException If an I/O error occurs while creating the Socket.
***/
@Override
public
Socket
createSocket
(
InetAddress
address
,
int
port
)
throws
IOException
{
if
(
connProxy
!=
null
)
{
Socket
s
=
new
Socket
(
connProxy
);
s
.
connect
(
new
InetSocketAddress
(
address
,
port
));
return
s
;
}
return
new
Socket
(
address
,
port
);
}
/***
* Creates a Socket connected to the given host and port and
* originating from the specified local address and port.
*
* @param host The hostname to connect to.
* @param port The port to connect to.
* @param localAddr The local address to use.
* @param localPort The local port to use.
* @return A Socket connected to the given host and port.
* @exception UnknownHostException If the hostname cannot be resolved.
* @exception IOException If an I/O error occurs while creating the Socket.
***/
@Override
public
Socket
createSocket
(
String
host
,
int
port
,
InetAddress
localAddr
,
int
localPort
)
throws
UnknownHostException
,
IOException
{
if
(
connProxy
!=
null
)
{
Socket
s
=
new
Socket
(
connProxy
);
s
.
bind
(
new
InetSocketAddress
(
localAddr
,
localPort
));
s
.
connect
(
new
InetSocketAddress
(
host
,
port
));
return
s
;
}
return
new
Socket
(
host
,
port
,
localAddr
,
localPort
);
}
/***
* Creates a Socket connected to the given host and port and
* originating from the specified local address and port.
*
* @param address The address of the host to connect to.
* @param port The port to connect to.
* @param localAddr The local address to use.
* @param localPort The local port to use.
* @return A Socket connected to the given host and port.
* @exception IOException If an I/O error occurs while creating the Socket.
***/
@Override
public
Socket
createSocket
(
InetAddress
address
,
int
port
,
InetAddress
localAddr
,
int
localPort
)
throws
IOException
{
if
(
connProxy
!=
null
)
{
Socket
s
=
new
Socket
(
connProxy
);
s
.
bind
(
new
InetSocketAddress
(
localAddr
,
localPort
));
s
.
connect
(
new
InetSocketAddress
(
address
,
port
));
return
s
;
}
return
new
Socket
(
address
,
port
,
localAddr
,
localPort
);
}
/***
* Creates a ServerSocket bound to a specified port. A port
* of 0 will create the ServerSocket on a system-determined free port.
*
* @param port The port on which to listen, or 0 to use any free port.
* @return A ServerSocket that will listen on a specified port.
* @exception IOException If an I/O error occurs while creating
* the ServerSocket.
***/
public
ServerSocket
createServerSocket
(
int
port
)
throws
IOException
{
return
new
ServerSocket
(
port
);
}
/***
* Creates a ServerSocket bound to a specified port with a given
* maximum queue length for incoming connections. A port of 0 will
* create the ServerSocket on a system-determined free port.
*
* @param port The port on which to listen, or 0 to use any free port.
* @param backlog The maximum length of the queue for incoming connections.
* @return A ServerSocket that will listen on a specified port.
* @exception IOException If an I/O error occurs while creating
* the ServerSocket.
***/
public
ServerSocket
createServerSocket
(
int
port
,
int
backlog
)
throws
IOException
{
return
new
ServerSocket
(
port
,
backlog
);
}
/***
* Creates a ServerSocket bound to a specified port on a given local
* address with a given maximum queue length for incoming connections.
* A port of 0 will
* create the ServerSocket on a system-determined free port.
*
* @param port The port on which to listen, or 0 to use any free port.
* @param backlog The maximum length of the queue for incoming connections.
* @param bindAddr The local address to which the ServerSocket should bind.
* @return A ServerSocket that will listen on a specified port.
* @exception IOException If an I/O error occurs while creating
* the ServerSocket.
***/
public
ServerSocket
createServerSocket
(
int
port
,
int
backlog
,
InetAddress
bindAddr
)
throws
IOException
{
return
new
ServerSocket
(
port
,
backlog
,
bindAddr
);
}
}
client/src/main/java/org/apache/commons/net/MalformedServerReplyException.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net
;
import
java.io.IOException
;
/***
* This exception is used to indicate that the reply from a server
* could not be interpreted. Most of the NetComponents classes attempt
* to be as lenient as possible when receiving server replies. Many
* server implementations deviate from IETF protocol specifications, making
* it necessary to be as flexible as possible. However, there will be
* certain situations where it is not possible to continue an operation
* because the server reply could not be interpreted in a meaningful manner.
* In these cases, a MalformedServerReplyException should be thrown.
*
*
***/
public
class
MalformedServerReplyException
extends
IOException
{
private
static
final
long
serialVersionUID
=
6006765264250543945L
;
/*** Constructs a MalformedServerReplyException with no message ***/
public
MalformedServerReplyException
()
{
super
();
}
/***
* Constructs a MalformedServerReplyException with a specified message.
*
* @param message The message explaining the reason for the exception.
***/
public
MalformedServerReplyException
(
String
message
)
{
super
(
message
);
}
}
client/src/main/java/org/apache/commons/net/PrintCommandListener.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net
;
import
java.io.PrintStream
;
import
java.io.PrintWriter
;
/***
* This is a support class for some of the example programs. It is
* a sample implementation of the ProtocolCommandListener interface
* which just prints out to a specified stream all command/reply traffic.
*
* @since 2.0
***/
public
class
PrintCommandListener
implements
ProtocolCommandListener
{
private
final
PrintWriter
__writer
;
private
final
boolean
__nologin
;
private
final
char
__eolMarker
;
private
final
boolean
__directionMarker
;
/**
* Create the default instance which prints everything.
*
* @param stream where to write the commands and responses
* e.g. System.out
* @since 3.0
*/
public
PrintCommandListener
(
PrintStream
stream
)
{
this
(
new
PrintWriter
(
stream
));
}
/**
* Create an instance which optionally suppresses login command text
* and indicates where the EOL starts with the specified character.
*
* @param stream where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login
*
* @since 3.0
*/
public
PrintCommandListener
(
PrintStream
stream
,
boolean
suppressLogin
)
{
this
(
new
PrintWriter
(
stream
),
suppressLogin
);
}
/**
* Create an instance which optionally suppresses login command text
* and indicates where the EOL starts with the specified character.
*
* @param stream where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL.
*
* @since 3.0
*/
public
PrintCommandListener
(
PrintStream
stream
,
boolean
suppressLogin
,
char
eolMarker
)
{
this
(
new
PrintWriter
(
stream
),
suppressLogin
,
eolMarker
);
}
/**
* Create an instance which optionally suppresses login command text
* and indicates where the EOL starts with the specified character.
*
* @param stream where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL.
* @param showDirection if {@code true}, add {@code "> "} or {@code "< "} as appropriate to the output
*
* @since 3.0
*/
public
PrintCommandListener
(
PrintStream
stream
,
boolean
suppressLogin
,
char
eolMarker
,
boolean
showDirection
)
{
this
(
new
PrintWriter
(
stream
),
suppressLogin
,
eolMarker
,
showDirection
);
}
/**
* Create the default instance which prints everything.
*
* @param writer where to write the commands and responses
*/
public
PrintCommandListener
(
PrintWriter
writer
)
{
this
(
writer
,
false
);
}
/**
* Create an instance which optionally suppresses login command text.
*
* @param writer where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login
*
* @since 3.0
*/
public
PrintCommandListener
(
PrintWriter
writer
,
boolean
suppressLogin
)
{
this
(
writer
,
suppressLogin
,
(
char
)
0
);
}
/**
* Create an instance which optionally suppresses login command text
* and indicates where the EOL starts with the specified character.
*
* @param writer where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL.
*
* @since 3.0
*/
public
PrintCommandListener
(
PrintWriter
writer
,
boolean
suppressLogin
,
char
eolMarker
)
{
this
(
writer
,
suppressLogin
,
eolMarker
,
false
);
}
/**
* Create an instance which optionally suppresses login command text
* and indicates where the EOL starts with the specified character.
*
* @param writer where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL.
* @param showDirection if {@code true}, add {@code ">} " or {@code "< "} as appropriate to the output
*
* @since 3.0
*/
public
PrintCommandListener
(
PrintWriter
writer
,
boolean
suppressLogin
,
char
eolMarker
,
boolean
showDirection
)
{
__writer
=
writer
;
__nologin
=
suppressLogin
;
__eolMarker
=
eolMarker
;
__directionMarker
=
showDirection
;
}
@Override
public
void
protocolCommandSent
(
ProtocolCommandEvent
event
)
{
if
(
__directionMarker
)
{
__writer
.
print
(
"> "
);
}
if
(
__nologin
)
{
String
cmd
=
event
.
getCommand
();
if
(
"PASS"
.
equalsIgnoreCase
(
cmd
)
||
"USER"
.
equalsIgnoreCase
(
cmd
))
{
__writer
.
print
(
cmd
);
__writer
.
println
(
" *******"
);
// Don't bother with EOL marker for this!
}
else
{
final
String
IMAP_LOGIN
=
"LOGIN"
;
if
(
IMAP_LOGIN
.
equalsIgnoreCase
(
cmd
))
{
// IMAP
String
msg
=
event
.
getMessage
();
msg
=
msg
.
substring
(
0
,
msg
.
indexOf
(
IMAP_LOGIN
)+
IMAP_LOGIN
.
length
());
__writer
.
print
(
msg
);
__writer
.
println
(
" *******"
);
// Don't bother with EOL marker for this!
}
else
{
__writer
.
print
(
getPrintableString
(
event
.
getMessage
()));
}
}
}
else
{
__writer
.
print
(
getPrintableString
(
event
.
getMessage
()));
}
__writer
.
flush
();
}
private
String
getPrintableString
(
String
msg
){
if
(
__eolMarker
==
0
)
{
return
msg
;
}
int
pos
=
msg
.
indexOf
(
SocketClient
.
NETASCII_EOL
);
if
(
pos
>
0
)
{
return
msg
.
substring
(
0
,
pos
)
+
__eolMarker
+
msg
.
substring
(
pos
);
}
return
msg
;
}
@Override
public
void
protocolReplyReceived
(
ProtocolCommandEvent
event
)
{
if
(
__directionMarker
)
{
__writer
.
print
(
"< "
);
}
__writer
.
print
(
event
.
getMessage
());
__writer
.
flush
();
}
}
client/src/main/java/org/apache/commons/net/ProtocolCommandEvent.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net
;
import
java.util.EventObject
;
/***
* There exists a large class of IETF protocols that work by sending an
* ASCII text command and arguments to a server, and then receiving an
* ASCII text reply. For debugging and other purposes, it is extremely
* useful to log or keep track of the contents of the protocol messages.
* The ProtocolCommandEvent class coupled with the
* {@link org.apache.commons.net.ProtocolCommandListener}
* interface facilitate this process.
*
*
* @see ProtocolCommandListener
* @see ProtocolCommandSupport
***/
public
class
ProtocolCommandEvent
extends
EventObject
{
private
static
final
long
serialVersionUID
=
403743538418947240L
;
private
final
int
__replyCode
;
private
final
boolean
__isCommand
;
private
final
String
__message
,
__command
;
/***
* Creates a ProtocolCommandEvent signalling a command was sent to
* the server. ProtocolCommandEvents created with this constructor
* should only be sent after a command has been sent, but before the
* reply has been received.
*
* @param source The source of the event.
* @param command The string representation of the command type sent, not
* including the arguments (e.g., "STAT" or "GET").
* @param message The entire command string verbatim as sent to the server,
* including all arguments.
***/
public
ProtocolCommandEvent
(
Object
source
,
String
command
,
String
message
)
{
super
(
source
);
__replyCode
=
0
;
__message
=
message
;
__isCommand
=
true
;
__command
=
command
;
}
/***
* Creates a ProtocolCommandEvent signalling a reply to a command was
* received. ProtocolCommandEvents created with this constructor
* should only be sent after a complete command reply has been received
* fromt a server.
*
* @param source The source of the event.
* @param replyCode The integer code indicating the natureof the reply.
* This will be the protocol integer value for protocols
* that use integer reply codes, or the reply class constant
* corresponding to the reply for protocols like POP3 that use
* strings like OK rather than integer codes (i.e., POP3Repy.OK).
* @param message The entire reply as received from the server.
***/
public
ProtocolCommandEvent
(
Object
source
,
int
replyCode
,
String
message
)
{
super
(
source
);
__replyCode
=
replyCode
;
__message
=
message
;
__isCommand
=
false
;
__command
=
null
;
}
/***
* Returns the string representation of the command type sent (e.g., "STAT"
* or "GET"). If the ProtocolCommandEvent is a reply event, then null
* is returned.
*
* @return The string representation of the command type sent, or null
* if this is a reply event.
***/
public
String
getCommand
()
{
return
__command
;
}
/***
* Returns the reply code of the received server reply. Undefined if
* this is not a reply event.
*
* @return The reply code of the received server reply. Undefined if
* not a reply event.
***/
public
int
getReplyCode
()
{
return
__replyCode
;
}
/***
* Returns true if the ProtocolCommandEvent was generated as a result
* of sending a command.
*
* @return true If the ProtocolCommandEvent was generated as a result
* of sending a command. False otherwise.
***/
public
boolean
isCommand
()
{
return
__isCommand
;
}
/***
* Returns true if the ProtocolCommandEvent was generated as a result
* of receiving a reply.
*
* @return true If the ProtocolCommandEvent was generated as a result
* of receiving a reply. False otherwise.
***/
public
boolean
isReply
()
{
return
!
isCommand
();
}
/***
* Returns the entire message sent to or received from the server.
* Includes the line terminator.
*
* @return The entire message sent to or received from the server.
***/
public
String
getMessage
()
{
return
__message
;
}
}
client/src/main/java/org/apache/commons/net/ProtocolCommandListener.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net
;
import
java.util.EventListener
;
/***
* There exists a large class of IETF protocols that work by sending an
* ASCII text command and arguments to a server, and then receiving an
* ASCII text reply. For debugging and other purposes, it is extremely
* useful to log or keep track of the contents of the protocol messages.
* The ProtocolCommandListener interface coupled with the
* {@link ProtocolCommandEvent} class facilitate this process.
* <p>
* To receive ProtocolCommandEvents, you merely implement the
* ProtocolCommandListener interface and register the class as a listener
* with a ProtocolCommandEvent source such as
* {@link org.apache.commons.net.ftp.FTPClient}.
*
*
* @see ProtocolCommandEvent
* @see ProtocolCommandSupport
***/
public
interface
ProtocolCommandListener
extends
EventListener
{
/***
* This method is invoked by a ProtocolCommandEvent source after
* sending a protocol command to a server.
*
* @param event The ProtocolCommandEvent fired.
***/
public
void
protocolCommandSent
(
ProtocolCommandEvent
event
);
/***
* This method is invoked by a ProtocolCommandEvent source after
* receiving a reply from a server.
*
* @param event The ProtocolCommandEvent fired.
***/
public
void
protocolReplyReceived
(
ProtocolCommandEvent
event
);
}
client/src/main/java/org/apache/commons/net/ProtocolCommandSupport.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net
;
import
java.io.Serializable
;
import
java.util.EventListener
;
import
org.apache.commons.net.util.ListenerList
;
/***
* ProtocolCommandSupport is a convenience class for managing a list of
* ProtocolCommandListeners and firing ProtocolCommandEvents. You can
* simply delegate ProtocolCommandEvent firing and listener
* registering/unregistering tasks to this class.
*
*
* @see ProtocolCommandEvent
* @see ProtocolCommandListener
***/
public
class
ProtocolCommandSupport
implements
Serializable
{
private
static
final
long
serialVersionUID
=
-
8017692739988399978L
;
private
final
Object
__source
;
private
final
ListenerList
__listeners
;
/***
* Creates a ProtocolCommandSupport instance using the indicated source
* as the source of ProtocolCommandEvents.
*
* @param source The source to use for all generated ProtocolCommandEvents.
***/
public
ProtocolCommandSupport
(
Object
source
)
{
__listeners
=
new
ListenerList
();
__source
=
source
;
}
/***
* Fires a ProtocolCommandEvent signalling the sending of a command to all
* registered listeners, invoking their
* {@link org.apache.commons.net.ProtocolCommandListener#protocolCommandSent protocolCommandSent() }
* methods.
*
* @param command The string representation of the command type sent, not
* including the arguments (e.g., "STAT" or "GET").
* @param message The entire command string verbatim as sent to the server,
* including all arguments.
***/
public
void
fireCommandSent
(
String
command
,
String
message
)
{
ProtocolCommandEvent
event
;
event
=
new
ProtocolCommandEvent
(
__source
,
command
,
message
);
for
(
EventListener
listener
:
__listeners
)
{
((
ProtocolCommandListener
)
listener
).
protocolCommandSent
(
event
);
}
}
/***
* Fires a ProtocolCommandEvent signalling the reception of a command reply
* to all registered listeners, invoking their
* {@link org.apache.commons.net.ProtocolCommandListener#protocolReplyReceived protocolReplyReceived() }
* methods.
*
* @param replyCode The integer code indicating the natureof the reply.
* This will be the protocol integer value for protocols
* that use integer reply codes, or the reply class constant
* corresponding to the reply for protocols like POP3 that use
* strings like OK rather than integer codes (i.e., POP3Repy.OK).
* @param message The entire reply as received from the server.
***/
public
void
fireReplyReceived
(
int
replyCode
,
String
message
)
{
ProtocolCommandEvent
event
;
event
=
new
ProtocolCommandEvent
(
__source
,
replyCode
,
message
);
for
(
EventListener
listener
:
__listeners
)
{
((
ProtocolCommandListener
)
listener
).
protocolReplyReceived
(
event
);
}
}
/***
* Adds a ProtocolCommandListener.
*
* @param listener The ProtocolCommandListener to add.
***/
public
void
addProtocolCommandListener
(
ProtocolCommandListener
listener
)
{
__listeners
.
addListener
(
listener
);
}
/***
* Removes a ProtocolCommandListener.
*
* @param listener The ProtocolCommandListener to remove.
***/
public
void
removeProtocolCommandListener
(
ProtocolCommandListener
listener
)
{
__listeners
.
removeListener
(
listener
);
}
/***
* Returns the number of ProtocolCommandListeners currently registered.
*
* @return The number of ProtocolCommandListeners currently registered.
***/
public
int
getListenerCount
()
{
return
__listeners
.
getListenerCount
();
}
}
client/src/main/java/org/apache/commons/net/SocketClient.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net
;
import
java.io.Closeable
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.net.InetAddress
;
import
java.net.InetSocketAddress
;
import
java.net.Proxy
;
import
java.net.Socket
;
import
java.net.SocketException
;
import
java.nio.charset.Charset
;
import
javax.net.ServerSocketFactory
;
import
javax.net.SocketFactory
;
/**
* The SocketClient provides the basic operations that are required of
* client objects accessing sockets. It is meant to be
* subclassed to avoid having to rewrite the same code over and over again
* to open a socket, close a socket, set timeouts, etc. Of special note
* is the {@link #setSocketFactory setSocketFactory }
* method, which allows you to control the type of Socket the SocketClient
* creates for initiating network connections. This is especially useful
* for adding SSL or proxy support as well as better support for applets. For
* example, you could create a
* {@link javax.net.SocketFactory} that
* requests browser security capabilities before creating a socket.
* All classes derived from SocketClient should use the
* {@link #_socketFactory_ _socketFactory_ } member variable to
* create Socket and ServerSocket instances rather than instantiating
* them by directly invoking a constructor. By honoring this contract
* you guarantee that a user will always be able to provide his own
* Socket implementations by substituting his own SocketFactory.
* @see SocketFactory
*/
public
abstract
class
SocketClient
{
/**
* The end of line character sequence used by most IETF protocols. That
* is a carriage return followed by a newline: "\r\n"
*/
public
static
final
String
NETASCII_EOL
=
"\r\n"
;
/** The default SocketFactory shared by all SocketClient instances. */
private
static
final
SocketFactory
__DEFAULT_SOCKET_FACTORY
=
SocketFactory
.
getDefault
();
/** The default {@link ServerSocketFactory} */
private
static
final
ServerSocketFactory
__DEFAULT_SERVER_SOCKET_FACTORY
=
ServerSocketFactory
.
getDefault
();
/**
* A ProtocolCommandSupport object used to manage the registering of
* ProtocolCommandListeners and the firing of ProtocolCommandEvents.
*/
private
ProtocolCommandSupport
__commandSupport
;
/** The timeout to use after opening a socket. */
protected
int
_timeout_
;
/** The socket used for the connection. */
protected
Socket
_socket_
;
/** The hostname used for the connection (null = no hostname supplied). */
protected
String
_hostname_
;
/** The default port the client should connect to. */
protected
int
_defaultPort_
;
/** The socket's InputStream. */
protected
InputStream
_input_
;
/** The socket's OutputStream. */
protected
OutputStream
_output_
;
/** The socket's SocketFactory. */
protected
SocketFactory
_socketFactory_
;
/** The socket's ServerSocket Factory. */
protected
ServerSocketFactory
_serverSocketFactory_
;
/** The socket's connect timeout (0 = infinite timeout) */
private
static
final
int
DEFAULT_CONNECT_TIMEOUT
=
0
;
protected
int
connectTimeout
=
DEFAULT_CONNECT_TIMEOUT
;
/** Hint for SO_RCVBUF size */
private
int
receiveBufferSize
=
-
1
;
/** Hint for SO_SNDBUF size */
private
int
sendBufferSize
=
-
1
;
/** The proxy to use when connecting. */
private
Proxy
connProxy
;
/**
* Charset to use for byte IO.
*/
private
Charset
charset
=
Charset
.
defaultCharset
();
/**
* Default constructor for SocketClient. Initializes
* _socket_ to null, _timeout_ to 0, _defaultPort to 0,
* _isConnected_ to false, charset to {@code Charset.defaultCharset()}
* and _socketFactory_ to a shared instance of
* {@link org.apache.commons.net.DefaultSocketFactory}.
*/
public
SocketClient
()
{
_socket_
=
null
;
_hostname_
=
null
;
_input_
=
null
;
_output_
=
null
;
_timeout_
=
0
;
_defaultPort_
=
0
;
_socketFactory_
=
__DEFAULT_SOCKET_FACTORY
;
_serverSocketFactory_
=
__DEFAULT_SERVER_SOCKET_FACTORY
;
}
/**
* Because there are so many connect() methods, the _connectAction_()
* method is provided as a means of performing some action immediately
* after establishing a connection, rather than reimplementing all
* of the connect() methods. The last action performed by every
* connect() method after opening a socket is to call this method.
* <p>
* This method sets the timeout on the just opened socket to the default
* timeout set by {@link #setDefaultTimeout setDefaultTimeout() },
* sets _input_ and _output_ to the socket's InputStream and OutputStream
* respectively, and sets _isConnected_ to true.
* <p>
* Subclasses overriding this method should start by calling
* <code> super._connectAction_() </code> first to ensure the
* initialization of the aforementioned protected variables.
* @throws IOException (SocketException) if a problem occurs with the socket
*/
protected
void
_connectAction_
()
throws
IOException
{
_socket_
.
setSoTimeout
(
_timeout_
);
_input_
=
_socket_
.
getInputStream
();
_output_
=
_socket_
.
getOutputStream
();
}
/**
* Opens a Socket connected to a remote host at the specified port and
* originating from the current host at a system assigned port.
* Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions.
* <p>
* @param host The remote host.
* @param port The port to connect to on the remote host.
* @exception SocketException If the socket timeout could not be set.
* @exception IOException If the socket could not be opened. In most
* cases you will only want to catch IOException since SocketException is
* derived from it.
*/
public
void
connect
(
InetAddress
host
,
int
port
)
throws
SocketException
,
IOException
{
_hostname_
=
null
;
_socket_
=
_socketFactory_
.
createSocket
();
if
(
receiveBufferSize
!=
-
1
)
{
_socket_
.
setReceiveBufferSize
(
receiveBufferSize
);
}
if
(
sendBufferSize
!=
-
1
)
{
_socket_
.
setSendBufferSize
(
sendBufferSize
);
}
_socket_
.
connect
(
new
InetSocketAddress
(
host
,
port
),
connectTimeout
);
_connectAction_
();
}
/**
* Opens a Socket connected to a remote host at the specified port and
* originating from the current host at a system assigned port.
* Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions.
* <p>
* @param hostname The name of the remote host.
* @param port The port to connect to on the remote host.
* @exception SocketException If the socket timeout could not be set.
* @exception IOException If the socket could not be opened. In most
* cases you will only want to catch IOException since SocketException is
* derived from it.
* @exception java.net.UnknownHostException If the hostname cannot be resolved.
*/
public
void
connect
(
String
hostname
,
int
port
)
throws
SocketException
,
IOException
{
connect
(
InetAddress
.
getByName
(
hostname
),
port
);
_hostname_
=
hostname
;
}
/**
* Opens a Socket connected to a remote host at the specified port and
* originating from the specified local address and port.
* Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions.
* <p>
* @param host The remote host.
* @param port The port to connect to on the remote host.
* @param localAddr The local address to use.
* @param localPort The local port to use.
* @exception SocketException If the socket timeout could not be set.
* @exception IOException If the socket could not be opened. In most
* cases you will only want to catch IOException since SocketException is
* derived from it.
*/
public
void
connect
(
InetAddress
host
,
int
port
,
InetAddress
localAddr
,
int
localPort
)
throws
SocketException
,
IOException
{
_hostname_
=
null
;
_socket_
=
_socketFactory_
.
createSocket
();
if
(
receiveBufferSize
!=
-
1
)
{
_socket_
.
setReceiveBufferSize
(
receiveBufferSize
);
}
if
(
sendBufferSize
!=
-
1
)
{
_socket_
.
setSendBufferSize
(
sendBufferSize
);
}
_socket_
.
bind
(
new
InetSocketAddress
(
localAddr
,
localPort
));
_socket_
.
connect
(
new
InetSocketAddress
(
host
,
port
),
connectTimeout
);
_connectAction_
();
}
/**
* Opens a Socket connected to a remote host at the specified port and
* originating from the specified local address and port.
* Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions.
* <p>
* @param hostname The name of the remote host.
* @param port The port to connect to on the remote host.
* @param localAddr The local address to use.
* @param localPort The local port to use.
* @exception SocketException If the socket timeout could not be set.
* @exception IOException If the socket could not be opened. In most
* cases you will only want to catch IOException since SocketException is
* derived from it.
* @exception java.net.UnknownHostException If the hostname cannot be resolved.
*/
public
void
connect
(
String
hostname
,
int
port
,
InetAddress
localAddr
,
int
localPort
)
throws
SocketException
,
IOException
{
connect
(
InetAddress
.
getByName
(
hostname
),
port
,
localAddr
,
localPort
);
_hostname_
=
hostname
;
}
/**
* Opens a Socket connected to a remote host at the current default port
* and originating from the current host at a system assigned port.
* Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions.
* <p>
* @param host The remote host.
* @exception SocketException If the socket timeout could not be set.
* @exception IOException If the socket could not be opened. In most
* cases you will only want to catch IOException since SocketException is
* derived from it.
*/
public
void
connect
(
InetAddress
host
)
throws
SocketException
,
IOException
{
_hostname_
=
null
;
connect
(
host
,
_defaultPort_
);
}
/**
* Opens a Socket connected to a remote host at the current default
* port and originating from the current host at a system assigned port.
* Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions.
* <p>
* @param hostname The name of the remote host.
* @exception SocketException If the socket timeout could not be set.
* @exception IOException If the socket could not be opened. In most
* cases you will only want to catch IOException since SocketException is
* derived from it.
* @exception java.net.UnknownHostException If the hostname cannot be resolved.
*/
public
void
connect
(
String
hostname
)
throws
SocketException
,
IOException
{
connect
(
hostname
,
_defaultPort_
);
_hostname_
=
hostname
;
}
/**
* Disconnects the socket connection.
* You should call this method after you've finished using the class
* instance and also before you call
* {@link #connect connect() }
* again. _isConnected_ is set to false, _socket_ is set to null,
* _input_ is set to null, and _output_ is set to null.
* <p>
* @exception IOException If there is an error closing the socket.
*/
public
void
disconnect
()
throws
IOException
{
closeQuietly
(
_socket_
);
closeQuietly
(
_input_
);
closeQuietly
(
_output_
);
_socket_
=
null
;
_hostname_
=
null
;
_input_
=
null
;
_output_
=
null
;
}
private
void
closeQuietly
(
Socket
socket
)
{
if
(
socket
!=
null
){
try
{
socket
.
close
();
}
catch
(
IOException
e
)
{
// Ignored
}
}
}
private
void
closeQuietly
(
Closeable
close
){
if
(
close
!=
null
){
try
{
close
.
close
();
}
catch
(
IOException
e
)
{
// Ignored
}
}
}
/**
* Returns true if the client is currently connected to a server.
* <p>
* Delegates to {@link Socket#isConnected()}
* @return True if the client is currently connected to a server,
* false otherwise.
*/
public
boolean
isConnected
()
{
if
(
_socket_
==
null
)
{
return
false
;
}
return
_socket_
.
isConnected
();
}
/**
* Make various checks on the socket to test if it is available for use.
* Note that the only sure test is to use it, but these checks may help
* in some cases.
* @see <a href="https://issues.apache.org/jira/browse/NET-350">NET-350</a>
* @return {@code true} if the socket appears to be available for use
* @since 3.0
*/
public
boolean
isAvailable
(){
if
(
isConnected
())
{
try
{
if
(
_socket_
.
getInetAddress
()
==
null
)
{
return
false
;
}
if
(
_socket_
.
getPort
()
==
0
)
{
return
false
;
}
if
(
_socket_
.
getRemoteSocketAddress
()
==
null
)
{
return
false
;
}
if
(
_socket_
.
isClosed
())
{
return
false
;
}
/* these aren't exact checks (a Socket can be half-open),
but since we usually require two-way data transfer,
we check these here too: */
if
(
_socket_
.
isInputShutdown
())
{
return
false
;
}
if
(
_socket_
.
isOutputShutdown
())
{
return
false
;
}
/* ignore the result, catch exceptions: */
_socket_
.
getInputStream
();
_socket_
.
getOutputStream
();
}
catch
(
IOException
ioex
)
{
return
false
;
}
return
true
;
}
else
{
return
false
;
}
}
/**
* Sets the default port the SocketClient should connect to when a port
* is not specified. The {@link #_defaultPort_ _defaultPort_ }
* variable stores this value. If never set, the default port is equal
* to zero.
* <p>
* @param port The default port to set.
*/
public
void
setDefaultPort
(
int
port
)
{
_defaultPort_
=
port
;
}
/**
* Returns the current value of the default port (stored in
* {@link #_defaultPort_ _defaultPort_ }).
* <p>
* @return The current value of the default port.
*/
public
int
getDefaultPort
()
{
return
_defaultPort_
;
}
/**
* Set the default timeout in milliseconds to use when opening a socket.
* This value is only used previous to a call to
* {@link #connect connect()}
* and should not be confused with {@link #setSoTimeout setSoTimeout()}
* which operates on an the currently opened socket. _timeout_ contains
* the new timeout value.
* <p>
* @param timeout The timeout in milliseconds to use for the socket
* connection.
*/
public
void
setDefaultTimeout
(
int
timeout
)
{
_timeout_
=
timeout
;
}
/**
* Returns the default timeout in milliseconds that is used when
* opening a socket.
* <p>
* @return The default timeout in milliseconds that is used when
* opening a socket.
*/
public
int
getDefaultTimeout
()
{
return
_timeout_
;
}
/**
* Set the timeout in milliseconds of a currently open connection.
* Only call this method after a connection has been opened
* by {@link #connect connect()}.
* <p>
* To set the initial timeout, use {@link #setDefaultTimeout(int)} instead.
*
* @param timeout The timeout in milliseconds to use for the currently
* open socket connection.
* @exception SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open
*/
public
void
setSoTimeout
(
int
timeout
)
throws
SocketException
{
_socket_
.
setSoTimeout
(
timeout
);
}
/**
* Set the underlying socket send buffer size.
* <p>
* @param size The size of the buffer in bytes.
* @throws SocketException never thrown, but subclasses might want to do so
* @since 2.0
*/
public
void
setSendBufferSize
(
int
size
)
throws
SocketException
{
sendBufferSize
=
size
;
}
/**
* Get the current sendBuffer size
* @return the size, or -1 if not initialised
* @since 3.0
*/
protected
int
getSendBufferSize
(){
return
sendBufferSize
;
}
/**
* Sets the underlying socket receive buffer size.
* <p>
* @param size The size of the buffer in bytes.
* @throws SocketException never (but subclasses may wish to do so)
* @since 2.0
*/
public
void
setReceiveBufferSize
(
int
size
)
throws
SocketException
{
receiveBufferSize
=
size
;
}
/**
* Get the current receivedBuffer size
* @return the size, or -1 if not initialised
* @since 3.0
*/
protected
int
getReceiveBufferSize
(){
return
receiveBufferSize
;
}
/**
* Returns the timeout in milliseconds of the currently opened socket.
* <p>
* @return The timeout in milliseconds of the currently opened socket.
* @exception SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open
*/
public
int
getSoTimeout
()
throws
SocketException
{
return
_socket_
.
getSoTimeout
();
}
/**
* Enables or disables the Nagle's algorithm (TCP_NODELAY) on the
* currently opened socket.
* <p>
* @param on True if Nagle's algorithm is to be enabled, false if not.
* @exception SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open
*/
public
void
setTcpNoDelay
(
boolean
on
)
throws
SocketException
{
_socket_
.
setTcpNoDelay
(
on
);
}
/**
* Returns true if Nagle's algorithm is enabled on the currently opened
* socket.
* <p>
* @return True if Nagle's algorithm is enabled on the currently opened
* socket, false otherwise.
* @exception SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open
*/
public
boolean
getTcpNoDelay
()
throws
SocketException
{
return
_socket_
.
getTcpNoDelay
();
}
/**
* Sets the SO_KEEPALIVE flag on the currently opened socket.
*
* From the Javadocs, the default keepalive time is 2 hours (although this is
* implementation dependent). It looks as though the Windows WSA sockets implementation
* allows a specific keepalive value to be set, although this seems not to be the case on
* other systems.
* @param keepAlive If true, keepAlive is turned on
* @throws SocketException if there is a problem with the socket
* @throws NullPointerException if the socket is not currently open
* @since 2.2
*/
public
void
setKeepAlive
(
boolean
keepAlive
)
throws
SocketException
{
_socket_
.
setKeepAlive
(
keepAlive
);
}
/**
* Returns the current value of the SO_KEEPALIVE flag on the currently opened socket.
* Delegates to {@link Socket#getKeepAlive()}
* @return True if SO_KEEPALIVE is enabled.
* @throws SocketException if there is a problem with the socket
* @throws NullPointerException if the socket is not currently open
* @since 2.2
*/
public
boolean
getKeepAlive
()
throws
SocketException
{
return
_socket_
.
getKeepAlive
();
}
/**
* Sets the SO_LINGER timeout on the currently opened socket.
* <p>
* @param on True if linger is to be enabled, false if not.
* @param val The linger timeout (in hundredths of a second?)
* @exception SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open
*/
public
void
setSoLinger
(
boolean
on
,
int
val
)
throws
SocketException
{
_socket_
.
setSoLinger
(
on
,
val
);
}
/**
* Returns the current SO_LINGER timeout of the currently opened socket.
* <p>
* @return The current SO_LINGER timeout. If SO_LINGER is disabled returns
* -1.
* @exception SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open
*/
public
int
getSoLinger
()
throws
SocketException
{
return
_socket_
.
getSoLinger
();
}
/**
* Returns the port number of the open socket on the local host used
* for the connection.
* Delegates to {@link Socket#getLocalPort()}
* <p>
* @return The port number of the open socket on the local host used
* for the connection.
* @throws NullPointerException if the socket is not currently open
*/
public
int
getLocalPort
()
{
return
_socket_
.
getLocalPort
();
}
/**
* Returns the local address to which the client's socket is bound.
* Delegates to {@link Socket#getLocalAddress()}
* <p>
* @return The local address to which the client's socket is bound.
* @throws NullPointerException if the socket is not currently open
*/
public
InetAddress
getLocalAddress
()
{
return
_socket_
.
getLocalAddress
();
}
/**
* Returns the port number of the remote host to which the client is
* connected.
* Delegates to {@link Socket#getPort()}
* <p>
* @return The port number of the remote host to which the client is
* connected.
* @throws NullPointerException if the socket is not currently open
*/
public
int
getRemotePort
()
{
return
_socket_
.
getPort
();
}
/**
* @return The remote address to which the client is connected.
* Delegates to {@link Socket#getInetAddress()}
* @throws NullPointerException if the socket is not currently open
*/
public
InetAddress
getRemoteAddress
()
{
return
_socket_
.
getInetAddress
();
}
/**
* Verifies that the remote end of the given socket is connected to the
* the same host that the SocketClient is currently connected to. This
* is useful for doing a quick security check when a client needs to
* accept a connection from a server, such as an FTP data connection or
* a BSD R command standard error stream.
* <p>
* @param socket the item to check against
* @return True if the remote hosts are the same, false if not.
*/
public
boolean
verifyRemote
(
Socket
socket
)
{
InetAddress
host1
,
host2
;
host1
=
socket
.
getInetAddress
();
host2
=
getRemoteAddress
();
return
host1
.
equals
(
host2
);
}
/**
* Sets the SocketFactory used by the SocketClient to open socket
* connections. If the factory value is null, then a default
* factory is used (only do this to reset the factory after having
* previously altered it).
* Any proxy setting is discarded.
* <p>
* @param factory The new SocketFactory the SocketClient should use.
*/
public
void
setSocketFactory
(
SocketFactory
factory
)
{
if
(
factory
==
null
)
{
_socketFactory_
=
__DEFAULT_SOCKET_FACTORY
;
}
else
{
_socketFactory_
=
factory
;
}
// re-setting the socket factory makes the proxy setting useless,
// so set the field to null so that getProxy() doesn't return a
// Proxy that we're actually not using.
connProxy
=
null
;
}
/**
* Sets the ServerSocketFactory used by the SocketClient to open ServerSocket
* connections. If the factory value is null, then a default
* factory is used (only do this to reset the factory after having
* previously altered it).
* <p>
* @param factory The new ServerSocketFactory the SocketClient should use.
* @since 2.0
*/
public
void
setServerSocketFactory
(
ServerSocketFactory
factory
)
{
if
(
factory
==
null
)
{
_serverSocketFactory_
=
__DEFAULT_SERVER_SOCKET_FACTORY
;
}
else
{
_serverSocketFactory_
=
factory
;
}
}
/**
* Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's
* connect() method.
* @param connectTimeout The connection timeout to use (in ms)
* @since 2.0
*/
public
void
setConnectTimeout
(
int
connectTimeout
)
{
this
.
connectTimeout
=
connectTimeout
;
}
/**
* Get the underlying socket connection timeout.
* @return timeout (in ms)
* @since 2.0
*/
public
int
getConnectTimeout
()
{
return
connectTimeout
;
}
/**
* Get the underlying {@link ServerSocketFactory}
* @return The server socket factory
* @since 2.2
*/
public
ServerSocketFactory
getServerSocketFactory
()
{
return
_serverSocketFactory_
;
}
/**
* Adds a ProtocolCommandListener.
*
* @param listener The ProtocolCommandListener to add.
* @since 3.0
*/
public
void
addProtocolCommandListener
(
ProtocolCommandListener
listener
)
{
getCommandSupport
().
addProtocolCommandListener
(
listener
);
}
/**
* Removes a ProtocolCommandListener.
*
* @param listener The ProtocolCommandListener to remove.
* @since 3.0
*/
public
void
removeProtocolCommandListener
(
ProtocolCommandListener
listener
)
{
getCommandSupport
().
removeProtocolCommandListener
(
listener
);
}
/**
* If there are any listeners, send them the reply details.
*
* @param replyCode the code extracted from the reply
* @param reply the full reply text
* @since 3.0
*/
protected
void
fireReplyReceived
(
int
replyCode
,
String
reply
)
{
if
(
getCommandSupport
().
getListenerCount
()
>
0
)
{
getCommandSupport
().
fireReplyReceived
(
replyCode
,
reply
);
}
}
/**
* If there are any listeners, send them the command details.
*
* @param command the command name
* @param message the complete message, including command name
* @since 3.0
*/
protected
void
fireCommandSent
(
String
command
,
String
message
)
{
if
(
getCommandSupport
().
getListenerCount
()
>
0
)
{
getCommandSupport
().
fireCommandSent
(
command
,
message
);
}
}
/**
* Create the CommandSupport instance if required
*/
protected
void
createCommandSupport
(){
__commandSupport
=
new
ProtocolCommandSupport
(
this
);
}
/**
* Subclasses can override this if they need to provide their own
* instance field for backwards compatibilty.
*
* @return the CommandSupport instance, may be {@code null}
* @since 3.0
*/
protected
ProtocolCommandSupport
getCommandSupport
()
{
return
__commandSupport
;
}
/**
* Sets the proxy for use with all the connections.
* The proxy is used for connections established after the
* call to this method.
*
* @param proxy the new proxy for connections.
* @since 3.2
*/
public
void
setProxy
(
Proxy
proxy
)
{
setSocketFactory
(
new
DefaultSocketFactory
(
proxy
));
connProxy
=
proxy
;
}
/**
* Gets the proxy for use with all the connections.
* @return the current proxy for connections.
*/
public
Proxy
getProxy
()
{
return
connProxy
;
}
/**
* Gets the charset name.
*
* @return the charset.
* @since 3.3
* @deprecated Since the code now requires Java 1.6 as a mininmum
*/
@Deprecated
public
String
getCharsetName
()
{
return
charset
.
name
();
}
/**
* Gets the charset.
*
* @return the charset.
* @since 3.3
*/
public
Charset
getCharset
()
{
return
charset
;
}
/**
* Sets the charset.
*
* @param charset the charset.
* @since 3.3
*/
public
void
setCharset
(
Charset
charset
)
{
this
.
charset
=
charset
;
}
/*
* N.B. Fields cannot be pulled up into a super-class without breaking binary compatibility,
* so the abstract method is needed to pass the instance to the methods which were moved here.
*/
}
client/src/main/java/org/apache/commons/net/telnet/EchoOptionHandler.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net.telnet
;
/***
* Implements the telnet echo option RFC 857.
***/
public
class
EchoOptionHandler
extends
TelnetOptionHandler
{
/***
* Constructor for the EchoOptionHandler. Allows defining desired
* initial setting for local/remote activation of this option and
* behaviour in case a local/remote activation request for this
* option is received.
* <p>
* @param initlocal - if set to true, a WILL is sent upon connection.
* @param initremote - if set to true, a DO is sent upon connection.
* @param acceptlocal - if set to true, any DO request is accepted.
* @param acceptremote - if set to true, any WILL request is accepted.
***/
public
EchoOptionHandler
(
boolean
initlocal
,
boolean
initremote
,
boolean
acceptlocal
,
boolean
acceptremote
)
{
super
(
TelnetOption
.
ECHO
,
initlocal
,
initremote
,
acceptlocal
,
acceptremote
);
}
/***
* Constructor for the EchoOptionHandler. Initial and accept
* behaviour flags are set to false
***/
public
EchoOptionHandler
()
{
super
(
TelnetOption
.
ECHO
,
false
,
false
,
false
,
false
);
}
}
client/src/main/java/org/apache/commons/net/telnet/InvalidTelnetOptionException.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net.telnet
;
/***
* The InvalidTelnetOptionException is the exception that is
* thrown whenever a TelnetOptionHandler with an invlaid
* option code is registered in TelnetClient with addOptionHandler.
***/
public
class
InvalidTelnetOptionException
extends
Exception
{
private
static
final
long
serialVersionUID
=
-
2516777155928793597L
;
/***
* Option code
***/
private
final
int
optionCode
;
/***
* Error message
***/
private
final
String
msg
;
/***
* Constructor for the exception.
* <p>
* @param message - Error message.
* @param optcode - Option code.
***/
public
InvalidTelnetOptionException
(
String
message
,
int
optcode
)
{
optionCode
=
optcode
;
msg
=
message
;
}
/***
* Gets the error message of ths exception.
* <p>
* @return the error message.
***/
@Override
public
String
getMessage
()
{
return
(
msg
+
": "
+
optionCode
);
}
}
client/src/main/java/org/apache/commons/net/telnet/SimpleOptionHandler.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net.telnet
;
/***
* Simple option handler that can be used for options
* that don't require subnegotiation.
***/
public
class
SimpleOptionHandler
extends
TelnetOptionHandler
{
/***
* Constructor for the SimpleOptionHandler. Allows defining desired
* initial setting for local/remote activation of this option and
* behaviour in case a local/remote activation request for this
* option is received.
* <p>
* @param optcode - option code.
* @param initlocal - if set to true, a WILL is sent upon connection.
* @param initremote - if set to true, a DO is sent upon connection.
* @param acceptlocal - if set to true, any DO request is accepted.
* @param acceptremote - if set to true, any WILL request is accepted.
***/
public
SimpleOptionHandler
(
int
optcode
,
boolean
initlocal
,
boolean
initremote
,
boolean
acceptlocal
,
boolean
acceptremote
)
{
super
(
optcode
,
initlocal
,
initremote
,
acceptlocal
,
acceptremote
);
}
/***
* Constructor for the SimpleOptionHandler. Initial and accept
* behaviour flags are set to false
* <p>
* @param optcode - option code.
***/
public
SimpleOptionHandler
(
int
optcode
)
{
super
(
optcode
,
false
,
false
,
false
,
false
);
}
}
client/src/main/java/org/apache/commons/net/telnet/SuppressGAOptionHandler.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net.telnet
;
/***
* Implements the telnet suppress go ahead option RFC 858.
***/
public
class
SuppressGAOptionHandler
extends
TelnetOptionHandler
{
/***
* Constructor for the SuppressGAOptionHandler. Allows defining desired
* initial setting for local/remote activation of this option and
* behaviour in case a local/remote activation request for this
* option is received.
* <p>
* @param initlocal - if set to true, a WILL is sent upon connection.
* @param initremote - if set to true, a DO is sent upon connection.
* @param acceptlocal - if set to true, any DO request is accepted.
* @param acceptremote - if set to true, any WILL request is accepted.
***/
public
SuppressGAOptionHandler
(
boolean
initlocal
,
boolean
initremote
,
boolean
acceptlocal
,
boolean
acceptremote
)
{
super
(
TelnetOption
.
SUPPRESS_GO_AHEAD
,
initlocal
,
initremote
,
acceptlocal
,
acceptremote
);
}
/***
* Constructor for the SuppressGAOptionHandler. Initial and accept
* behaviour flags are set to false
***/
public
SuppressGAOptionHandler
()
{
super
(
TelnetOption
.
SUPPRESS_GO_AHEAD
,
false
,
false
,
false
,
false
);
}
}
client/src/main/java/org/apache/commons/net/telnet/Telnet.java
0 → 100644
View file @
7c094a26
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.apache.commons.net.telnet
;
import
java.io.BufferedInputStream
;
import
java.io.BufferedOutputStream
;
import
java.io.OutputStream
;
import
java.io.IOException
;
import
java.util.Arrays
;
import
org.apache.commons.net.SocketClient
;
class
Telnet
extends
SocketClient
{
static
final
boolean
debug
=
/*true;*/
false
;
static
final
boolean
debugoptions
=
/*true;*/
false
;
static
final
byte
[]
_COMMAND_DO
=
{
(
byte
)
TelnetCommand
.
IAC
,
(
byte
)
TelnetCommand
.
DO
};
static
final
byte
[]
_COMMAND_DONT
=
{
(
byte
)
TelnetCommand
.
IAC
,
(
byte
)
TelnetCommand
.
DONT
};
static
final
byte
[]
_COMMAND_WILL
=
{
(
byte
)
TelnetCommand
.
IAC
,
(
byte
)
TelnetCommand
.
WILL
};
static
final
byte
[]
_COMMAND_WONT
=
{
(
byte
)
TelnetCommand
.
IAC
,
(
byte
)
TelnetCommand
.
WONT
};
static
final
byte
[]
_COMMAND_SB
=
{
(
byte
)
TelnetCommand
.
IAC
,
(
byte
)
TelnetCommand
.
SB
};
static
final
byte
[]
_COMMAND_SE
=
{
(
byte
)
TelnetCommand
.
IAC
,
(
byte
)
TelnetCommand
.
SE
};
static
final
int
_WILL_MASK
=
0x01
,
_DO_MASK
=
0x02
,
_REQUESTED_WILL_MASK
=
0x04
,
_REQUESTED_DO_MASK
=
0x08
;
/* public */
static
final
int
DEFAULT_PORT
=
23
;
int
[]
_doResponse
,
_willResponse
,
_options
;
/* TERMINAL-TYPE option (start)*/
/***
* Terminal type option
***/
protected
static
final
int
TERMINAL_TYPE
=
24
;
/***
* Send (for subnegotiation)
***/
protected
static
final
int
TERMINAL_TYPE_SEND
=
1
;
/***
* Is (for subnegotiation)
***/
protected
static
final
int
TERMINAL_TYPE_IS
=
0
;
/***
* Is sequence (for subnegotiation)
***/
static
final
byte
[]
_COMMAND_IS
=
{
(
byte
)
TERMINAL_TYPE
,
(
byte
)
TERMINAL_TYPE_IS
};
/***
* Terminal type
***/
private
String
terminalType
=
null
;
/* TERMINAL-TYPE option (end)*/
/* open TelnetOptionHandler functionality (start)*/
/***
* Array of option handlers
***/
private
final
TelnetOptionHandler
optionHandlers
[];
/* open TelnetOptionHandler functionality (end)*/
/* Code Section added for supporting AYT (start)*/
/***
* AYT sequence
***/
static
final
byte
[]
_COMMAND_AYT
=
{
(
byte
)
TelnetCommand
.
IAC
,
(
byte
)
TelnetCommand
.
AYT
};
/***
* monitor to wait for AYT
***/
private
final
Object
aytMonitor
=
new
Object
();
/***
* flag for AYT
***/
private
volatile
boolean
aytFlag
=
true
;
/* Code Section added for supporting AYT (end)*/
/***
* The stream on which to spy
***/
private
volatile
OutputStream
spyStream
=
null
;
/***
* The notification handler
***/
private
TelnetNotificationHandler
__notifhand
=
null
;
/***
* Empty Constructor
***/
Telnet
()
{
setDefaultPort
(
DEFAULT_PORT
);
_doResponse
=
new
int
[
TelnetOption
.
MAX_OPTION_VALUE
+
1
];
_willResponse
=
new
int
[
TelnetOption
.
MAX_OPTION_VALUE
+
1
];
_options
=
new
int
[
TelnetOption
.
MAX_OPTION_VALUE
+
1
];
optionHandlers
=
new
TelnetOptionHandler
[
TelnetOption
.
MAX_OPTION_VALUE
+
1
];
}
/* TERMINAL-TYPE option (start)*/
/***
* This constructor lets you specify the terminal type.
*
* @param termtype - terminal type to be negotiated (ej. VT100)
***/
Telnet
(
String
termtype
)
{
setDefaultPort
(
DEFAULT_PORT
);
_doResponse
=
new
int
[
TelnetOption
.
MAX_OPTION_VALUE
+
1
];
_willResponse
=
new
int
[
TelnetOption
.
MAX_OPTION_VALUE
+
1
];
_options
=
new
int
[
TelnetOption
.
MAX_OPTION_VALUE
+
1
];
terminalType
=
termtype
;
optionHandlers
=
new
TelnetOptionHandler
[
TelnetOption
.
MAX_OPTION_VALUE
+
1
];
}
/* TERMINAL-TYPE option (end)*/
/***
* Looks for the state of the option.
*
* @return returns true if a will has been acknowledged
*
* @param option - option code to be looked up.
***/
boolean
_stateIsWill
(
int
option
)
{
return
((
_options
[
option
]
&
_WILL_MASK
)
!=
0
);
}
/***
* Looks for the state of the option.
*
* @return returns true if a wont has been acknowledged
*
* @param option - option code to be looked up.
***/
boolean
_stateIsWont
(
int
option
)
{
return
!
_stateIsWill
(
option
);
}
/***
* Looks for the state of the option.
*
* @return returns true if a do has been acknowledged
*
* @param option - option code to be looked up.
***/
boolean
_stateIsDo
(
int
option
)
{
return
((
_options
[
option
]
&
_DO_MASK
)
!=
0
);
}
/***
* Looks for the state of the option.
*
* @return returns true if a dont has been acknowledged
*
* @param option - option code to be looked up.
***/
boolean
_stateIsDont
(
int
option
)
{
return
!
_stateIsDo
(
option
);
}
/***
* Looks for the state of the option.
*
* @return returns true if a will has been reuqested
*
* @param option - option code to be looked up.
***/
boolean
_requestedWill
(
int
option
)
{
return
((
_options
[
option
]
&
_REQUESTED_WILL_MASK
)
!=
0
);
}
/***
* Looks for the state of the option.
*
* @return returns true if a wont has been reuqested
*
* @param option - option code to be looked up.
***/
boolean
_requestedWont
(
int
option
)
{
return
!
_requestedWill
(
option
);
}
/***
* Looks for the state of the option.
*
* @return returns true if a do has been reuqested
*
* @param option - option code to be looked up.
***/
boolean
_requestedDo
(
int
option
)
{
return
((
_options
[
option
]
&
_REQUESTED_DO_MASK
)
!=
0
);
}
/***
* Looks for the state of the option.
*
* @return returns true if a dont has been reuqested
*
* @param option - option code to be looked up.
***/
boolean
_requestedDont
(
int
option
)
{
return
!
_requestedDo
(
option
);
}
/***
* Sets the state of the option.
*
* @param option - option code to be set.
* @throws IOException
***/
void
_setWill
(
int
option
)
throws
IOException
{
_options
[
option
]
|=
_WILL_MASK
;
/* open TelnetOptionHandler functionality (start)*/
if
(
_requestedWill
(
option
))
{
if
(
optionHandlers
[
option
]
!=
null
)
{
optionHandlers
[
option
].
setWill
(
true
);
int
subneg
[]
=
optionHandlers
[
option
].
startSubnegotiationLocal
();
if
(
subneg
!=
null
)
{
_sendSubnegotiation
(
subneg
);
}
}
}
/* open TelnetOptionHandler functionality (end)*/
}
/***
* Sets the state of the option.
*
* @param option - option code to be set.
* @throws IOException
***/
void
_setDo
(
int
option
)
throws
IOException
{
_options
[
option
]
|=
_DO_MASK
;
/* open TelnetOptionHandler functionality (start)*/
if
(
_requestedDo
(
option
))
{
if
(
optionHandlers
[
option
]
!=
null
)
{
optionHandlers
[
option
].
setDo
(
true
);
int
subneg
[]
=
optionHandlers
[
option
].
startSubnegotiationRemote
();
if
(
subneg
!=
null
)
{
_sendSubnegotiation
(
subneg
);
}
}
}
/* open TelnetOptionHandler functionality (end)*/
}
/***
* Sets the state of the option.
*
* @param option - option code to be set.
***/
void
_setWantWill
(
int
option
)
{
_options
[
option
]
|=
_REQUESTED_WILL_MASK
;
}
/***
* Sets the state of the option.
*
* @param option - option code to be set.
***/
void
_setWantDo
(
int
option
)
{
_options
[
option
]
|=
_REQUESTED_DO_MASK
;
}
/***
* Sets the state of the option.
*
* @param option - option code to be set.
***/
void
_setWont
(
int
option
)
{
_options
[
option
]
&=
~
_WILL_MASK
;
/* open TelnetOptionHandler functionality (start)*/
if
(
optionHandlers
[
option
]
!=
null
)
{
optionHandlers
[
option
].
setWill
(
false
);
}
/* open TelnetOptionHandler functionality (end)*/
}
/***
* Sets the state of the option.
*
* @param option - option code to be set.
***/
void
_setDont
(
int
option
)
{
_options
[
option
]
&=
~
_DO_MASK
;
/* open TelnetOptionHandler functionality (start)*/
if
(
optionHandlers
[
option
]
!=
null
)
{
optionHandlers
[
option
].
setDo
(
false
);
}
/* open TelnetOptionHandler functionality (end)*/
}
/***
* Sets the state of the option.
*
* @param option - option code to be set.
***/
void
_setWantWont
(
int
option
)
{
_options
[
option
]
&=
~
_REQUESTED_WILL_MASK
;
}
/***
* Sets the state of the option.
*
* @param option - option code to be set.
***/
void
_setWantDont
(
int
option
)
{
_options
[
option
]
&=
~
_REQUESTED_DO_MASK
;
}
/**
* Processes a COMMAND.
*
* @param command - option code to be set.
**/
void
_processCommand
(
int
command
)
{
if
(
debugoptions
)
{
System
.
err
.
println
(
"RECEIVED COMMAND: "
+
command
);
}
if
(
__notifhand
!=
null
)
{
__notifhand
.
receivedNegotiation
(
TelnetNotificationHandler
.
RECEIVED_COMMAND
,
command
);
}
}
/**
* Processes a DO request.
*
* @param option - option code to be set.
* @throws IOException - Exception in I/O.
**/
void
_processDo
(
int
option
)
throws
IOException
{
if
(
debugoptions
)
{
System
.
err
.
println
(
"RECEIVED DO: "
+
TelnetOption
.
getOption
(
option
));
}
if
(
__notifhand
!=
null
)
{
__notifhand
.
receivedNegotiation
(
TelnetNotificationHandler
.
RECEIVED_DO
,
option
);
}
boolean
acceptNewState
=
false
;
/* open TelnetOptionHandler functionality (start)*/
if
(
optionHandlers
[
option
]
!=
null
)
{
acceptNewState
=
optionHandlers
[
option
].
getAcceptLocal
();
}
else
{
/* open TelnetOptionHandler functionality (end)*/
/* TERMINAL-TYPE option (start)*/
if
(
option
==
TERMINAL_TYPE
)
{
if
((
terminalType
!=
null
)
&&
(
terminalType
.
length
()
>
0
))
{
acceptNewState
=
true
;
}
}
/* TERMINAL-TYPE option (end)*/
/* open TelnetOptionHandler functionality (start)*/
}
/* open TelnetOptionHandler functionality (end)*/
if
(
_willResponse
[
option
]
>
0
)
{
--
_willResponse
[
option
];
if
(
_willResponse
[
option
]
>
0
&&
_stateIsWill
(
option
))
{
--
_willResponse
[
option
];
}
}
if
(
_willResponse
[
option
]
==
0
)
{
if
(
_requestedWont
(
option
))
{
switch
(
option
)
{
default
:
break
;
}
if
(
acceptNewState
)
{
_setWantWill
(
option
);
_sendWill
(
option
);
}
else
{
++
_willResponse
[
option
];
_sendWont
(
option
);
}
}
else
{
// Other end has acknowledged option.
switch
(
option
)
{
default
:
break
;
}
}
}
_setWill
(
option
);
}
/**
* Processes a DONT request.
*
* @param option - option code to be set.
* @throws IOException - Exception in I/O.
**/
void
_processDont
(
int
option
)
throws
IOException
{
if
(
debugoptions
)
{
System
.
err
.
println
(
"RECEIVED DONT: "
+
TelnetOption
.
getOption
(
option
));
}
if
(
__notifhand
!=
null
)
{
__notifhand
.
receivedNegotiation
(
TelnetNotificationHandler
.
RECEIVED_DONT
,
option
);
}
if
(
_willResponse
[
option
]
>
0
)
{
--
_willResponse
[
option
];
if
(
_willResponse
[
option
]
>
0
&&
_stateIsWont
(
option
))
{
--
_willResponse
[
option
];
}
}
if
(
_willResponse
[
option
]
==
0
&&
_requestedWill
(
option
))
{
switch
(
option
)
{
default
:
break
;
}
/* FIX for a BUG in the negotiation (start)*/
if
((
_stateIsWill
(
option
))
||
(
_requestedWill
(
option
)))
{
_sendWont
(
option
);
}
_setWantWont
(
option
);
/* FIX for a BUG in the negotiation (end)*/
}
_setWont
(
option
);
}
/**
* Processes a WILL request.
*
* @param option - option code to be set.
* @throws IOException - Exception in I/O.
**/
void
_processWill
(
int
option
)
throws
IOException
{
if
(
debugoptions
)
{
System
.
err
.
println
(
"RECEIVED WILL: "
+
TelnetOption
.
getOption
(
option
));
}
if
(
__notifhand
!=
null
)
{
__notifhand
.
receivedNegotiation
(
TelnetNotificationHandler
.
RECEIVED_WILL
,
option
);
}
boolean
acceptNewState
=
false
;
/* open TelnetOptionHandler functionality (start)*/
if
(
optionHandlers
[
option
]
!=
null
)
{
acceptNewState
=
optionHandlers
[
option
].
getAcceptRemote
();
}
/* open TelnetOptionHandler functionality (end)*/
if
(
_doResponse
[
option
]
>
0
)
{
--
_doResponse
[
option
];
if
(
_doResponse
[
option
]
>
0
&&
_stateIsDo
(
option
))
{
--
_doResponse
[
option
];
}
}
if
(
_doResponse
[
option
]
==
0
&&
_requestedDont
(
option
))
{
switch
(
option
)
{
default
:
break
;
}
if
(
acceptNewState
)
{
_setWantDo
(
option
);
_sendDo
(
option
);
}
else
{
++
_doResponse
[
option
];
_sendDont
(
option
);
}
}
_setDo
(
option
);
}
/**
* Processes a WONT request.
*
* @param option - option code to be set.
* @throws IOException - Exception in I/O.
**/
void
_processWont
(
int
option
)
throws
IOException
{
if
(
debugoptions
)
{
System
.
err
.
println
(
"RECEIVED WONT: "
+
TelnetOption
.
getOption
(
option
));
}
if
(
__notifhand
!=
null
)
{
__notifhand
.
receivedNegotiation
(
TelnetNotificationHandler
.
RECEIVED_WONT
,
option
);
}
if
(
_doResponse
[
option
]
>
0
)
{
--
_doResponse
[
option
];
if
(
_doResponse
[
option
]
>
0
&&
_stateIsDont
(
option
))
{
--
_doResponse
[
option
];
}
}
if
(
_doResponse
[
option
]
==
0
&&
_requestedDo
(
option
))
{
switch
(
option
)
{
default
:
break
;
}
/* FIX for a BUG in the negotiation (start)*/
if
((
_stateIsDo
(
option
))
||
(
_requestedDo
(
option
)))
{
_sendDont
(
option
);
}
_setWantDont
(
option
);
/* FIX for a BUG in the negotiation (end)*/
}
_setDont
(
option
);
}
/* TERMINAL-TYPE option (start)*/
/**
* Processes a suboption negotiation.
*
* @param suboption - subnegotiation data received
* @param suboptionLength - length of data received
* @throws IOException - Exception in I/O.
**/
void
_processSuboption
(
int
suboption
[],
int
suboptionLength
)
throws
IOException
{
if
(
debug
)
{
System
.
err
.
println
(
"PROCESS SUBOPTION."
);
}
/* open TelnetOptionHandler functionality (start)*/
if
(
suboptionLength
>
0
)
{
if
(
optionHandlers
[
suboption
[
0
]]
!=
null
)
{
int
responseSuboption
[]
=
optionHandlers
[
suboption
[
0
]].
answerSubnegotiation
(
suboption
,
suboptionLength
);
_sendSubnegotiation
(
responseSuboption
);
}
else
{
if
(
suboptionLength
>
1
)
{
if
(
debug
)
{
for
(
int
ii
=
0
;
ii
<
suboptionLength
;
ii
++)
{
System
.
err
.
println
(
"SUB["
+
ii
+
"]: "
+
suboption
[
ii
]);
}
}
if
((
suboption
[
0
]
==
TERMINAL_TYPE
)
&&
(
suboption
[
1
]
==
TERMINAL_TYPE_SEND
))
{
_sendTerminalType
();
}
}
}
}
/* open TelnetOptionHandler functionality (end)*/
}
/***
* Sends terminal type information.
*
* @throws IOException - Exception in I/O.
***/
final
synchronized
void
_sendTerminalType
()
throws
IOException
{
if
(
debug
)
{
System
.
err
.
println
(
"SEND TERMINAL-TYPE: "
+
terminalType
);
}
if
(
terminalType
!=
null
)
{
_output_
.
write
(
_COMMAND_SB
);
_output_
.
write
(
_COMMAND_IS
);
_output_
.
write
(
terminalType
.
getBytes
(
getCharset
()));
_output_
.
write
(
_COMMAND_SE
);
_output_
.
flush
();
}
}
/* TERMINAL-TYPE option (end)*/
/* open TelnetOptionHandler functionality (start)*/
/**
* Manages subnegotiation for Terminal Type.
*
* @param subn - subnegotiation data to be sent
* @throws IOException - Exception in I/O.
**/
final
synchronized
void
_sendSubnegotiation
(
int
subn
[])
throws
IOException
{
if
(
debug
)
{
System
.
err
.
println
(
"SEND SUBNEGOTIATION: "
);
if
(
subn
!=
null
)
{
System
.
err
.
println
(
Arrays
.
toString
(
subn
));
}
}
if
(
subn
!=
null
)
{
_output_
.
write
(
_COMMAND_SB
);
// Note _output_ is buffered, so might as well simplify by writing single bytes
for
(
int
element
:
subn
)
{
byte
b
=
(
byte
)
element
;
if
(
b
==
(
byte
)
TelnetCommand
.
IAC
)
{
// cast is necessary because IAC is outside the signed byte range
_output_
.
write
(
b
);
// double any IAC bytes
}
_output_
.
write
(
b
);
}
_output_
.
write
(
_COMMAND_SE
);
/* Code Section added for sending the negotiation ASAP (start)*/
_output_
.
flush
();
/* Code Section added for sending the negotiation ASAP (end)*/
}
}
/* open TelnetOptionHandler functionality (end)*/
/**
* Sends a command, automatically adds IAC prefix and flushes the output.
*
* @param cmd - command data to be sent
* @throws IOException - Exception in I/O.
* @since 3.0
*/
final
synchronized
void
_sendCommand
(
byte
cmd
)
throws
IOException
{
_output_
.
write
(
TelnetCommand
.
IAC
);
_output_
.
write
(
cmd
);
_output_
.
flush
();
}
/* Code Section added for supporting AYT (start)*/
/***
* Processes the response of an AYT
***/
final
synchronized
void
_processAYTResponse
()
{
if
(!
aytFlag
)
{
synchronized
(
aytMonitor
)
{
aytFlag
=
true
;
aytMonitor
.
notifyAll
();
}
}
}
/* Code Section added for supporting AYT (end)*/
/***
* Called upon connection.
*
* @throws IOException - Exception in I/O.
***/
@Override
protected
void
_connectAction_
()
throws
IOException
{
/* (start). BUGFIX: clean the option info for each connection*/
for
(
int
ii
=
0
;
ii
<
TelnetOption
.
MAX_OPTION_VALUE
+
1
;
ii
++)
{
_doResponse
[
ii
]
=
0
;
_willResponse
[
ii
]
=
0
;
_options
[
ii
]
=
0
;
if
(
optionHandlers
[
ii
]
!=
null
)
{
optionHandlers
[
ii
].
setDo
(
false
);
optionHandlers
[
ii
].
setWill
(
false
);
}
}
/* (end). BUGFIX: clean the option info for each connection*/
super
.
_connectAction_
();
_input_
=
new
BufferedInputStream
(
_input_
);
_output_
=
new
BufferedOutputStream
(
_output_
);
/* open TelnetOptionHandler functionality (start)*/
for
(
int
ii
=
0
;
ii
<
TelnetOption
.
MAX_OPTION_VALUE
+
1
;
ii
++)
{
if
(
optionHandlers
[
ii
]
!=
null
)
{
if
(
optionHandlers
[
ii
].
getInitLocal
())
{
_requestWill
(
optionHandlers
[
ii
].
getOptionCode
());
}
if
(
optionHandlers
[
ii
].
getInitRemote
())
{
_requestDo
(
optionHandlers
[
ii
].
getOptionCode
());
}
}
}
/* open TelnetOptionHandler functionality (end)*/
}
/**
* Sends a DO.
*
* @param option - Option code.
* @throws IOException - Exception in I/O.
**/
final
synchronized
void
_sendDo
(
int
option
)
throws
IOException
{
if
(
debug
||
debugoptions
)
{
System
.
err
.
println
(
"DO: "
+
TelnetOption
.
getOption
(
option
));
}
_output_
.
write
(
_COMMAND_DO
);
_output_
.
write
(
option
);
/* Code Section added for sending the negotiation ASAP (start)*/
_output_
.
flush
();
/* Code Section added for sending the negotiation ASAP (end)*/
}
/**
* Requests a DO.
*
* @param option - Option code.
* @throws IOException - Exception in I/O.
**/
final
synchronized
void
_requestDo
(
int
option
)
throws
IOException
{
if
((
_doResponse
[
option
]
==
0
&&
_stateIsDo
(
option
))
||
_requestedDo
(
option
))
{
return
;
}
_setWantDo
(
option
);
++
_doResponse
[
option
];
_sendDo
(
option
);
}
/**
* Sends a DONT.
*
* @param option - Option code.
* @throws IOException - Exception in I/O.
**/
final
synchronized
void
_sendDont
(
int
option
)
throws
IOException
{
if
(
debug
||
debugoptions
)
{
System
.
err
.
println
(
"DONT: "
+
TelnetOption
.
getOption
(
option
));
}
_output_
.
write
(
_COMMAND_DONT
);
_output_
.
write
(
option
);
/* Code Section added for sending the negotiation ASAP (start)*/
_output_
.
flush
();
/* Code Section added for sending the negotiation ASAP (end)*/
}
/**
* Requests a DONT.
*
* @param option - Option code.
* @throws IOException - Exception in I/O.
**/
final
synchronized
void
_requestDont
(
int
option
)
throws
IOException
{
if
((
_doResponse
[
option
]
==
0
&&
_stateIsDont
(
option
))
||
_requestedDont
(
option
))
{
return
;
}
_setWantDont
(
option
);
++
_doResponse
[
option
];
_sendDont
(
option
);
}
/**
* Sends a WILL.
*
* @param option - Option code.
* @throws IOException - Exception in I/O.
**/
final
synchronized
void
_sendWill
(
int
option
)
throws
IOException
{
if
(
debug
||
debugoptions
)
{
System
.
err
.
println
(
"WILL: "
+
TelnetOption
.
getOption
(
option
));
}
_output_
.
write
(
_COMMAND_WILL
);
_output_
.
write
(
option
);
/* Code Section added for sending the negotiation ASAP (start)*/
_output_
.
flush
();
/* Code Section added for sending the negotiation ASAP (end)*/
}
/**
* Requests a WILL.
*
* @param option - Option code.
* @throws IOException - Exception in I/O.
**/
final
synchronized
void
_requestWill
(
int
option
)
throws
IOException
{
if
((
_willResponse
[
option
]
==
0
&&
_stateIsWill
(
option
))
||
_requestedWill
(
option
))
{
return
;
}
_setWantWill
(
option
);
++
_doResponse
[
option
];
_sendWill
(
option
);
}
/**
* Sends a WONT.
*
* @param option - Option code.
* @throws IOException - Exception in I/O.
**/
final
synchronized
void
_sendWont
(
int
option
)
throws
IOException
{
if
(
debug
||
debugoptions
)
{
System
.
err
.
println
(
"WONT: "
+
TelnetOption
.
getOption
(
option
));
}
_output_
.
write
(
_COMMAND_WONT
);
_output_
.
write
(
option
);
/* Code Section added for sending the negotiation ASAP (start)*/
_output_
.
flush
();
/* Code Section added for sending the negotiation ASAP (end)*/
}
/**
* Requests a WONT.
*
* @param option - Option code.
* @throws IOException - Exception in I/O.
**/
final
synchronized
void
_requestWont
(
int
option
)
throws
IOException
{
if
((
_willResponse
[
option
]
==
0
&&
_stateIsWont
(
option
))
||
_requestedWont
(
option
))
{
return
;
}
_setWantWont
(
option
);
++
_doResponse
[
option
];
_sendWont
(
option
);
}
/**
* Sends a byte.
*
* @param b - byte to send
* @throws IOException - Exception in I/O.
**/
final
synchronized
void
_sendByte
(
int
b
)
throws
IOException
{
_output_
.
write
(
b
);
/* Code Section added for supporting spystreams (start)*/
_spyWrite
(
b
);
/* Code Section added for supporting spystreams (end)*/
}
/* Code Section added for supporting AYT (start)*/
/**
* Sends an Are You There sequence and waits for the result.
*
* @param timeout - Time to wait for a response (millis.)
* @throws IOException - Exception in I/O.
* @throws IllegalArgumentException - Illegal argument
* @throws InterruptedException - Interrupted during wait.
* @return true if AYT received a response, false otherwise
**/
final
boolean
_sendAYT
(
long
timeout
)
throws
IOException
,
IllegalArgumentException
,
InterruptedException
{
boolean
retValue
=
false
;
synchronized
(
aytMonitor
)
{
synchronized
(
this
)
{
aytFlag
=
false
;
_output_
.
write
(
_COMMAND_AYT
);
_output_
.
flush
();
}
aytMonitor
.
wait
(
timeout
);
if
(!
aytFlag
)
{
retValue
=
false
;
aytFlag
=
true
;
}
else
{
retValue
=
true
;
}
}
return
(
retValue
);
}
/* Code Section added for supporting AYT (end)*/
/* open TelnetOptionHandler functionality (start)*/
/**
* Registers a new TelnetOptionHandler for this telnet to use.
*
* @param opthand - option handler to be registered.
* @throws InvalidTelnetOptionException - The option code is invalid.
* @throws IOException on error
**/
void
addOptionHandler
(
TelnetOptionHandler
opthand
)
throws
InvalidTelnetOptionException
,
IOException
{
int
optcode
=
opthand
.
getOptionCode
();
if
(
TelnetOption
.
isValidOption
(
optcode
))
{
if
(
optionHandlers
[
optcode
]
==
null
)
{
optionHandlers
[
optcode
]
=
opthand
;
if
(
isConnected
())
{
if
(
opthand
.
getInitLocal
())
{
_requestWill
(
optcode
);
}
if
(
opthand
.
getInitRemote
())
{
_requestDo
(
optcode
);
}
}
}
else
{
throw
(
new
InvalidTelnetOptionException
(
"Already registered option"
,
optcode
));
}
}
else
{
throw
(
new
InvalidTelnetOptionException
(
"Invalid Option Code"
,
optcode
));
}
}
/**
* Unregisters a TelnetOptionHandler.
*
* @param optcode - Code of the option to be unregistered.
* @throws InvalidTelnetOptionException - The option code is invalid.
* @throws IOException on error
**/
void
deleteOptionHandler
(
int
optcode
)
throws
InvalidTelnetOptionException
,
IOException
{
if
(
TelnetOption
.
isValidOption
(
optcode
))
{
if
(
optionHandlers
[
optcode
]
==
null
)
{
throw
(
new
InvalidTelnetOptionException
(
"Unregistered option"
,
optcode
));
}
else
{
TelnetOptionHandler
opthand
=
optionHandlers
[
optcode
];
optionHandlers
[
optcode
]
=
null
;
if
(
opthand
.
getWill
())
{
_requestWont
(
optcode
);
}
if
(
opthand
.
getDo
())
{
_requestDont
(
optcode
);
}
}
}
else
{
throw
(
new
InvalidTelnetOptionException
(
"Invalid Option Code"
,
optcode
));
}
}
/* open TelnetOptionHandler functionality (end)*/
/* Code Section added for supporting spystreams (start)*/
/***
* Registers an OutputStream for spying what's going on in
* the Telnet session.
*
* @param spystream - OutputStream on which session activity
* will be echoed.
***/
void
_registerSpyStream
(
OutputStream
spystream
)
{
spyStream
=
spystream
;
}
/***
* Stops spying this Telnet.
*
***/
void
_stopSpyStream
()
{
spyStream
=
null
;
}
/***
* Sends a read char on the spy stream.
*
* @param ch - character read from the session
***/
void
_spyRead
(
int
ch
)
{
OutputStream
spy
=
spyStream
;
if
(
spy
!=
null
)
{
try
{
if
(
ch
!=
'\r'
)
// never write '\r' on its own
{
if
(
ch
==
'\n'
)
{
spy
.
write
(
'\r'
);
// add '\r' before '\n'
}
spy
.
write
(
ch
);
// write original character
spy
.
flush
();
}
}
catch
(
IOException
e
)
{
spyStream
=
null
;
}
}
}
/***
* Sends a written char on the spy stream.
*
* @param ch - character written to the session
***/
void
_spyWrite
(
int
ch
)
{
if
(!(
_stateIsDo
(
TelnetOption
.
ECHO
)
&&
_requestedDo
(
TelnetOption
.
ECHO
)))
{
OutputStream
spy
=
spyStream
;
if
(
spy
!=
null
)
{
try
{
spy
.
write
(
ch
);
spy
.
flush
();
}
catch
(
IOException
e
)
{
spyStream
=
null
;
}
}
}
}
/* Code Section added for supporting spystreams (end)*/
/***
* Registers a notification handler to which will be sent
* notifications of received telnet option negotiation commands.
*
* @param notifhand - TelnetNotificationHandler to be registered
***/
public
void
registerNotifHandler
(
TelnetNotificationHandler
notifhand
)
{
__notifhand
=
notifhand
;
}
/***
* Unregisters the current notification handler.
*
***/
public
void
unregisterNotifHandler
()
{
__notifhand
=
null
;
}
}
Prev
1
2
3
4
5
6
7
8
9
…
19
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment