jtopenlite.com.ibm.jtopenlite.HostServerConnection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400-jdk9 Show documentation
Show all versions of jt400-jdk9 Show documentation
The Open Source version of the IBM Toolbox for Java
///////////////////////////////////////////////////////////////////////////////
//
// JTOpenLite
//
// Filename: HostServerConnection.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 2011-2012 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.jtopenlite;
import java.io.*;
import java.net.Socket;
import java.text.*;
/**
* Represents a TCP/IP socket connection to an IBM i Host Server job. All
* HostServerConnections have associated system information provided via the
* SystemInfo class.
**/
public abstract class HostServerConnection implements Connection {
private final SystemInfo info_;
private final String user_;
private final String jobName_;
private boolean closed_ = false;
private final Socket socket_;
protected final HostInputStream in_;
protected final HostOutputStream out_;
protected HostServerConnection(SystemInfo info, String user,
String jobName, Socket socket, HostInputStream in,
HostOutputStream out) {
info_ = info;
user_ = user;
jobName_ = jobName;
socket_ = socket;
in_ = in;
out_ = out;
}
/**
* Returns true if debugging is enabled by default for all
* HostServerConnection datastreams.
**/
public static boolean isDefaultDatastreamDebug() {
return Trace.isStreamTracingEnabled();
}
/**
* If debug is true, enables by default debugging on all
* HostServerConnection datastreams created after the call to this method.
**/
public static void setDefaultDatastreamDebug(boolean debug) {
HostInputStream.setAllDebug(debug);
HostOutputStream.setAllDebug(debug);
}
/**
* Returns the total number of bytes this connection has read since it was
* opened. If an I/O exception has occurred with this stream, the number
* returned by this method may not reflect any partial datastream bytes that
* may have actually been read before the exception took place.
**/
public long getBytesReceived() {
return in_.getBytesReceived();
}
/**
* Returns the total number of bytes this connection has written since it was opened.
* If an I/O exception has occurred with this stream, the number returned by this method
* may not reflect any partial datastream bytes that may have actually been written before
* the exception took place. Additionally, the number of bytes written over the TCP socket
* may be less, if the underlying stream has not yet been flushed.
**/
public long getBytesSent()
{
return out_.getBytesSent();
}
/**
* Returns true if datastream debugging is currently enabled.
**/
public boolean isDatastreamDebug() {
return in_.debug_;
}
/**
* If debug is true, enables datastream debugging for this
* connection.
**/
public void setDatastreamDebug(boolean debug) {
in_.setDebug(debug);
out_.setDebug(debug);
}
/**
* Sends an "end job" datastream (if supported) and closes the underlying
* socket.
**/
public final void close() throws IOException {
if (closed_)
return;
try {
sendEndJobRequest();
} finally {
closed_ = true;
forceClose();
}
}
protected abstract void sendEndJobRequest() throws IOException;
private void forceClose() throws IOException {
IOException rethrownException = null;
try {
in_.close();
out_.close();
} catch (java.net.SocketException socketException) {
if (socketException.toString().indexOf("Socket closed") >= 0) {
// Ignore this exception
} else {
rethrownException = socketException;
throw rethrownException;
}
} finally {
try {
socket_.close();
} catch (java.net.SocketException socketException) {
if (socketException.toString().indexOf("Socket closed") >= 0) {
// Ignore this exception
} else {
// Only throw an exception if one has not yet been thrown.
if (rethrownException == null) {
throw socketException;
}
}
}
}
}
protected final void finalize() throws Throwable {
close();
}
/**
* Returns true if close() has been called on this connection.
**/
public final boolean isClosed() {
return closed_;
}
/**
* Returns the system information associated with this connection.
**/
public final SystemInfo getInfo() {
return info_;
}
/**
* Returns the currently authenticated user of this connection.
**/
public final String getUser() {
return user_;
}
/**
* Returns the host server job string for the job that is connected to this
* connection.
**/
public final String getJobName() {
return jobName_;
}
protected static byte[] getEncryptedPassword(byte[] userBytes,
byte[] passwordBytes, byte[] clientSeed, byte[] serverSeed,
int passwordLevel) throws IOException {
final boolean doSHAInsteadOfDES = passwordLevel >= 2;
byte[] encryptedPassword = null;
if (doSHAInsteadOfDES)
{
encryptedPassword = EncryptPassword.encryptPasswordSHA(userBytes, passwordBytes, clientSeed, serverSeed);
}
else
{
// Normal DES encryption.
encryptedPassword = EncryptPassword.encryptPasswordDES(userBytes,
passwordBytes, clientSeed, serverSeed);
}
return encryptedPassword;
}
protected static String connect(SystemInfo info, HostOutputStream dout,
HostInputStream din, int serverID, String user, String password)
throws IOException {
// Exchange random seeds.
long seed = sendExchangeRandomSeedsRequest(dout, serverID);
byte[] clientSeed = Conv.longToByteArray(seed);
dout.flush();
int length = din.readInt();
if (length < 20) {
throw DataStreamException.badLength("exchangeRandomSeeds-"
+ serverID, length);
}
din.skipBytes(16);
int rc = din.readInt();
if (rc != 0) {
throw DataStreamException.badReturnCode("exchangeRandomSeeds-"
+ serverID, rc);
}
byte[] serverSeed = new byte[8];
din.readFully(serverSeed);
byte[] userBytes = getUserBytes(user, info.getPasswordLevel());
byte[] passwordBytes = getPasswordBytes(password, info.getPasswordLevel());
password = null;
byte[] encryptedPassword = getEncryptedPassword(userBytes, passwordBytes,
clientSeed, serverSeed, info.getPasswordLevel());
din.end();
byte[] userEBCDICBytes = (info.getPasswordLevel() < 2) ? userBytes : getUserBytes(user, 0);
sendStartServerRequest(dout, userEBCDICBytes, encryptedPassword, serverID);
dout.flush();
length = din.readInt();
if (length < 20) {
throw DataStreamException.badLength("startServer-" + serverID,
length);
}
din.skipBytes(16);
rc = din.readInt();
if (rc != 0) {
String msg = getReturnCodeMessage(rc);
throw msg == null ? DataStreamException.badReturnCode(
"startServer-" + serverID, rc) : DataStreamException
.errorMessage("startServer-" + serverID, new Message(String
.valueOf(rc), msg));
}
String jobName = null;
int remaining = length - 24;
while (remaining > 10) {
int ll = din.readInt();
int cp = din.readShort();
remaining -= 6;
if (cp == 0x111F) // Job name.
{
din.skipBytes(4); // CCSID is always 0.
remaining -= 4;
int jobLength = ll - 10;
byte[] jobBytes = new byte[jobLength];
din.readFully(jobBytes);
jobName = Conv.ebcdicByteArrayToString(jobBytes, 0, jobLength);
remaining -= jobLength;
} else {
din.skipBytes(ll - 6);
remaining -= (ll - 6);
}
}
din.skipBytes(remaining);
din.end();
return jobName;
}
private static String getReturnCodeMessage(int rc) {
if ((rc & 0xFFFF0000) == 0x00010000)
return "Error on request data";
if ((rc & 0xFFFF0000) == 0x00040000)
return "General security error, function not performed";
if ((rc & 0xFFFF0000) == 0x00060000)
return "Authentication Token error";
switch (rc) {
case 0x00020001:
return "Userid error: User Id unknown";
case 0x00020002:
return "Userid error: User Id valid, but revoked";
case 0x00020003:
return "Userid error: User Id mismatch with authentication token";
case 0x0003000B:
return "Password error: Password or Passphrase incorrect";
case 0x0003000C:
return "Password error: User profile will be revoked on next invalid password or passphrase";
case 0x0003000D:
return "Password error: Password or Passphrase correct, but expired";
case 0x0003000E:
return "Password error: Pre-V2R2 encrypted password";
case 0x00030010:
return "Password error: Password is *NONE";
}
return null;
}
static void sendStartServerRequest(HostOutputStream out, byte[] userBytes,
byte[] encryptedPassword, int serverID) throws IOException {
out.writeInt(44 + encryptedPassword.length);
out.writeByte(2); // Client attributes, 2 means return job info.
out.writeByte(0); // Server attribute.
out.writeShort(serverID); // Server ID.
out.writeInt(0); // CS instance.
out.writeInt(0); // Correlation ID.
out.writeShort(2); // Template length.
out.writeShort(0x7002); // ReqRep ID.
out.writeByte(encryptedPassword.length == 8 ? 1 : 3); // Password
// encryption
// type.
out.writeByte(1); // Send reply.
out.writeInt(6 + encryptedPassword.length); // Password LL.
out.writeShort(0x1105); // Password CP. 0x1115 is other.
out.write(encryptedPassword);
out.writeInt(16); // User ID LL.
out.writeShort(0x1104); // User ID CP.
out.write(userBytes);
}
static long sendExchangeRandomSeedsRequest(HostOutputStream out,
int serverID) throws IOException {
out.writeInt(28); // Length.
out.writeByte(1); // Client attributes, 1 means capable of SHA-1.
out.writeByte(0); // Server attributes.
out.writeShort(serverID); // Server ID.
out.writeInt(0); // CS instance.
out.writeInt(0); // Correlation ID.
out.writeShort(8); // Template length.
out.writeShort(0x7001); // ReqRep ID.
long clientSeed = System.currentTimeMillis();
out.writeLong(clientSeed);
return clientSeed;
}
static byte[] getUserBytes(String user, int level) throws IOException
{
if (level < 2)
{
if (user.length() > 10)
{
throw new IOException("User too long");
}
byte[] user37 = Conv.blankPadEBCDIC10(user.toUpperCase());
return user37;
}
else
{
byte[] b = new byte[20];
Conv.stringToBlankPadUnicodeByteArray(user.toUpperCase(), b, 0, 20);
return b;
}
}
static byte[] getPasswordBytes(String password, int level) throws IOException
{
if (level < 2)
{
// Prepend a Q to numeric password.
if (password.length() > 0 && Character.isDigit(password.charAt(0)))
{
password = "Q" + password;
}
if (password.length() > 10)
{
throw new IOException("Password too long");
}
byte[] password37 = Conv.blankPadEBCDIC10(password.toUpperCase());
return password37;
}
else
{
return Conv.stringToUnicodeByteArray(password);
}
}
protected static final class HostInputStream {
private static boolean allDebug_ = false;
private final InputStream in_;
private boolean debug_;
private int debugCounter_ = 0;
private final byte[] shortArray_ = new byte[2];
private final byte[] intArray_ = new byte[4];
private final byte[] longArray_ = new byte[8];
private PrintStream tracePrintStream = null;
private long bytesReceivedAtLastReset_ = 0;
private long latestBytesReceived_ = 0;
public static void setAllDebug(boolean debug)
{
allDebug_ = debug;
}
public HostInputStream(InputStream in) {
in_ = in;
debug_ = Trace.isStreamTracingEnabled();
if (debug_ || allDebug_ ) {
tracePrintStream = Trace.getPrintStream();
if (tracePrintStream == null) {
tracePrintStream = System.out;
}
}
}
public void resetLatestBytesReceived() {
bytesReceivedAtLastReset_ += latestBytesReceived_;
latestBytesReceived_ = 0;
}
public long getLatestBytesReceived() {
return latestBytesReceived_;
}
public long getBytesReceived() {
return bytesReceivedAtLastReset_ +latestBytesReceived_;
}
public void setDebug(boolean debug) {
debug_ = debug;
if (debug_) {
tracePrintStream = Trace.getPrintStream();
}
}
private void debugByte(int i) {
if (tracePrintStream != null) {
if (debugCounter_ == 0) {
synchronized (HostOutputStream.formatter_) {
tracePrintStream.print(HostOutputStream.formatter_
.format(new java.util.Date()));
tracePrintStream
.println(" Data stream data received...");
}
}
int highNibble = (0x00FF & i) >> 4;
int lowNibble = 0x000F & i;
tracePrintStream.print(HostOutputStream.CHAR[highNibble]);
tracePrintStream.print(HostOutputStream.CHAR[lowNibble]);
if (++debugCounter_ % 16 == 0)
tracePrintStream.println();
else
tracePrintStream.print(" ");
}
}
private void debugBytes(byte[] b, int offset, int length) {
for (int i = offset; i < offset + length; ++i) {
debugByte(b[i]);
}
}
/**
* Used to note the end of a datastream when debugging is enabled.
**/
public void end() {
if (debug_ && tracePrintStream != null) {
tracePrintStream.println();
debugCounter_ = 0;
}
}
public int read() throws IOException {
int i = in_.read();
if (i < 0) {
throw new EOFException();
}
if (debug_) {
debugByte(i);
}
++latestBytesReceived_;
return i;
}
public int readByte() throws IOException {
return read();
}
public int readShort() throws IOException {
int i = in_.read(shortArray_);
if (i != 2) {
int numRead = (i >= 0 ? i : 0);
latestBytesReceived_ += numRead;
while (i >= 0 && numRead < 2) {
i = in_.read(shortArray_, numRead, 2 - numRead);
numRead += (i >= 0 ? i : 0);
latestBytesReceived_ += numRead;
}
if (numRead < 2) {
throw new EOFException();
}
} else {
latestBytesReceived_ += 2;
}
if (debug_) {
debugBytes(shortArray_, 0, 2);
}
return ((shortArray_[0] & 0x00FF) << 8) | (shortArray_[1] & 0x00FF);
}
public int readInt() throws IOException {
int i = in_.read(intArray_);
if (i != 4) {
int numRead = (i >= 0 ? i : 0);
latestBytesReceived_ += numRead;
while (i >= 0 && numRead < 4) {
i = in_.read(intArray_, numRead, 4 - numRead);
numRead += (i >= 0 ? i : 0);
latestBytesReceived_ += numRead;
}
if (numRead < 4) {
throw new EOFException();
}
} else {
latestBytesReceived_ += 4;
}
if (debug_) {
debugBytes(intArray_, 0, 4);
}
return Conv.byteArrayToInt(intArray_, 0);
}
public long readLong() throws IOException {
int i = in_.read(longArray_);
if (i != 8) {
int numRead = (i >= 0 ? i : 0);
latestBytesReceived_ += numRead;
while (i >= 0 && numRead < 8) {
i = in_.read(longArray_, numRead, 8 - numRead);
numRead += (i >= 0 ? i : 0);
latestBytesReceived_ += numRead;
}
if (numRead < 8) {
throw new EOFException();
}
} else {
latestBytesReceived_ += 8;
}
if (debug_) {
debugBytes(longArray_, 0, 8);
}
return Conv.byteArrayToLong(longArray_, 0);
}
public int skipBytes(final int n) throws IOException {
if (debug_) {
int num = 0;
while (num < n) {
read();
++num;
}
return num;
}
int i = (int) in_.skip(n);
if (i != n) {
int numSkipped = (i >= 0 ? i : 0);
latestBytesReceived_ += numSkipped;
while (i >= 0 && numSkipped < n) {
i = (int) in_.skip(n - numSkipped);
numSkipped += (i >= 0 ? i : 0);
latestBytesReceived_ += numSkipped;
}
if (numSkipped < n) {
throw new EOFException();
}
} else {
latestBytesReceived_ += n;
}
return i;
}
public void close() throws IOException {
in_.close();
if (debug_ && tracePrintStream != null) {
tracePrintStream.println();
debugCounter_ = 0;
}
}
public void readFully(final byte[] b) throws IOException {
int i = in_.read(b);
if (i != b.length) {
int numRead = (i >= 0 ? i : 0);
latestBytesReceived_ += numRead;
while (i >= 0 && numRead < b.length) {
i = in_.read(b, numRead, b.length - numRead);
numRead += (i >= 0 ? i : 0);
latestBytesReceived_ += numRead;
}
if (numRead < b.length) {
throw new EOFException();
}
} else {
latestBytesReceived_ += i;
}
if (debug_) {
debugBytes(b, 0, b.length);
}
}
public void readFully(final byte[] b, final int offset, final int length)
throws IOException {
int i = in_.read(b, offset, length);
if (i != length) {
int numRead = (i >= 0 ? i : 0);
latestBytesReceived_ += numRead;
while (i >= 0 && numRead < length) {
i = in_.read(b, offset + numRead, length - numRead);
numRead += (i >= 0 ? i : 0);
latestBytesReceived_ += numRead;
}
if (numRead < length) {
throw new EOFException();
}
} else {
latestBytesReceived_ += length;
}
if (debug_) {
debugBytes(b, offset, length);
}
}
};
protected static final class HostOutputStream {
static SimpleDateFormat formatter_ = new SimpleDateFormat(
"EEE MMM d HH:mm:ss:SSS z yyyy");
static final char[] CHAR = new char[] { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
private static boolean allDebug_ = false;
private final OutputStream out_;
private boolean debug_;
private int debugCounter_ = 0;
private int bytesSent_ = 0;
private PrintStream tracePrintStream = null;
public static void setAllDebug(boolean debug)
{
allDebug_ = debug;
}
public long getBytesSent() {
return bytesSent_;
}
public HostOutputStream(final OutputStream out) {
out_ = out;
debug_ = Trace.isStreamTracingEnabled();
if (debug_ || allDebug_) {
tracePrintStream = Trace.getPrintStream();
if (tracePrintStream == null) {
tracePrintStream=System.out;
}
}
}
public void setDebug(boolean debug) {
debug_ = debug;
if (debug_) {
tracePrintStream = Trace.getPrintStream();
}
}
public void writeInt(final int i) throws IOException {
out_.write(i >> 24);
out_.write(i >> 16);
out_.write(i >> 8);
out_.write(i);
bytesSent_ += 4;
if (debug_) {
debugInt(i);
}
}
private void debugInt(int i) {
debugByte(i >> 24);
debugByte(i >> 16);
debugByte(i >> 8);
debugByte(i);
}
private void debugShort(int i) {
debugByte(i >> 8);
debugByte(i);
}
private void debugByte(int i) {
if (tracePrintStream != null) {
if (debugCounter_ == 0) {
synchronized (formatter_) {
tracePrintStream.print(formatter_
.format(new java.util.Date()));
tracePrintStream.println(" Data stream sent...");
}
}
int highNibble = (0x00FF & i) >> 4;
int lowNibble = 0x000F & i;
tracePrintStream.print(CHAR[highNibble]);
tracePrintStream.print(CHAR[lowNibble]);
if (++debugCounter_ % 16 == 0)
tracePrintStream.println();
else
tracePrintStream.print(" ");
}
}
private void debugBytes(byte[] b, int offset, int length) {
for (int i = offset; i < offset + length; ++i) {
debugByte(b[i]);
}
}
public void writeShort(final int i) throws IOException {
out_.write(i >> 8);
out_.write(i);
bytesSent_ += 2;
if (debug_) {
debugShort(i);
}
}
public void writeLong(final long l) throws IOException {
int i1 = (int) (l >> 32);
int i2 = (int) l;
writeInt(i1);
writeInt(i2);
}
public void write(final byte[] b) throws IOException {
out_.write(b, 0, b.length);
bytesSent_ += b.length;
if (debug_) {
debugBytes(b, 0, b.length);
}
}
public void write(final byte[] b, final int offset, final int length)
throws IOException {
out_.write(b, offset, length);
bytesSent_ += length;
if (debug_) {
debugBytes(b, offset, length);
}
}
public void write(final int i) throws IOException {
out_.write(i);
++bytesSent_;
if (debug_) {
debugByte(i);
}
}
public void writeByte(final int i) throws IOException {
out_.write(i);
++bytesSent_;
if (debug_) {
debugByte(i);
}
}
public void close() throws IOException {
out_.close();
if (debug_ && tracePrintStream != null) {
tracePrintStream.println();
debugCounter_ = 0;
}
}
public void flush() throws IOException {
out_.flush();
if (debug_ && tracePrintStream != null) {
tracePrintStream.println();
debugCounter_ = 0;
}
}
}
protected static void writePadEBCDIC10(String s, HostOutputStream out)
throws IOException {
Conv.writePadEBCDIC10(s, out);
}
protected static void writePadEBCDIC(String s, int len, HostOutputStream out)
throws IOException {
Conv.writePadEBCDIC(s, len, out);
}
protected static void writeStringToUnicodeBytes(String s,
HostOutputStream out) throws IOException {
Conv.writeStringToUnicodeBytes(s, out);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy