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 Show documentation
Show all versions of jt400 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