Obex library cleanup, third pass

- Change variable namings
- Remove interface public modifier
- Move 2 duplicate methods to ObexSession
- Removed unused code and variables
- Use static variables for some protocol defines
This commit is contained in:
Tao Liejun
2009-07-02 19:29:09 +08:00
committed by Nick Pelly
parent d719890cab
commit 3998bf009a
17 changed files with 1120 additions and 1397 deletions

View File

@@ -37,9 +37,11 @@ package javax.obex;
*/
public final class ApplicationParameter {
private byte[] b_array;
private int length;
private int max_length = 1000;
private byte[] mArray;
private int mLength;
private int mMaxLength = 1000;
public static class TRIPLET_TAGID {
public static final byte ORDER_TAGID = 0x01;
@@ -91,7 +93,6 @@ public final class ApplicationParameter {
public static class TRIPLET_LENGTH {
public static final byte ORDER_LENGTH = 1;
//public final byte SEARCH_VALUE_LENGTH = 0x02;
public static final byte SEARCH_ATTRIBUTE_LENGTH = 1;
public static final byte MAXLISTCOUNT_LENGTH = 2;
@@ -107,34 +108,27 @@ public final class ApplicationParameter {
public static final byte NEWMISSEDCALLS_LENGTH = 1;
}
/*
public class TRIPLET_STRUCTURE{
TRIPLET_TAGID id;
TRIPLET_LENGTH length;
byte[] value;
}
*/
public ApplicationParameter() {
b_array = new byte[max_length];
length = 0;
mArray = new byte[mMaxLength];
mLength = 0;
}
public void addAPPHeader(byte tag, byte len, byte[] value) {
if ((length + len + 2) > max_length) {
byte[] array_tmp = new byte[length + 4 * len];
System.arraycopy(b_array, 0, array_tmp, 0, length);
b_array = array_tmp;
max_length = length + 4 * len;
if ((mLength + len + 2) > mMaxLength) {
byte[] array_tmp = new byte[mLength + 4 * len];
System.arraycopy(mArray, 0, array_tmp, 0, mLength);
mArray = array_tmp;
mMaxLength = mLength + 4 * len;
}
b_array[length++] = tag;
b_array[length++] = len;
System.arraycopy(value, 0, b_array, length, len);
length += len;
mArray[mLength++] = tag;
mArray[mLength++] = len;
System.arraycopy(value, 0, mArray, mLength, len);
mLength += len;
}
public byte[] getAPPparam() {
byte[] para = new byte[length];
System.arraycopy(b_array, 0, para, 0, length);
byte[] para = new byte[mLength];
System.arraycopy(mArray, 0, para, 0, mLength);
return para;
}
}

View File

@@ -106,8 +106,8 @@ public interface Authenticator {
* @return a <code>PasswordAuthentication</code> object containing the
* user name and password used for authentication
*/
public PasswordAuthentication onAuthenticationChallenge(String description,
boolean isUserIdRequired, boolean isFullAccess);
PasswordAuthentication onAuthenticationChallenge(String description, boolean isUserIdRequired,
boolean isFullAccess);
/**
* Called when a client or server receives an authentication response
@@ -120,5 +120,5 @@ public interface Authenticator {
* @return the correct password for the user name provided; if
* <code>null</code> is returned then the authentication request failed
*/
public byte[] onAuthenticationResponse(byte[] userName);
byte[] onAuthenticationResponse(byte[] userName);
}

View File

@@ -47,7 +47,7 @@ public interface BaseStream {
*
* @throws IOException if the object is closed
*/
public void ensureOpen() throws IOException;
void ensureOpen() throws IOException;
/**
* Verifies that additional information may be sent. In other words, the
@@ -55,7 +55,7 @@ public interface BaseStream {
*
* @throws IOException if the operation is completed
*/
public void ensureNotDone() throws IOException;
void ensureNotDone() throws IOException;
/**
* Continues the operation since there is no data to read.
@@ -69,7 +69,7 @@ public interface BaseStream {
*
* @throws IOException if an IO error occurs
*/
public boolean continueOperation(boolean sendEmpty, boolean inStream) throws IOException;
boolean continueOperation(boolean sendEmpty, boolean inStream) throws IOException;
/**
* Called when the output or input stream is closed.
@@ -79,5 +79,5 @@ public interface BaseStream {
*
* @throws IOException if an IO error occurs
*/
public void streamClosed(boolean inStream) throws IOException;
void streamClosed(boolean inStream) throws IOException;
}

View File

@@ -47,104 +47,82 @@ import java.io.ByteArrayOutputStream;
*/
public final class ClientOperation implements Operation, BaseStream {
/**
* Defines the basic packet length used by OBEX. Event OBEX packet has the
* same basic format:<BR>
* Byte 0: Request or Response Code
* Byte 1&2: Length of the packet.
*/
private static final int BASE_PACKET_LENGTH = 3;
private ClientSession mParent;
private ClientSession parent;
private boolean mInputOpen;
private InputStream socketInput;
private PrivateInputStream mPrivateInput;
private PrivateInputStream privateInput;
private boolean mPrivateInputOpen;
private PrivateOutputStream privateOutput;
private PrivateOutputStream mPrivateOutput;
private boolean isClosed;
private boolean mPrivateOutputOpen;
private String exceptionMessage;
private String mExceptionMessage;
private int maxPacketSize;
private int mMaxPacketSize;
private boolean isDone;
private boolean mOperationDone;
private boolean isGet;
private boolean mGetOperation;
private HeaderSet requestHeaders;
private HeaderSet mRequestHeader;
private HeaderSet replyHeaders;
private HeaderSet mReplyHeader;
private boolean isEndOfBodySent;
private boolean inputStreamOpened;
private boolean outputStreamOpened;
private boolean isValidateConnected;
private boolean mEndOfBodySent;
/**
* Creates new OperationImpl to read and write data to a server
*
* @param in the input stream to read from
*
* @param maxSize the maximum packet size
*
* @param p the parent to this object
*
* @param headers the headers to set in the initial request
*
* @param type <code>true</code> if this is a get request;
* <code>false</code. if this is a put request
* @param headers the headers to set in the initial request
*
* @throws IOExcpetion if the an IO error occured
*/
public ClientOperation(InputStream in, int maxSize, ClientSession p, HeaderSet header,
boolean type) throws IOException {
public ClientOperation(int maxSize, ClientSession p, HeaderSet header, boolean type)
throws IOException {
parent = p;
isEndOfBodySent = false;
socketInput = in;
isClosed = false;
isDone = false;
maxPacketSize = maxSize;
isGet = type;
mParent = p;
mEndOfBodySent = false;
mInputOpen = true;
mOperationDone = false;
mMaxPacketSize = maxSize;
mGetOperation = type;
inputStreamOpened = false;
outputStreamOpened = false;
isValidateConnected = false;
mPrivateInputOpen = false;
mPrivateOutputOpen = false;
mPrivateInput = null;
mPrivateOutput = null;
privateInput = null;
privateOutput = null;
mReplyHeader = new HeaderSet();
replyHeaders = new HeaderSet();
requestHeaders = new HeaderSet();
mRequestHeader = new HeaderSet();
int[] headerList = header.getHeaderList();
if (headerList != null) {
for (int i = 0; i < headerList.length; i++) {
requestHeaders.setHeader(headerList[i], header.getHeader(headerList[i]));
mRequestHeader.setHeader(headerList[i], header.getHeader(headerList[i]));
}
}
if ((header).authChall != null) {
requestHeaders.authChall = new byte[(header).authChall.length];
System.arraycopy((header).authChall, 0, requestHeaders.authChall, 0,
(header).authChall.length);
if ((header).mAuthChall != null) {
mRequestHeader.mAuthChall = new byte[(header).mAuthChall.length];
System.arraycopy((header).mAuthChall, 0, mRequestHeader.mAuthChall, 0,
(header).mAuthChall.length);
}
if ((header).authResp != null) {
requestHeaders.authResp = new byte[(header).authResp.length];
System.arraycopy((header).authResp, 0, requestHeaders.authResp, 0,
(header).authResp.length);
if ((header).mAuthResp != null) {
mRequestHeader.mAuthResp = new byte[(header).mAuthResp.length];
System.arraycopy((header).mAuthResp, 0, mRequestHeader.mAuthResp, 0,
(header).mAuthResp.length);
}
// requestHeaders = (HeaderSet)header;
}
/**
@@ -163,24 +141,24 @@ public final class ClientOperation implements Operation, BaseStream {
// }
//no compatible with sun-ri
if ((isDone) && (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE)) {
if ((mOperationDone) && (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE)) {
throw new IOException("Operation has already ended");
}
exceptionMessage = "Operation aborted";
if ((!isDone) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
isDone = true;
mExceptionMessage = "Operation aborted";
if ((!mOperationDone) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
mOperationDone = true;
/*
* Since we are not sending any headers or returning any headers then
* we just need to write and read the same bytes
*/
parent.sendRequest(0xFF, null, replyHeaders, null);
mParent.sendRequest(ObexHelper.OBEX_OPCODE_ABORT, null, mReplyHeader, null);
if (replyHeaders.responseCode != ResponseCodes.OBEX_HTTP_OK) {
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_OK) {
throw new IOException("Invalid response code from server");
}
exceptionMessage = null;
mExceptionMessage = null;
}
close();
@@ -199,12 +177,12 @@ public final class ClientOperation implements Operation, BaseStream {
*/
public synchronized int getResponseCode() throws IOException {
//avoid dup validateConnection
if ((replyHeaders.responseCode == -1)
|| (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
if ((mReplyHeader.responseCode == -1)
|| (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
validateConnection();
}
return replyHeaders.responseCode;
return mReplyHeader.responseCode;
}
/**
@@ -226,7 +204,7 @@ public final class ClientOperation implements Operation, BaseStream {
*/
public String getType() {
try {
return (String)replyHeaders.getHeader(HeaderSet.TYPE);
return (String)mReplyHeader.getHeader(HeaderSet.TYPE);
} catch (IOException e) {
return null;
}
@@ -242,7 +220,7 @@ public final class ClientOperation implements Operation, BaseStream {
*/
public long getLength() {
try {
Long temp = (Long)replyHeaders.getHeader(HeaderSet.LENGTH);
Long temp = (Long)mReplyHeader.getHeader(HeaderSet.LENGTH);
if (temp == null) {
return -1;
@@ -262,27 +240,23 @@ public final class ClientOperation implements Operation, BaseStream {
* @throws IOException if an I/O error occurs
*/
public InputStream openInputStream() throws IOException {
// TODO: this mode is not set yet.
// if ((parent.mode & Connector.READ) == 0)
// throw new IOException("write-only connection");
ensureOpen();
if (inputStreamOpened)
if (mPrivateInputOpen)
throw new IOException("no more input streams available");
if (isGet) {
if (mGetOperation) {
// send the GET request here
validateConnection();
isValidateConnected = true;
} else {
if (privateInput == null) {
privateInput = new PrivateInputStream(this);
if (mPrivateInput == null) {
mPrivateInput = new PrivateInputStream(this);
}
}
inputStreamOpened = true;
mPrivateInputOpen = true;
return privateInput;
return mPrivateInput;
}
/**8
@@ -304,27 +278,25 @@ public final class ClientOperation implements Operation, BaseStream {
* @throws IOException if an I/O error occurs
*/
public OutputStream openOutputStream() throws IOException {
// TODO: this mode is not set yet.
// if ((parent.mode & Connector.WRITE) == 0)
// throw new IOException("read-only connection");
ensureOpen();
ensureNotDone();
if (outputStreamOpened)
if (mPrivateOutputOpen)
throw new IOException("no more output streams available");
if (privateOutput == null) {
if (mPrivateOutput == null) {
// there are 3 bytes operation headers and 3 bytes body headers //
privateOutput = new PrivateOutputStream(this, maxPacketSize - 6);
mPrivateOutput = new PrivateOutputStream(this, mMaxPacketSize - 6);
}
outputStreamOpened = true;
mPrivateOutputOpen = true;
return privateOutput;
return mPrivateOutput;
}
public int getMaxPacketSize() {
return maxPacketSize - 6;
return mMaxPacketSize - 6;
}
/**
@@ -344,10 +316,10 @@ public final class ClientOperation implements Operation, BaseStream {
* @throws IOException if the operation has already ended or is closed
*/
public void close() throws IOException {
isClosed = true;
inputStreamOpened = false;
outputStreamOpened = false;
parent.setRequestInactive();
mInputOpen = false;
mPrivateInputOpen = false;
mPrivateOutputOpen = false;
mParent.setRequestInactive();
}
/**
@@ -359,10 +331,10 @@ public final class ClientOperation implements Operation, BaseStream {
*
* @throws IOException if this <code>Operation</code> has been closed
*/
public HeaderSet getReceivedHeaders() throws IOException {
public HeaderSet getReceivedHeader() throws IOException {
ensureOpen();
return replyHeaders;
return mReplyHeader;
}
/**
@@ -381,18 +353,18 @@ public final class ClientOperation implements Operation, BaseStream {
*/
public void sendHeaders(HeaderSet headers) throws IOException {
ensureOpen();
if (isDone) {
if (mOperationDone) {
throw new IOException("Operation has already exchanged all data");
}
if (headers == null) {
throw new NullPointerException("Headers may not be null");
throw new IOException("Headers may not be null");
}
int[] headerList = headers.getHeaderList();
if (headerList != null) {
for (int i = 0; i < headerList.length; i++) {
requestHeaders.setHeader(headerList[i], headers.getHeader(headerList[i]));
mRequestHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
}
}
}
@@ -406,49 +378,50 @@ public final class ClientOperation implements Operation, BaseStream {
*
* @throws IOException if an IO error occurred
*/
/*
private boolean readResponse() throws IOException {
replyHeaders.responseCode = socketInput.read();
int packetLength = socketInput.read();
packetLength = (packetLength << 8) + socketInput.read();
mReplyHeader.responseCode = mInput.read();
int packetLength = mInput.read();
packetLength = (packetLength << 8) + mInput.read();
if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) {
if (exceptionMessage != null) {
if (mExceptionMessage != null) {
abort();
}
throw new IOException("Received a packet that was too big");
}
if (packetLength > BASE_PACKET_LENGTH) {
int dataLength = packetLength - BASE_PACKET_LENGTH;
if (packetLength > ObexHelper.BASE_PACKET_LENGTH) {
int dataLength = packetLength - ObexHelper.BASE_PACKET_LENGTH;
byte[] data = new byte[dataLength];
int readLength = socketInput.read(data);
int readLength = mInput.read(data);
if (readLength != dataLength) {
throw new IOException("Received a packet without data as decalred length");
}
byte[] body = ObexHelper.updateHeaderSet(replyHeaders, data);
byte[] body = ObexHelper.updateHeaderSet(mReplyHeader, data);
if (body != null) {
privateInput.writeBytes(body, 1);
mPrivateInput.writeBytes(body, 1);
/*
* Determine if a body (0x48) header or an end of body (0x49)
* was received. If we received an end of body and
* a response code of OBEX_HTTP_OK, then the operation should
* end.
*/
if ((body[0] == 0x49) && (replyHeaders.responseCode == ResponseCodes.OBEX_HTTP_OK)) {
*
if ((body[0] == 0x49) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_OK)) {
return false;
}
}
}
if (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
return true;
} else {
return false;
}
}
*/
/**
* Verifies that additional information may be sent. In other words, the
* operation is not done.
@@ -456,7 +429,7 @@ public final class ClientOperation implements Operation, BaseStream {
* @throws IOException if the operation is completed
*/
public void ensureNotDone() throws IOException {
if (isDone) {
if (mOperationDone) {
throw new IOException("Operation has completed");
}
}
@@ -467,12 +440,12 @@ public final class ClientOperation implements Operation, BaseStream {
* @throws IOException if an exception needs to be thrown
*/
public void ensureOpen() throws IOException {
parent.ensureOpen();
mParent.ensureOpen();
if (exceptionMessage != null) {
throw new IOException(exceptionMessage);
if (mExceptionMessage != null) {
throw new IOException(mExceptionMessage);
}
if (isClosed) {
if (!mInputOpen) {
throw new IOException("Operation has already ended");
}
}
@@ -486,7 +459,7 @@ public final class ClientOperation implements Operation, BaseStream {
ensureOpen();
// to sure only one privateInput object exist.
if (privateInput == null) {
if (mPrivateInput == null) {
startProcessing();
}
}
@@ -501,13 +474,13 @@ public final class ClientOperation implements Operation, BaseStream {
*
* @throws IOException if an IO error occurs
*/
protected boolean sendRequest(int type) throws IOException {
private boolean sendRequest(int type) throws IOException {
boolean returnValue = false;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int bodyLength = -1;
byte[] headerArray = ObexHelper.createHeader(requestHeaders, true);
if (privateOutput != null) {
bodyLength = privateOutput.size();
byte[] headerArray = ObexHelper.createHeader(mRequestHeader, true);
if (mPrivateOutput != null) {
bodyLength = mPrivateOutput.size();
}
/*
@@ -518,40 +491,39 @@ public final class ClientOperation implements Operation, BaseStream {
* length, but it is a waste of resources if we can't send much of
* the body.
*/
if ((BASE_PACKET_LENGTH + headerArray.length) > maxPacketSize) {
if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketSize) {
int end = 0;
int start = 0;
// split & send the headerArray in multiple packets.
while (end != headerArray.length) {
//split the headerArray
end = ObexHelper.findHeaderEnd(headerArray, start, maxPacketSize
- BASE_PACKET_LENGTH);
end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
- ObexHelper.BASE_PACKET_LENGTH);
// can not split
if (end == -1) {
isDone = true;
mOperationDone = true;
abort();
// isDone = true;
exceptionMessage = "Header larger then can be sent in a packet";
isClosed = true;
mExceptionMessage = "Header larger then can be sent in a packet";
mInputOpen = false;
if (privateInput != null) {
privateInput.close();
if (mPrivateInput != null) {
mPrivateInput.close();
}
if (privateOutput != null) {
privateOutput.close();
if (mPrivateOutput != null) {
mPrivateOutput.close();
}
throw new IOException("OBEX Packet exceeds max packet size");
}
byte[] sendHeader = new byte[end - start];
System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
if (!parent.sendRequest(type, sendHeader, replyHeaders, privateInput)) {
if (!mParent.sendRequest(type, sendHeader, mReplyHeader, mPrivateInput)) {
return false;
}
if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) {
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
return false;
}
@@ -569,27 +541,27 @@ public final class ClientOperation implements Operation, BaseStream {
if (bodyLength > 0) {
/*
* Determine if I can send the whole body or just part of
* Determine if we can send the whole body or just part of
* the body. Remember that there is the 3 bytes for the
* response message and 3 bytes for the header ID and length
*/
if (bodyLength > (maxPacketSize - headerArray.length - 6)) {
if (bodyLength > (mMaxPacketSize - headerArray.length - 6)) {
returnValue = true;
bodyLength = maxPacketSize - headerArray.length - 6;
bodyLength = mMaxPacketSize - headerArray.length - 6;
}
byte[] body = privateOutput.readBytes(bodyLength);
byte[] body = mPrivateOutput.readBytes(bodyLength);
/*
* Since this is a put request if the final bit is set or
* the output stream is closed we need to send the 0x49
* (End of Body) otherwise, we need to send 0x48 (Body)
*/
if ((privateOutput.isClosed()) && (!returnValue) && (!isEndOfBodySent)
if ((mPrivateOutput.isClosed()) && (!returnValue) && (!mEndOfBodySent)
&& ((type & 0x80) != 0)) {
out.write(0x49);
isEndOfBodySent = true;
mEndOfBodySent = true;
} else {
out.write(0x48);
}
@@ -603,13 +575,13 @@ public final class ClientOperation implements Operation, BaseStream {
}
}
if (outputStreamOpened && bodyLength <= 0 && !isEndOfBodySent) {
if (mPrivateOutputOpen && bodyLength <= 0 && !mEndOfBodySent) {
// only 0x82 or 0x83 can send 0x49
if ((type & 0x80) == 0) {
out.write(0x48);
} else {
out.write(0x49);
isEndOfBodySent = true;
mEndOfBodySent = true;
}
@@ -619,19 +591,19 @@ public final class ClientOperation implements Operation, BaseStream {
}
if (out.size() == 0) {
if (!parent.sendRequest(type, null, replyHeaders, privateInput)) {
if (!mParent.sendRequest(type, null, mReplyHeader, mPrivateInput)) {
return false;
}
return returnValue;
}
if ((out.size() > 0)
&& (!parent.sendRequest(type, out.toByteArray(), replyHeaders, privateInput))) {
&& (!mParent.sendRequest(type, out.toByteArray(), mReplyHeader, mPrivateInput))) {
return false;
}
// send all of the output data in 0x48,
// send 0x49 with empty body
if ((privateOutput != null) && (privateOutput.size() > 0))
if ((mPrivateOutput != null) && (mPrivateOutput.size() > 0))
returnValue = true;
return returnValue;
@@ -646,41 +618,41 @@ public final class ClientOperation implements Operation, BaseStream {
*/
private synchronized void startProcessing() throws IOException {
if (privateInput == null) {
privateInput = new PrivateInputStream(this);
if (mPrivateInput == null) {
mPrivateInput = new PrivateInputStream(this);
}
boolean more = true;
if (isGet) {
if (!isDone) {
replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
if (mGetOperation) {
if (!mOperationDone) {
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
more = sendRequest(0x03);
}
if (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
parent.sendRequest(0x83, null, replyHeaders, privateInput);
if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
}
if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) {
isDone = true;
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
mOperationDone = true;
}
}
} else {
if (!isDone) {
replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
if (!mOperationDone) {
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
more = sendRequest(0x02);
}
}
if (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
parent.sendRequest(0x82, null, replyHeaders, privateInput);
if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
mParent.sendRequest(0x82, null, mReplyHeader, mPrivateInput);
}
if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) {
isDone = true;
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
mOperationDone = true;
}
}
}
@@ -697,45 +669,45 @@ public final class ClientOperation implements Operation, BaseStream {
public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
throws IOException {
if (isGet) {
if ((inStream) && (!isDone)) {
if (mGetOperation) {
if ((inStream) && (!mOperationDone)) {
// to deal with inputstream in get operation
parent.sendRequest(0x83, null, replyHeaders, privateInput);
mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
/*
* Determine if that was not the last packet in the operation
*/
if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) {
isDone = true;
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
mOperationDone = true;
}
return true;
} else if ((!inStream) && (!isDone)) {
} else if ((!inStream) && (!mOperationDone)) {
// to deal with outputstream in get operation
if (privateInput == null) {
privateInput = new PrivateInputStream(this);
if (mPrivateInput == null) {
mPrivateInput = new PrivateInputStream(this);
}
sendRequest(0x03);
return true;
} else if (isDone) {
} else if (mOperationDone) {
return false;
}
} else {
if ((!inStream) && (!isDone)) {
if ((!inStream) && (!mOperationDone)) {
// to deal with outputstream in put operation
if (replyHeaders.responseCode == -1) {
replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
if (mReplyHeader.responseCode == -1) {
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
}
sendRequest(0x02);
return true;
} else if ((inStream) && (!isDone)) {
} else if ((inStream) && (!mOperationDone)) {
// How to deal with inputstream in put operation ?
return false;
} else if (isDone) {
} else if (mOperationDone) {
return false;
}
@@ -752,23 +724,23 @@ public final class ClientOperation implements Operation, BaseStream {
* @throws IOException if an IO error occurs
*/
public void streamClosed(boolean inStream) throws IOException {
if (!isGet) {
if ((!inStream) && (!isDone)) {
if (!mGetOperation) {
if ((!inStream) && (!mOperationDone)) {
// to deal with outputstream in put operation
boolean more = true;
if ((privateOutput != null) && (privateOutput.size() <= 0)) {
byte[] headerArray = ObexHelper.createHeader(requestHeaders, false);
if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
if (headerArray.length <= 0)
more = false;
}
// If have not sent any data so send all now
if (replyHeaders.responseCode == -1) {
replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
if (mReplyHeader.responseCode == -1) {
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
}
while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
more = sendRequest(0x02);
}
@@ -777,61 +749,60 @@ public final class ClientOperation implements Operation, BaseStream {
* only have a single reply to send. so we don't need the while
* loop.
*/
while (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
sendRequest(0x82);
}
isDone = true;
} else if ((inStream) && (isDone)) {
mOperationDone = true;
} else if ((inStream) && (mOperationDone)) {
// how to deal with input stream in put stream ?
isDone = true;
mOperationDone = true;
}
} else {
isValidateConnected = false;
if ((inStream) && (!isDone)) {
if ((inStream) && (!mOperationDone)) {
// to deal with inputstream in get operation
// Have not sent any data so send it all now
if (replyHeaders.responseCode == -1) {
replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
if (mReplyHeader.responseCode == -1) {
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
}
while (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
if (!sendRequest(0x83)) {
break;
}
}
while (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) {
parent.sendRequest(0x83, null, replyHeaders, privateInput);
while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
}
isDone = true;
} else if ((!inStream) && (!isDone)) {
mOperationDone = true;
} else if ((!inStream) && (!mOperationDone)) {
// to deal with outputstream in get operation
// part of the data may have been sent in continueOperation.
boolean more = true;
if ((privateOutput != null) && (privateOutput.size() <= 0)) {
byte[] headerArray = ObexHelper.createHeader(requestHeaders, false);
if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
if (headerArray.length <= 0)
more = false;
}
if (privateInput == null) {
privateInput = new PrivateInputStream(this);
if (mPrivateInput == null) {
mPrivateInput = new PrivateInputStream(this);
}
if ((privateOutput != null) && (privateOutput.size() <= 0))
if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0))
more = false;
replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE;
while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) {
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
more = sendRequest(0x03);
}
sendRequest(0x83);
// parent.sendRequest(0x83, null, replyHeaders, privateInput);
if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) {
isDone = true;
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
mOperationDone = true;
}
}

View File

@@ -38,13 +38,11 @@ import java.io.InputStream;
import java.io.OutputStream;
/**
* This class implements the <code>Operation</code> interface. It will read
* and write data via puts and gets.
* This class in an implementation of the OBEX ClientSession.
*
* @hide
*/
public final class ClientSession implements ObexSession {
private Authenticator mAuthenticator;
public final class ClientSession extends ObexSession {
private boolean mOpen;
@@ -53,8 +51,6 @@ public final class ClientSession implements ObexSession {
private byte[] mConnectionId = null;
private byte[] mChallengeDigest = null;
/*
* The max Packet size must be at least 256 according to the OBEX
* specification.
@@ -67,14 +63,14 @@ public final class ClientSession implements ObexSession {
private final OutputStream mOutput;
public ClientSession(ObexTransport trans) throws IOException {
public ClientSession(final ObexTransport trans) throws IOException {
mInput = trans.openInputStream();
mOutput = trans.openOutputStream();
mOpen = true;
mRequestActive = false;
}
public HeaderSet connect(HeaderSet header) throws IOException {
public HeaderSet connect(final HeaderSet header) throws IOException {
ensureOpen();
if (mObexConnected) {
throw new IOException("Already connected to server");
@@ -119,7 +115,7 @@ public final class ClientSession implements ObexSession {
}
HeaderSet returnHeaderSet = new HeaderSet();
sendRequest(0x80, requestPacket, returnHeaderSet, null);
sendRequest(ObexHelper.OBEX_OPCODE_CONNECT, requestPacket, returnHeaderSet, null);
/*
* Read the response from the OBEX server.
@@ -147,21 +143,23 @@ public final class ClientSession implements ObexSession {
ensureOpen();
HeaderSet head;
if (header == null) {
header = new HeaderSet();
head = new HeaderSet();
} else {
if (header.nonce != null) {
head = header;
if (head.nonce != null) {
mChallengeDigest = new byte[16];
System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
}
}
// Add the connection ID if one exists
if (mConnectionId != null) {
header.connectionID = new byte[4];
System.arraycopy(mConnectionId, 0, header.connectionID, 0, 4);
head.mConnectionID = new byte[4];
System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
}
return new ClientOperation(mInput, maxPacketSize, this, header, true);
return new ClientOperation(maxPacketSize, this, head, true);
}
/**
@@ -178,7 +176,7 @@ public final class ClientSession implements ObexSession {
Operation op = put(header);
op.getResponseCode();
HeaderSet returnValue = op.getReceivedHeaders();
HeaderSet returnValue = op.getReceivedHeader();
op.close();
return returnValue;
@@ -200,8 +198,8 @@ public final class ClientSession implements ObexSession {
}
// Add the connection ID if one exists
if (mConnectionId != null) {
header.connectionID = new byte[4];
System.arraycopy(mConnectionId, 0, header.connectionID, 0, 4);
header.mConnectionID = new byte[4];
System.arraycopy(mConnectionId, 0, header.mConnectionID, 0, 4);
}
head = ObexHelper.createHeader(header, false);
@@ -212,13 +210,13 @@ public final class ClientSession implements ObexSession {
// Add the connection ID if one exists
if (mConnectionId != null) {
head = new byte[5];
head[0] = (byte)0xCB;
head[0] = (byte)HeaderSet.CONNECTION_ID;
System.arraycopy(mConnectionId, 0, head, 1, 4);
}
}
HeaderSet returnHeaderSet = new HeaderSet();
sendRequest(0x81, head, returnHeaderSet, null);
sendRequest(ObexHelper.OBEX_OPCODE_DISCONNECT, head, returnHeaderSet, null);
/*
* An OBEX DISCONNECT reply from the server:
@@ -253,36 +251,36 @@ public final class ClientSession implements ObexSession {
setRequestActive();
ensureOpen();
HeaderSet head;
if (header == null) {
header = new HeaderSet();
head = new HeaderSet();
} else {
// when auth is initated by client ,save the digest
if (header.nonce != null) {
head = header;
// when auth is initiated by client ,save the digest
if (head.nonce != null) {
mChallengeDigest = new byte[16];
System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
}
}
// Add the connection ID if one exists
if (mConnectionId != null) {
header.connectionID = new byte[4];
System.arraycopy(mConnectionId, 0, header.connectionID, 0, 4);
head.mConnectionID = new byte[4];
System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
}
return new ClientOperation(mInput, maxPacketSize, this, header, false);
return new ClientOperation(maxPacketSize, this, head, false);
}
public void setAuthenticator(Authenticator auth) {
public void setAuthenticator(Authenticator auth) throws IOException {
if (auth == null) {
throw new NullPointerException("Authenticator may not be null");
throw new IOException("Authenticator may not be null");
}
mAuthenticator = auth;
}
public HeaderSet setPath(HeaderSet header, boolean backup, boolean create)
throws IOException {
public HeaderSet setPath(HeaderSet header, boolean backup, boolean create) throws IOException {
if (!mObexConnected) {
throw new IOException("Not connected to the server");
}
@@ -291,29 +289,30 @@ public final class ClientSession implements ObexSession {
int totalLength = 2;
byte[] head = null;
HeaderSet headset;
if (header == null) {
header = new HeaderSet();
headset = new HeaderSet();
} else {
if (header.nonce != null) {
headset = header;
if (headset.nonce != null) {
mChallengeDigest = new byte[16];
System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
}
}
// when auth is initiated by client ,save the digest
if (header.nonce != null) {
if (headset.nonce != null) {
mChallengeDigest = new byte[16];
System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
}
// Add the connection ID if one exists
if (mConnectionId != null) {
header.connectionID = new byte[4];
System.arraycopy(mConnectionId, 0, header.connectionID, 0, 4);
headset.mConnectionID = new byte[4];
System.arraycopy(mConnectionId, 0, headset.mConnectionID, 0, 4);
}
head = ObexHelper.createHeader(header, false);
head = ObexHelper.createHeader(headset, false);
totalLength += head.length;
if (totalLength > maxPacketSize) {
@@ -345,12 +344,12 @@ public final class ClientSession implements ObexSession {
byte[] packet = new byte[totalLength];
packet[0] = (byte)flags;
packet[1] = (byte)0x00;
if (header != null) {
if (headset != null) {
System.arraycopy(head, 0, packet, 2, head.length);
}
HeaderSet returnHeaderSet = new HeaderSet();
sendRequest(0x85, packet, returnHeaderSet, null);
sendRequest(ObexHelper.OBEX_OPCODE_SETPATH, packet, returnHeaderSet, null);
/*
* An OBEX SETPATH reply from the server:
@@ -380,7 +379,7 @@ public final class ClientSession implements ObexSession {
* Allows Put and get operation objects to tell this object when they are
* done.
*/
/*package*/ synchronized void setRequestInactive() {
/*package*/synchronized void setRequestInactive() {
mRequestActive = false;
}
@@ -401,7 +400,7 @@ public final class ClientSession implements ObexSession {
* headers (i.e. authentication challenge or authentication response) are
* received, they will be processed.
*
* @param code the type of request to send to the client
* @param opCode the type of request to send to the client
*
* @param head the headers to send to the server
*
@@ -419,7 +418,7 @@ public final class ClientSession implements ObexSession {
*
* @throws IOException if an IO error occurs
*/
public boolean sendRequest(int code, byte[] head, HeaderSet header,
public boolean sendRequest(int opCode, byte[] head, HeaderSet header,
PrivateInputStream privateInput) throws IOException {
//check header length with local max size
if (head != null) {
@@ -427,10 +426,10 @@ public final class ClientSession implements ObexSession {
throw new IOException("header too large ");
}
}
//byte[] nonce;
int bytesReceived;
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write((byte)code);
out.write((byte)opCode);
// Determine if there are any headers to send
if (head == null) {
@@ -453,10 +452,12 @@ public final class ClientSession implements ObexSession {
if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
throw new IOException("Packet received exceeds packet size limit");
}
if (length > 3) {
if (length > ObexHelper.BASE_PACKET_LENGTH) {
byte[] data = null;
if (code == 0x80) {
if (opCode == ObexHelper.OBEX_OPCODE_CONNECT) {
@SuppressWarnings("unused")
int version = mInput.read();
@SuppressWarnings("unused")
int flags = mInput.read();
maxPacketSize = (mInput.read() << 8) + mInput.read();
@@ -483,7 +484,7 @@ public final class ClientSession implements ObexSession {
while (bytesReceived != (length - 3)) {
bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived);
}
if (code == 0xFF) {
if (opCode == ObexHelper.OBEX_OPCODE_ABORT) {
return true;
}
}
@@ -493,33 +494,33 @@ public final class ClientSession implements ObexSession {
privateInput.writeBytes(body, 1);
}
if (header.connectionID != null) {
if (header.mConnectionID != null) {
mConnectionId = new byte[4];
System.arraycopy(header.connectionID, 0, mConnectionId, 0, 4);
System.arraycopy(header.mConnectionID, 0, mConnectionId, 0, 4);
}
if (header.authResp != null) {
if (!handleAuthResp(header.authResp)) {
if (header.mAuthResp != null) {
if (!handleAuthResp(header.mAuthResp)) {
setRequestInactive();
throw new IOException("Authentication Failed");
}
}
if ((header.responseCode == ResponseCodes.OBEX_HTTP_UNAUTHORIZED)
&& (header.authChall != null)) {
&& (header.mAuthChall != null)) {
if (handleAuthChall(header)) {
out.write((byte)0x4E);
out.write((byte)((header.authResp.length + 3) >> 8));
out.write((byte)(header.authResp.length + 3));
out.write(header.authResp);
header.authChall = null;
header.authResp = null;
out.write((byte)HeaderSet.AUTH_RESPONSE);
out.write((byte)((header.mAuthResp.length + 3) >> 8));
out.write((byte)(header.mAuthResp.length + 3));
out.write(header.mAuthResp);
header.mAuthChall = null;
header.mAuthResp = null;
byte[] sendHeaders = new byte[out.size() - 3];
System.arraycopy(out.toByteArray(), 3, sendHeaders, 0, sendHeaders.length);
return sendRequest(code, sendHeaders, header, privateInput);
return sendRequest(opCode, sendHeaders, header, privateInput);
}
}
}
@@ -527,194 +528,6 @@ public final class ClientSession implements ObexSession {
return true;
}
/**
* Called when the client received an authentication challenge header. This
* will cause the authenticator to handle the authentication challenge.
*
* @param header the header with the authentication challenge
*
* @return <code>true</code> if the last request should be resent;
* <code>false</code> if the last request should not be resent
*/
protected boolean handleAuthChall(HeaderSet header) {
if (mAuthenticator == null) {
return false;
}
/*
* An authentication challenge is made up of one required and two
* optional tag length value triplets. The tag 0x00 is required to be
* in the authentication challenge and it represents the challenge
* digest that was received. The tag 0x01 is the options tag. This
* tag tracks if user ID is required and if full access will be
* granted. The tag 0x02 is the realm, which provides a description of
* which user name and password to use.
*/
byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.authChall);
byte[] option = ObexHelper.getTagValue((byte)0x01, header.authChall);
byte[] description = ObexHelper.getTagValue((byte)0x02, header.authChall);
String realm = "";
if (description != null) {
byte[] realmString = new byte[description.length - 1];
System.arraycopy(description, 1, realmString, 0, realmString.length);
switch (description[0] & 0xFF) {
case 0x00:
// ASCII encoding
// Fall through
case 0x01:
// ISO-8859-1 encoding
try {
realm = new String(realmString, "ISO8859_1");
} catch (Exception e) {
throw new RuntimeException("Unsupported Encoding Scheme");
}
break;
case 0xFF:
// UNICODE Encoding
realm = ObexHelper.convertToUnicode(realmString, false);
break;
case 0x02:
// ISO-8859-2 encoding
// Fall through
case 0x03:
// ISO-8859-3 encoding
// Fall through
case 0x04:
// ISO-8859-4 encoding
// Fall through
case 0x05:
// ISO-8859-5 encoding
// Fall through
case 0x06:
// ISO-8859-6 encoding
// Fall through
case 0x07:
// ISO-8859-7 encoding
// Fall through
case 0x08:
// ISO-8859-8 encoding
// Fall through
case 0x09:
// ISO-8859-9 encoding
// Fall through
default:
throw new RuntimeException("Unsupported Encoding Scheme");
}
}
boolean isUserIDRequired = false;
boolean isFullAccess = true;
if (option != null) {
if ((option[0] & 0x01) != 0) {
isUserIDRequired = true;
}
if ((option[0] & 0x02) != 0) {
isFullAccess = false;
}
}
PasswordAuthentication result = null;
header.authChall = null;
try {
result = mAuthenticator.onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
} catch (Exception e) {
return false;
}
/*
* If no password was provided then do not resend the request
*/
if (result == null) {
return false;
}
byte[] password = result.getPassword();
if (password == null) {
return false;
}
byte[] userName = result.getUserName();
/*
* Create the authentication response header. It includes 1 required
* and 2 option tag length value triples. The required triple has a
* tag of 0x00 and is the response digest. The first optional tag is
* 0x01 and represents the user ID. If no user ID is provided, then
* no user ID will be sent. The second optional tag is 0x02 and is the
* challenge that was received. This will always be sent
*/
if (userName != null) {
header.authResp = new byte[38 + userName.length];
header.authResp[36] = (byte)0x01;
header.authResp[37] = (byte)userName.length;
System.arraycopy(userName, 0, header.authResp, 38, userName.length);
} else {
header.authResp = new byte[36];
}
// Create the secret String
byte[] digest = new byte[challenge.length + password.length];
System.arraycopy(challenge, 0, digest, 0, challenge.length);
System.arraycopy(password, 0, digest, challenge.length, password.length);
// Add the Response Digest
header.authResp[0] = (byte)0x00;
header.authResp[1] = (byte)0x10;
byte[] responseDigest = ObexHelper.computeMd5Hash(digest);
System.arraycopy(responseDigest, 0, header.authResp, 2, 16);
// Add the challenge
header.authResp[18] = (byte)0x02;
header.authResp[19] = (byte)0x10;
System.arraycopy(challenge, 0, header.authResp, 20, 16);
return true;
}
/**
* Called when the client received an authentication response header. This
* will cause the authenticator to handle the authentication response.
*
* @param authResp the authentication response
*
* @return <code>true</code> if the response passed; <code>false</code> if
* the response failed
*/
protected boolean handleAuthResp(byte[] authResp) {
if (mAuthenticator == null) {
return false;
}
byte[] correctPassword = mAuthenticator.onAuthenticationResponse(ObexHelper.getTagValue(
(byte)0x01, authResp));
if (correctPassword == null) {
return false;
}
byte[] temp = new byte[correctPassword.length + 16];
System.arraycopy(mChallengeDigest, 0, temp, 0, 16);
System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length);
byte[] correctResponse = ObexHelper.computeMd5Hash(temp);
byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp);
for (int i = 0; i < 16; i++) {
if (correctResponse[i] != actualResponse[i]) {
return false;
}
}
return true;
}
public void close() throws IOException {
mOpen = false;
mInput.close();

View File

@@ -117,6 +117,20 @@ public final class HeaderSet {
*/
public static final int HTTP = 0x47;
/**
* Represents the OBEX BODY header.
* <P>
* The value of <code>BODY</code> is 0x48 (72).
*/
public static final int BODY = 0x48;
/**
* Represents the OBEX End of BODY header.
* <P>
* The value of <code>BODY</code> is 0x49 (73).
*/
public static final int END_OF_BODY = 0x49;
/**
* Represents the OBEX Who header. Identifies the OBEX application to
* determine if the two peers are talking to each other.
@@ -126,12 +140,13 @@ public final class HeaderSet {
public static final int WHO = 0x4A;
/**
* Represents the OBEX Object Class header. This header specifies the
* OBEX object class of the object.
* Represents the OBEX Connection ID header. Identifies used for OBEX
* connection multiplexing.
* <P>
* The value of <code>OBJECT_CLASS</code> is 0x4F (79).
* The value of <code>CONNECTION_ID</code> is 0xCB (203).
*/
public static final int OBJECT_CLASS = 0x4F;
public static final int CONNECTION_ID = 0xCB;
/**
* Represents the OBEX Application Parameter header. This header specifies
@@ -141,49 +156,71 @@ public final class HeaderSet {
*/
public static final int APPLICATION_PARAMETER = 0x4C;
private Long count; // 4 byte unsigned integer
/**
* Represents the OBEX authentication digest-challenge.
* <P>
* The value of <code>AUTH_CHALLENGE</code> is 0x4D (77).
*/
public static final int AUTH_CHALLENGE = 0x4D;
private String name; // null terminated Unicode text string
/**
* Represents the OBEX authentication digest-response.
* <P>
* The value of <code>AUTH_RESPONSE</code> is 0x4E (78).
*/
public static final int AUTH_RESPONSE = 0x4E;
private String type; // null terminated ASCII text string
/**
* Represents the OBEX Object Class header. This header specifies the
* OBEX object class of the object.
* <P>
* The value of <code>OBJECT_CLASS</code> is 0x4F (79).
*/
public static final int OBJECT_CLASS = 0x4F;
private Long length; // 4 byte unsigend integer
private Long mCount; // 4 byte unsigned integer
private Calendar isoTime; // String of the form YYYYMMDDTHHMMSSZ
private String mName; // null terminated Unicode text string
private Calendar byteTime; // 4 byte unsigned integer
private String mType; // null terminated ASCII text string
private String description; // null terminated Unicode text String
private Long mLength; // 4 byte unsigend integer
private byte[] target; // byte sequence
private Calendar mIsoTime; // String of the form YYYYMMDDTHHMMSSZ
private byte[] http; // byte sequence
private Calendar mByteTime; // 4 byte unsigned integer
private byte[] who; // length prefixed byte sequence
private String mDescription; // null terminated Unicode text String
private byte[] appParam; // byte sequence of the form tag length value
private byte[] mTarget; // byte sequence
public byte[] authChall; // The authentication challenge header
private byte[] mHttpHeader; // byte sequence
public byte[] authResp; // The authentication response header
private byte[] mWho; // length prefixed byte sequence
public byte[] connectionID; // THe connection ID
private byte[] mAppParam; // byte sequence of the form tag length value
private byte[] objectClass; // byte sequence
public byte[] mAuthChall; // The authentication challenge header
private String[] unicodeUserDefined; //null terminated unicode string
public byte[] mAuthResp; // The authentication response header
private byte[][] sequenceUserDefined; // byte sequence user defined
public byte[] mConnectionID; // THe connection ID
private Byte[] byteUserDefined; // 1 byte
private byte[] mObjectClass; // byte sequence
private Long[] integerUserDefined; // 4 byte unsigned integer
private String[] mUnicodeUserDefined; //null terminated unicode string
/*package*/ int responseCode;
private byte[][] mSequenceUserDefined; // byte sequence user defined
/*package*/ byte[] nonce;
private Byte[] mByteUserDefined; // 1 byte
private final Random random;
private Long[] mIntegerUserDefined; // 4 byte unsigned integer
/*package*/int responseCode;
/*package*/byte[] nonce;
private final Random mRandom;
/**
* Creates new <code>HeaderSet</code> object.
@@ -191,12 +228,12 @@ public final class HeaderSet {
* @param size the max packet size for this connection
*/
public HeaderSet() {
unicodeUserDefined = new String[16];
sequenceUserDefined = new byte[16][];
byteUserDefined = new Byte[16];
integerUserDefined = new Long[16];
mUnicodeUserDefined = new String[16];
mSequenceUserDefined = new byte[16][];
mByteUserDefined = new Byte[16];
mIntegerUserDefined = new Long[16];
responseCode = -1;
random = new Random();
mRandom = new Random();
}
/**
@@ -222,7 +259,7 @@ public final class HeaderSet {
case COUNT:
if (!(headerValue instanceof Long)) {
if (headerValue == null) {
count = null;
mCount = null;
break;
}
throw new IllegalArgumentException("Count must be a Long");
@@ -231,24 +268,24 @@ public final class HeaderSet {
if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
throw new IllegalArgumentException("Count must be between 0 and 0xFFFFFFFF");
}
count = (Long)headerValue;
mCount = (Long)headerValue;
break;
case NAME:
if ((headerValue != null) && (!(headerValue instanceof String))) {
throw new IllegalArgumentException("Name must be a String");
}
name = (String)headerValue;
mName = (String)headerValue;
break;
case TYPE:
if ((headerValue != null) && (!(headerValue instanceof String))) {
throw new IllegalArgumentException("Type must be a String");
}
type = (String)headerValue;
mType = (String)headerValue;
break;
case LENGTH:
if (!(headerValue instanceof Long)) {
if (headerValue == null) {
length = null;
mLength = null;
break;
}
throw new IllegalArgumentException("Length must be a Long");
@@ -257,84 +294,84 @@ public final class HeaderSet {
if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
throw new IllegalArgumentException("Length must be between 0 and 0xFFFFFFFF");
}
length = (Long)headerValue;
mLength = (Long)headerValue;
break;
case TIME_ISO_8601:
if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
throw new IllegalArgumentException("Time ISO 8601 must be a Calendar");
}
isoTime = (Calendar)headerValue;
mIsoTime = (Calendar)headerValue;
break;
case TIME_4_BYTE:
if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
throw new IllegalArgumentException("Time 4 Byte must be a Calendar");
}
byteTime = (Calendar)headerValue;
mByteTime = (Calendar)headerValue;
break;
case DESCRIPTION:
if ((headerValue != null) && (!(headerValue instanceof String))) {
throw new IllegalArgumentException("Description must be a String");
}
description = (String)headerValue;
mDescription = (String)headerValue;
break;
case TARGET:
if (headerValue == null) {
target = null;
mTarget = null;
} else {
if (!(headerValue instanceof byte[])) {
throw new IllegalArgumentException("Target must be a byte array");
} else {
target = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, target, 0, target.length);
mTarget = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, mTarget, 0, mTarget.length);
}
}
break;
case HTTP:
if (headerValue == null) {
http = null;
mHttpHeader = null;
} else {
if (!(headerValue instanceof byte[])) {
throw new IllegalArgumentException("HTTP must be a byte array");
} else {
http = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, http, 0, http.length);
mHttpHeader = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, mHttpHeader, 0, mHttpHeader.length);
}
}
break;
case WHO:
if (headerValue == null) {
who = null;
mWho = null;
} else {
if (!(headerValue instanceof byte[])) {
throw new IllegalArgumentException("WHO must be a byte array");
} else {
who = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, who, 0, who.length);
mWho = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, mWho, 0, mWho.length);
}
}
break;
case OBJECT_CLASS:
if (headerValue == null) {
objectClass = null;
mObjectClass = null;
} else {
if (!(headerValue instanceof byte[])) {
throw new IllegalArgumentException("Object Class must be a byte array");
} else {
objectClass = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, objectClass, 0, objectClass.length);
mObjectClass = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, mObjectClass, 0, mObjectClass.length);
}
}
break;
case APPLICATION_PARAMETER:
if (headerValue == null) {
appParam = null;
mAppParam = null;
} else {
if (!(headerValue instanceof byte[])) {
throw new IllegalArgumentException(
"Application Parameter must be a byte array");
} else {
appParam = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, appParam, 0, appParam.length);
mAppParam = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, mAppParam, 0, mAppParam.length);
}
}
break;
@@ -345,7 +382,7 @@ public final class HeaderSet {
throw new IllegalArgumentException(
"Unicode String User Defined must be a String");
}
unicodeUserDefined[headerID - 0x30] = (String)headerValue;
mUnicodeUserDefined[headerID - 0x30] = (String)headerValue;
break;
}
@@ -353,15 +390,15 @@ public final class HeaderSet {
if ((headerID >= 0x70) && (headerID <= 0x7F)) {
if (headerValue == null) {
sequenceUserDefined[headerID - 0x70] = null;
mSequenceUserDefined[headerID - 0x70] = null;
} else {
if (!(headerValue instanceof byte[])) {
throw new IllegalArgumentException(
"Byte Sequence User Defined must be a byte array");
} else {
sequenceUserDefined[headerID - 0x70] = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, sequenceUserDefined[headerID - 0x70],
0, sequenceUserDefined[headerID - 0x70].length);
mSequenceUserDefined[headerID - 0x70] = new byte[((byte[])headerValue).length];
System.arraycopy(headerValue, 0, mSequenceUserDefined[headerID - 0x70],
0, mSequenceUserDefined[headerID - 0x70].length);
}
}
break;
@@ -371,7 +408,7 @@ public final class HeaderSet {
if ((headerValue != null) && (!(headerValue instanceof Byte))) {
throw new IllegalArgumentException("ByteUser Defined must be a Byte");
}
byteUserDefined[headerID - 0xB0] = (Byte)headerValue;
mByteUserDefined[headerID - 0xB0] = (Byte)headerValue;
break;
}
@@ -380,7 +417,7 @@ public final class HeaderSet {
if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
if (!(headerValue instanceof Long)) {
if (headerValue == null) {
integerUserDefined[headerID - 0xF0] = null;
mIntegerUserDefined[headerID - 0xF0] = null;
break;
}
throw new IllegalArgumentException("Integer User Defined must be a Long");
@@ -390,7 +427,7 @@ public final class HeaderSet {
throw new IllegalArgumentException(
"Integer User Defined must be between 0 and 0xFFFFFFFF");
}
integerUserDefined[headerID - 0xF0] = (Long)headerValue;
mIntegerUserDefined[headerID - 0xF0] = (Long)headerValue;
break;
}
throw new IllegalArgumentException("Invalid Header Identifier");
@@ -417,45 +454,45 @@ public final class HeaderSet {
switch (headerID) {
case COUNT:
return count;
return mCount;
case NAME:
return name;
return mName;
case TYPE:
return type;
return mType;
case LENGTH:
return length;
return mLength;
case TIME_ISO_8601:
return isoTime;
return mIsoTime;
case TIME_4_BYTE:
return byteTime;
return mByteTime;
case DESCRIPTION:
return description;
return mDescription;
case TARGET:
return target;
return mTarget;
case HTTP:
return http;
return mHttpHeader;
case WHO:
return who;
return mWho;
case OBJECT_CLASS:
return objectClass;
return mObjectClass;
case APPLICATION_PARAMETER:
return appParam;
return mAppParam;
default:
// Verify that it was not a Unicode String user Defined
if ((headerID >= 0x30) && (headerID <= 0x3F)) {
return unicodeUserDefined[headerID - 0x30];
return mUnicodeUserDefined[headerID - 0x30];
}
// Verify that it was not a byte sequence user defined header
if ((headerID >= 0x70) && (headerID <= 0x7F)) {
return sequenceUserDefined[headerID - 0x70];
return mSequenceUserDefined[headerID - 0x70];
}
// Verify that it was not a byte user defined header
if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
return byteUserDefined[headerID - 0xB0];
return mByteUserDefined[headerID - 0xB0];
}
// Verify that it was not a itneger user defined header
// Verify that it was not a integer user defined header
if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
return integerUserDefined[headerID - 0xF0];
return mIntegerUserDefined[headerID - 0xF0];
}
throw new IllegalArgumentException("Invalid Header Identifier");
}
@@ -478,63 +515,63 @@ public final class HeaderSet {
public int[] getHeaderList() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
if (count != null) {
if (mCount != null) {
out.write(COUNT);
}
if (name != null) {
if (mName != null) {
out.write(NAME);
}
if (type != null) {
if (mType != null) {
out.write(TYPE);
}
if (length != null) {
if (mLength != null) {
out.write(LENGTH);
}
if (isoTime != null) {
if (mIsoTime != null) {
out.write(TIME_ISO_8601);
}
if (byteTime != null) {
if (mByteTime != null) {
out.write(TIME_4_BYTE);
}
if (description != null) {
if (mDescription != null) {
out.write(DESCRIPTION);
}
if (target != null) {
if (mTarget != null) {
out.write(TARGET);
}
if (http != null) {
if (mHttpHeader != null) {
out.write(HTTP);
}
if (who != null) {
if (mWho != null) {
out.write(WHO);
}
if (appParam != null) {
if (mAppParam != null) {
out.write(APPLICATION_PARAMETER);
}
if (objectClass != null) {
if (mObjectClass != null) {
out.write(OBJECT_CLASS);
}
for (int i = 0x30; i < 0x40; i++) {
if (unicodeUserDefined[i - 0x30] != null) {
if (mUnicodeUserDefined[i - 0x30] != null) {
out.write(i);
}
}
for (int i = 0x70; i < 0x80; i++) {
if (sequenceUserDefined[i - 0x70] != null) {
if (mSequenceUserDefined[i - 0x70] != null) {
out.write(i);
}
}
for (int i = 0xB0; i < 0xC0; i++) {
if (byteUserDefined[i - 0xB0] != null) {
if (mByteUserDefined[i - 0xB0] != null) {
out.write(i);
}
}
for (int i = 0xF0; i < 0x100; i++) {
if (integerUserDefined[i - 0xF0] != null) {
if (mIntegerUserDefined[i - 0xF0] != null) {
out.write(i);
}
}
@@ -572,18 +609,20 @@ public final class HeaderSet {
* @param access if <code>true</code> then full access will be granted if
* successful; if <code>false</code> then read-only access will be granted
* if successful
* @throws IOException
*/
public void createAuthenticationChallenge(String realm, boolean userID, boolean access) {
public void createAuthenticationChallenge(String realm, boolean userID, boolean access)
throws IOException {
try {
nonce = new byte[16];
for (int i = 0; i < 16; i++) {
nonce[i] = (byte)random.nextInt();
nonce[i] = (byte)mRandom.nextInt();
}
authChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID);
mAuthChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID);
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
throw e;
}
}

View File

@@ -48,15 +48,17 @@ import java.util.TimeZone;
*/
public final class ObexHelper {
/** Prevent object construction of helper class */
private ObexHelper() {}
/**
* Defines the OBEX CONTINUE response code.
* <P>
* The value of <code>OBEX_HTTP_CONTINUE</code> is 0x90 (144).
* Defines the basic packet length used by OBEX. Every OBEX packet has the
* same basic format:<BR>
* Byte 0: Request or Response Code
* Byte 1&2: Length of the packet.
*/
public static final int OBEX_HTTP_CONTINUE = 0x90;
public static final int BASE_PACKET_LENGTH = 3;
/** Prevent object construction of helper class */
private ObexHelper() {
}
/**
* The maximum packet size for OBEX packets that this client can handle.
@@ -73,6 +75,48 @@ public final class ObexHelper {
*/
public static final int MAX_PACKET_SIZE_INT = 0xFFFE;
public static final int OBEX_OPCODE_CONNECT = 0x80;
public static final int OBEX_OPCODE_DISCONNECT = 0x81;
public static final int OBEX_OPCODE_PUT = 0x02;
public static final int OBEX_OPCODE_PUT_FINAL = 0x82;
public static final int OBEX_OPCODE_GET = 0x03;
public static final int OBEX_OPCODE_GET_FINAL = 0x83;
public static final int OBEX_OPCODE_RESERVED = 0x04;
public static final int OBEX_OPCODE_RESERVED_FINAL = 0x84;
public static final int OBEX_OPCODE_SETPATH = 0x85;
public static final int OBEX_OPCODE_ABORT = 0xFF;
public static final int OBEX_AUTH_REALM_CHARSET_ASCII = 0x00;
public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_1 = 0x01;
public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_2 = 0x02;
public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_3 = 0x03;
public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_4 = 0x04;
public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_5 = 0x05;
public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_6 = 0x06;
public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_7 = 0x07;
public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_8 = 0x08;
public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_9 = 0x09;
public static final int OBEX_AUTH_REALM_CHARSET_UNICODE = 0xFF;
/**
* Updates the HeaderSet with the headers received in the byte array
* provided. Invalid headers are ignored.
@@ -153,37 +197,25 @@ public final class ObexHelper {
value.length - 1, "ISO8859_1"));
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("ISO8859_1 is not supported"
+ e.getMessage());
throw e;
}
break;
// This is the constant for the authentication challenge header
// This header does not have a constant defined in the Java
// OBEX API
case 0x4D:
headerImpl.authChall = new byte[length];
System.arraycopy(headerArray, index, headerImpl.authChall, 0,
case HeaderSet.AUTH_CHALLENGE:
headerImpl.mAuthChall = new byte[length];
System.arraycopy(headerArray, index, headerImpl.mAuthChall, 0,
length);
break;
// This is the constant for the authentication response header
// This header does not have a constant defined in the Java
// OBEX API
case 0x4E:
headerImpl.authResp = new byte[length];
System
.arraycopy(headerArray, index, headerImpl.authResp, 0,
length);
case HeaderSet.AUTH_RESPONSE:
headerImpl.mAuthResp = new byte[length];
System.arraycopy(headerArray, index, headerImpl.mAuthResp, 0,
length);
break;
/*
* These two case statements are for the body (0x48)
* and end of body (0x49) headers.
*/
case 0x48:
case HeaderSet.BODY:
/* Fall Through */
case 0x49:
case HeaderSet.END_OF_BODY:
body = new byte[length + 1];
body[0] = (byte)headerID;
System.arraycopy(headerArray, index, body, 1, length);
@@ -211,24 +243,16 @@ public final class ObexHelper {
.substring(13, 15)));
headerImpl.setHeader(HeaderSet.TIME_ISO_8601, temp);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("ISO8859_1 is not supported"
+ e.getMessage());
} catch (Exception e) {
throw new IOException(
"Time Header does not follow ISO 8601 standard");
throw e;
}
break;
default:
try {
if ((headerID & 0xC0) == 0x00) {
headerImpl.setHeader(headerID, ObexHelper.convertToUnicode(
value, true));
} else {
headerImpl.setHeader(headerID, value);
}
} catch (Exception e) {
// Not a valid header so ignore
if ((headerID & 0xC0) == 0x00) {
headerImpl.setHeader(headerID, ObexHelper.convertToUnicode(
value, true));
} else {
headerImpl.setHeader(headerID, value);
}
}
@@ -262,9 +286,9 @@ public final class ObexHelper {
if (headerID != HeaderSet.TIME_4_BYTE) {
// Determine if it is a connection ID. These
// need to be handled differently
if (headerID == 0xCB) {
headerImpl.connectionID = new byte[4];
System.arraycopy(value, 0, headerImpl.connectionID, 0, 4);
if (headerID == HeaderSet.CONNECTION_ID) {
headerImpl.mConnectionID = new byte[4];
System.arraycopy(value, 0, headerImpl.mConnectionID, 0, 4);
} else {
headerImpl.setHeader(headerID, Long
.valueOf(convertToLong(value)));
@@ -328,10 +352,10 @@ public final class ObexHelper {
* Determine if there is a connection ID to send. If there is,
* then it should be the first header in the packet.
*/
if ((headImpl.connectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
if ((headImpl.mConnectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
out.write((byte)0xCB);
out.write(headImpl.connectionID);
out.write((byte)HeaderSet.CONNECTION_ID);
out.write(headImpl.mConnectionID);
}
// Count Header
@@ -351,8 +375,8 @@ public final class ObexHelper {
out.write((byte)HeaderSet.NAME);
value = ObexHelper.convertToUnicodeByteArray(stringHeader);
length = value.length + 3;
lengthArray[0] = (byte)(255 & (length >> 8));
lengthArray[1] = (byte)(255 & length);
lengthArray[0] = (byte)(0xFF & (length >> 8));
lengthArray[1] = (byte)(0xFF & length);
out.write(lengthArray);
out.write(value);
if (nullOut) {
@@ -367,7 +391,7 @@ public final class ObexHelper {
try {
value = stringHeader.getBytes("ISO8859_1");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unsupported Encoding Scheme: " + e.getMessage());
throw e;
}
length = value.length + 4;
@@ -440,7 +464,7 @@ public final class ObexHelper {
try {
value = buffer.toString().getBytes("ISO8859_1");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UnsupportedEncodingException: " + e.getMessage());
throw e;
}
length = value.length + 3;
@@ -612,28 +636,28 @@ public final class ObexHelper {
}
// Add the authentication challenge header
if (headImpl.authChall != null) {
out.write((byte)0x4D);
length = headImpl.authChall.length + 3;
if (headImpl.mAuthChall != null) {
out.write((byte)HeaderSet.AUTH_CHALLENGE);
length = headImpl.mAuthChall.length + 3;
lengthArray[0] = (byte)(255 & (length >> 8));
lengthArray[1] = (byte)(255 & length);
out.write(lengthArray);
out.write(headImpl.authChall);
out.write(headImpl.mAuthChall);
if (nullOut) {
headImpl.authChall = null;
headImpl.mAuthChall = null;
}
}
// Add the authentication response header
if (headImpl.authResp != null) {
out.write((byte)0x4E);
length = headImpl.authResp.length + 3;
if (headImpl.mAuthResp != null) {
out.write((byte)HeaderSet.AUTH_RESPONSE);
length = headImpl.mAuthResp.length + 3;
lengthArray[0] = (byte)(255 & (length >> 8));
lengthArray[1] = (byte)(255 & length);
out.write(lengthArray);
out.write(headImpl.authResp);
out.write(headImpl.mAuthResp);
if (nullOut) {
headImpl.authResp = null;
headImpl.mAuthResp = null;
}
}

View File

@@ -47,8 +47,180 @@ import java.io.IOException;
*
* @hide
*/
public interface ObexSession {
public class ObexSession {
public void close() throws IOException;
protected Authenticator mAuthenticator;
protected byte[] mChallengeDigest;
/**
* Called when the server received an authentication challenge header. This
* will cause the authenticator to handle the authentication challenge.
*
* @param header
* the header with the authentication challenge
*
* @return <code>true</code> if the last request should be resent;
* <code>false</code> if the last request should not be resent
* @throws IOException
*/
public boolean handleAuthChall(HeaderSet header) throws IOException {
if (mAuthenticator == null) {
return false;
}
/*
* An authentication challenge is made up of one required and two
* optional tag length value triplets. The tag 0x00 is required to be in
* the authentication challenge and it represents the challenge digest
* that was received. The tag 0x01 is the options tag. This tag tracks
* if user ID is required and if full access will be granted. The tag
* 0x02 is the realm, which provides a description of which user name
* and password to use.
*/
byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.mAuthChall);
byte[] option = ObexHelper.getTagValue((byte)0x01, header.mAuthChall);
byte[] description = ObexHelper.getTagValue((byte)0x02, header.mAuthChall);
String realm = null;
if (description != null) {
byte[] realmString = new byte[description.length - 1];
System.arraycopy(description, 1, realmString, 0, realmString.length);
switch (description[0] & 0xFF) {
case ObexHelper.OBEX_AUTH_REALM_CHARSET_ASCII:
// ASCII encoding
// Fall through
case ObexHelper.OBEX_AUTH_REALM_CHARSET_ISO_8859_1:
// ISO-8859-1 encoding
try {
realm = new String(realmString, "ISO8859_1");
} catch (Exception e) {
throw new IOException("Unsupported Encoding Scheme");
}
break;
case ObexHelper.OBEX_AUTH_REALM_CHARSET_UNICODE:
// UNICODE Encoding
realm = ObexHelper.convertToUnicode(realmString, false);
break;
default:
throw new IOException("Unsupported Encoding Scheme");
}
}
boolean isUserIDRequired = false;
boolean isFullAccess = true;
if (option != null) {
if ((option[0] & 0x01) != 0) {
isUserIDRequired = true;
}
if ((option[0] & 0x02) != 0) {
isFullAccess = false;
}
}
PasswordAuthentication result = null;
header.mAuthChall = null;
try {
result = mAuthenticator
.onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
} catch (Exception e) {
return false;
}
/*
* If no password is provided then we not resent the request
*/
if (result == null) {
return false;
}
byte[] password = result.getPassword();
if (password == null) {
return false;
}
byte[] userName = result.getUserName();
/*
* Create the authentication response header. It includes 1 required and
* 2 option tag length value triples. The required triple has a tag of
* 0x00 and is the response digest. The first optional tag is 0x01 and
* represents the user ID. If no user ID is provided, then no user ID
* will be sent. The second optional tag is 0x02 and is the challenge
* that was received. This will always be sent
*/
if (userName != null) {
header.mAuthResp = new byte[38 + userName.length];
header.mAuthResp[36] = (byte)0x01;
header.mAuthResp[37] = (byte)userName.length;
System.arraycopy(userName, 0, header.mAuthResp, 38, userName.length);
} else {
header.mAuthResp = new byte[36];
}
// Create the secret String
byte[] digest = new byte[challenge.length + password.length + 1];
System.arraycopy(challenge, 0, digest, 0, challenge.length);
// Insert colon between challenge and password
digest[challenge.length] = (byte)0x3A;
System.arraycopy(password, 0, digest, challenge.length + 1, password.length);
// Add the Response Digest
header.mAuthResp[0] = (byte)0x00;
header.mAuthResp[1] = (byte)0x10;
System.arraycopy(ObexHelper.computeMd5Hash(digest), 0, header.mAuthResp, 2, 16);
// Add the challenge
header.mAuthResp[18] = (byte)0x02;
header.mAuthResp[19] = (byte)0x10;
System.arraycopy(challenge, 0, header.mAuthResp, 20, 16);
return true;
}
/**
* Called when the server received an authentication response header. This
* will cause the authenticator to handle the authentication response.
*
* @param authResp
* the authentication response
*
* @return <code>true</code> if the response passed; <code>false</code> if
* the response failed
*/
public boolean handleAuthResp(byte[] authResp) {
if (mAuthenticator == null) {
return false;
}
// get the correct password from the application
byte[] correctPassword = mAuthenticator.onAuthenticationResponse(ObexHelper.getTagValue(
(byte)0x01, authResp));
if (correctPassword == null) {
return false;
}
byte[] temp = new byte[correctPassword.length + 16];
System.arraycopy(mChallengeDigest, 0, temp, 0, 16);
System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length);
byte[] correctResponse = ObexHelper.computeMd5Hash(temp);
byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp);
// compare the MD5 hash array .
for (int i = 0; i < 16; i++) {
if (correctResponse[i] != actualResponse[i]) {
return false;
}
}
return true;
}
}

View File

@@ -137,7 +137,7 @@ public interface Operation {
* @throws IOException if the transaction has already ended or if an
* OBEX server calls this method
*/
public void abort() throws IOException;
void abort() throws IOException;
/**
* Returns the headers that have been received during the operation.
@@ -148,7 +148,7 @@ public interface Operation {
*
* @throws IOException if this <code>Operation</code> has been closed
*/
public HeaderSet getReceivedHeaders() throws IOException;
HeaderSet getReceivedHeader() throws IOException;
/**
* Specifies the headers that should be sent in the next OBEX message that
@@ -165,7 +165,7 @@ public interface Operation {
*
* @throws NullPointerException if <code>headers</code> if <code>null</code>
*/
public void sendHeaders(HeaderSet headers) throws IOException;
void sendHeaders(HeaderSet headers) throws IOException;
/**
* Returns the response code received from the server. Response codes
@@ -178,23 +178,23 @@ public interface Operation {
* @throws IOException if an error occurred in the transport layer during
* the transaction; if this object was created by an OBEX server
*/
public int getResponseCode() throws IOException;
int getResponseCode() throws IOException;
public String getEncoding();
String getEncoding();
public long getLength();
long getLength();
public String getType();
String getType();
public InputStream openInputStream() throws IOException;
InputStream openInputStream() throws IOException;
public DataInputStream openDataInputStream() throws IOException;
DataInputStream openDataInputStream() throws IOException;
public OutputStream openOutputStream() throws IOException;
OutputStream openOutputStream() throws IOException;
public DataOutputStream openDataOutputStream() throws IOException;
DataOutputStream openDataOutputStream() throws IOException;
public void close() throws IOException;
void close() throws IOException;
public int getMaxPacketSize();
int getMaxPacketSize();
}

View File

@@ -37,11 +37,11 @@ package javax.obex;
*
* @hide
*/
public class PasswordAuthentication {
public final class PasswordAuthentication {
private byte[] userName;
private byte[] mUserName;
private byte[] password;
private final byte[] mPassword;
/**
* Creates a new <code>PasswordAuthentication</code> with the user name
@@ -51,17 +51,17 @@ public class PasswordAuthentication {
*
* @param password the password to include in the response
*
* @exception NullPointerException if <code>password</code> is
* @throws NullPointerException if <code>password</code> is
* <code>null</code>
*/
public PasswordAuthentication(byte[] userName, byte[] password) {
public PasswordAuthentication(final byte[] userName, final byte[] password) {
if (userName != null) {
this.userName = new byte[userName.length];
System.arraycopy(userName, 0, this.userName, 0, userName.length);
mUserName = new byte[userName.length];
System.arraycopy(userName, 0, mUserName, 0, userName.length);
}
this.password = new byte[password.length];
System.arraycopy(password, 0, this.password, 0, password.length);
mPassword = new byte[password.length];
System.arraycopy(password, 0, mPassword, 0, password.length);
}
/**
@@ -71,7 +71,7 @@ public class PasswordAuthentication {
* @return the user name
*/
public byte[] getUserName() {
return this.userName;
return mUserName;
}
/**
@@ -80,6 +80,6 @@ public class PasswordAuthentication {
* @return the password
*/
public byte[] getPassword() {
return this.password;
return mPassword;
}
}

View File

@@ -39,23 +39,17 @@ import java.io.IOException;
* This object provides an input stream to the Operation objects used in this
* package.
*
* TODO: Include the other read() methods defined in InputStream.
*
* @hide
*/
public class PrivateInputStream extends InputStream {
public final class PrivateInputStream extends InputStream {
private BaseStream parent;
private BaseStream mParent;
private byte[] data;
private byte[] mData;
private int index;
private int mIndex;
private boolean isOpen;
public PrivateInputStream() {
}
private boolean mOpen;
/**
* Creates an input stream for the <code>Operation</code> to read from
@@ -63,10 +57,10 @@ public class PrivateInputStream extends InputStream {
* @param p the connection this input stream is for
*/
public PrivateInputStream(BaseStream p) {
parent = p;
data = new byte[0];
index = 0;
isOpen = true;
mParent = p;
mData = new byte[0];
mIndex = 0;
mOpen = true;
}
/**
@@ -83,7 +77,7 @@ public class PrivateInputStream extends InputStream {
@Override
public synchronized int available() throws IOException {
ensureOpen();
return data.length - index;
return mData.length - mIndex;
}
/**
@@ -101,12 +95,12 @@ public class PrivateInputStream extends InputStream {
@Override
public synchronized int read() throws IOException {
ensureOpen();
while (data.length == index) {
if (!parent.continueOperation(true, true)) {
while (mData.length == mIndex) {
if (!mParent.continueOperation(true, true)) {
return -1;
}
}
return (data[index++] & 0xFF);
return (mData[mIndex++] & 0xFF);
}
@Override
@@ -118,33 +112,33 @@ public class PrivateInputStream extends InputStream {
public synchronized int read(byte[] b, int offset, int length) throws IOException {
if (b == null) {
throw new NullPointerException("buffer is null");
throw new IOException("buffer is null");
}
if ((offset | length) < 0 || length > b.length - offset) {
throw new ArrayIndexOutOfBoundsException("index outof bound");
}
ensureOpen();
int currentDataLength = data.length - index;
int currentDataLength = mData.length - mIndex;
int remainReadLength = length;
int offset1 = offset;
int result = 0;
while (currentDataLength <= remainReadLength) {
System.arraycopy(data, index, b, offset1, currentDataLength);
index += currentDataLength;
System.arraycopy(mData, mIndex, b, offset1, currentDataLength);
mIndex += currentDataLength;
offset1 += currentDataLength;
result += currentDataLength;
remainReadLength -= currentDataLength;
if (!parent.continueOperation(true, true)) {
if (!mParent.continueOperation(true, true)) {
return result == 0 ? -1 : result;
}
currentDataLength = data.length - index;
currentDataLength = mData.length - mIndex;
}
if (remainReadLength > 0) {
System.arraycopy(data, index, b, offset1, remainReadLength);
index += remainReadLength;
System.arraycopy(mData, mIndex, b, offset1, remainReadLength);
mIndex += remainReadLength;
result += remainReadLength;
}
return result;
@@ -160,14 +154,14 @@ public class PrivateInputStream extends InputStream {
*/
public synchronized void writeBytes(byte[] body, int start) {
int length = (body.length - start) + (data.length - index);
int length = (body.length - start) + (mData.length - mIndex);
byte[] temp = new byte[length];
System.arraycopy(data, index, temp, 0, data.length - index);
System.arraycopy(body, start, temp, data.length - index, body.length - start);
System.arraycopy(mData, mIndex, temp, 0, mData.length - mIndex);
System.arraycopy(body, start, temp, mData.length - mIndex, body.length - start);
data = temp;
index = 0;
mData = temp;
mIndex = 0;
notifyAll();
}
@@ -177,8 +171,8 @@ public class PrivateInputStream extends InputStream {
* @throws IOException if the stream is not open
*/
private void ensureOpen() throws IOException {
parent.ensureOpen();
if (!isOpen) {
mParent.ensureOpen();
if (!mOpen) {
throw new IOException("Input stream is closed");
}
}
@@ -191,7 +185,7 @@ public class PrivateInputStream extends InputStream {
*/
@Override
public void close() throws IOException {
isOpen = false;
parent.streamClosed(true);
mOpen = false;
mParent.streamClosed(true);
}
}

View File

@@ -42,15 +42,15 @@ import java.io.ByteArrayOutputStream;
*
* @hide
*/
class PrivateOutputStream extends OutputStream {
public final class PrivateOutputStream extends OutputStream {
private BaseStream parent;
private BaseStream mParent;
private ByteArrayOutputStream output;
private ByteArrayOutputStream mArray;
private boolean isClosed;
private boolean mOpen;
private int maxPacketSize;
private int mMaxPacketSize;
/**
* Creates an empty <code>PrivateOutputStream</code> to write to.
@@ -58,9 +58,9 @@ class PrivateOutputStream extends OutputStream {
* @param p the connection that this stream runs over
*/
public PrivateOutputStream(BaseStream p, int maxSize) {
parent = p;
output = new ByteArrayOutputStream();
maxPacketSize = maxSize;
mParent = p;
mArray = new ByteArrayOutputStream();
mMaxPacketSize = maxSize;
}
/**
@@ -68,8 +68,8 @@ class PrivateOutputStream extends OutputStream {
*
* @return the number of bytes written to the output stream
*/
protected int size() {
return output.size();
public int size() {
return mArray.size();
}
/**
@@ -85,10 +85,10 @@ class PrivateOutputStream extends OutputStream {
@Override
public synchronized void write(int b) throws IOException {
ensureOpen();
parent.ensureNotDone();
output.write(b);
if (output.size() == maxPacketSize) {
parent.continueOperation(true, false);
mParent.ensureNotDone();
mArray.write(b);
if (mArray.size() == mMaxPacketSize) {
mParent.continueOperation(true, false);
}
}
@@ -103,44 +103,29 @@ class PrivateOutputStream extends OutputStream {
int remainLength = count;
if (buffer == null) {
throw new NullPointerException("buffer is null");
throw new IOException("buffer is null");
}
if ((offset | count) < 0 || count > buffer.length - offset) {
throw new IndexOutOfBoundsException("index outof bound");
}
ensureOpen();
parent.ensureNotDone();
if (count < maxPacketSize) {
output.write(buffer, offset, count);
mParent.ensureNotDone();
if (count < mMaxPacketSize) {
mArray.write(buffer, offset, count);
} else {
while (remainLength >= maxPacketSize) {
output.write(buffer, offset1, maxPacketSize);
offset1 += maxPacketSize;
while (remainLength >= mMaxPacketSize) {
mArray.write(buffer, offset1, mMaxPacketSize);
offset1 += mMaxPacketSize;
remainLength = count - offset1;
parent.continueOperation(true, false);
mParent.continueOperation(true, false);
}
if (remainLength > 0) {
output.write(buffer, offset1, remainLength);
mArray.write(buffer, offset1, remainLength);
}
}
}
/**
* Reads the bytes that have been written to this stream.
*
* @return the byte array that is written
*/
protected synchronized byte[] readBytes() {
if (output.size() > 0) {
byte[] result = output.toByteArray();
output.reset();
return result;
} else {
return null;
}
}
/**
* Reads the bytes that have been written to this stream.
*
@@ -148,14 +133,14 @@ class PrivateOutputStream extends OutputStream {
*
* @return the byte array that is written
*/
protected synchronized byte[] readBytes(int size) {
if (output.size() > 0) {
byte[] temp = output.toByteArray();
output.reset();
public synchronized byte[] readBytes(int size) {
if (mArray.size() > 0) {
byte[] temp = mArray.toByteArray();
mArray.reset();
byte[] result = new byte[size];
System.arraycopy(temp, 0, result, 0, size);
if (temp.length != size) {
output.write(temp, size, temp.length - size);
mArray.write(temp, size, temp.length - size);
}
return result;
} else {
@@ -169,8 +154,8 @@ class PrivateOutputStream extends OutputStream {
* @throws IOException if the stream is not open
*/
private void ensureOpen() throws IOException {
parent.ensureOpen();
if (isClosed) {
mParent.ensureOpen();
if (!mOpen) {
throw new IOException("Output stream is closed");
}
}
@@ -183,8 +168,8 @@ class PrivateOutputStream extends OutputStream {
*/
@Override
public void close() throws IOException {
isClosed = true;
parent.streamClosed(false);
mOpen = false;
mParent.streamClosed(false);
}
/**
@@ -193,7 +178,7 @@ class PrivateOutputStream extends OutputStream {
* @return <code>true</code> if the connection is closed;
* <code>false</code> if the connection is open
*/
protected boolean isClosed() {
return isClosed;
public boolean isClosed() {
return !mOpen;
}
}

View File

@@ -38,11 +38,8 @@ package javax.obex;
* <P>
* <STRONG>IMPORTANT NOTE</STRONG>
* <P>
* It is important to note that these values are different then those defined
* in <code>javax.microedition.io.HttpConnection</code>. The values in this
* interface represent the values defined in the IrOBEX specification. The
* values in <code>javax.microedition.io.HttpConnection</code> represent values
* defined in the HTTP specification.
* The values in this interface represent the values defined in the IrOBEX
* specification, which is different with the HTTP specification.
* <P>
* <code>OBEX_DATABASE_FULL</code> and <code>OBEX_DATABASE_LOCKED</code> require
* further description since they are not defined in HTTP. The server will send
@@ -54,7 +51,14 @@ package javax.obex;
*
* @hide
*/
public class ResponseCodes {
public final class ResponseCodes {
/**
* Defines the OBEX CONTINUE response code.
* <P>
* The value of <code>OBEX_HTTP_CONTINUE</code> is 0x90 (144).
*/
public static final int OBEX_HTTP_CONTINUE = 0x90;
/**
* Defines the OBEX SUCCESS response code.
@@ -318,5 +322,6 @@ public class ResponseCodes {
/**
* Constructor does nothing.
*/
private ResponseCodes() {}
private ResponseCodes() {
}
}

View File

@@ -48,7 +48,7 @@ import java.io.ByteArrayOutputStream;
* additional OBEX packet. 0x82 is a PUT request that says that request is
* complete. In this case, the server can begin sending the response. The
* 0x03 is a GET request that signals that the request is not finished. When
* the server receives a 0x83, the client is signalling the server that it is
* the server receives a 0x83, the client is signaling the server that it is
* done with its request.
*
* TODO: Extend the ClientOperation and reuse the methods defined
@@ -56,52 +56,44 @@ import java.io.ByteArrayOutputStream;
*
* @hide
*/
public class ServerOperation implements Operation, BaseStream {
public final class ServerOperation implements Operation, BaseStream {
private InputStream socketInput;
public boolean isAborted;
private ServerSession parent;
public HeaderSet requestHeader;
private int maxPacketLength;
public HeaderSet replyHeader;
private int responseSize;
public boolean finalBitSet;
private boolean isClosed;
private InputStream mInput;
boolean finalBitSet;
private ServerSession mParent;
// This variable defines when the end of body
// header has been received. When this header
// is received, no further body data will be
// received from the client
private boolean endOfBody;
private int mMaxPacketLength;
private boolean isGet;
private int mResponseSize;
boolean isAborted;
private boolean mClosed;
HeaderSet requestHeaders;
private boolean mGetOperation;
HeaderSet replyHeaders;
private PrivateInputStream mPrivateInput;
PrivateInputStream privateInput;
private PrivateOutputStream mPrivateOutput;
private PrivateOutputStream privateOutput;
private boolean mPrivateOutputOpen;
private String exceptionString;
private String mExceptionString;
private ServerRequestHandler listener;
private ServerRequestHandler mListener;
private boolean outputStreamOpened;
private boolean mRequestFinished;
private boolean requestFinished;
private static final int BASE_PACKET_LENGTH = 3;
private boolean isHasBody;
private boolean mHasBody;
/**
* Creates new PutServerOperation
* Creates new ServerOperation
*
* @param p the parent that created this object
*
@@ -121,19 +113,18 @@ public class ServerOperation implements Operation, BaseStream {
ServerRequestHandler listen) throws IOException {
isAborted = false;
parent = p;
socketInput = in;
maxPacketLength = maxSize;
isClosed = false;
requestHeaders = new HeaderSet();
replyHeaders = new HeaderSet();
privateInput = new PrivateInputStream(this);
endOfBody = false;
responseSize = 3;
listener = listen;
requestFinished = false;
outputStreamOpened = false;
isHasBody = false;
mParent = p;
mInput = in;
mMaxPacketLength = maxSize;
mClosed = false;
requestHeader = new HeaderSet();
replyHeader = new HeaderSet();
mPrivateInput = new PrivateInputStream(this);
mResponseSize = 3;
mListener = listen;
mRequestFinished = false;
mPrivateOutputOpen = false;
mHasBody = false;
int bytesReceived;
/*
@@ -143,12 +134,12 @@ public class ServerOperation implements Operation, BaseStream {
/*
* It is a PUT request.
*/
isGet = false;
mGetOperation = false;
} else {
/*
* It is a GET request.
*/
isGet = true;
mGetOperation = true;
}
/*
@@ -158,7 +149,7 @@ public class ServerOperation implements Operation, BaseStream {
finalBitSet = false;
} else {
finalBitSet = true;
requestFinished = true;
mRequestFinished = true;
}
int length = in.read();
@@ -168,7 +159,7 @@ public class ServerOperation implements Operation, BaseStream {
* Determine if the packet length is larger than this device can receive
*/
if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
parent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
throw new IOException("Packet received was too large");
}
@@ -183,81 +174,69 @@ public class ServerOperation implements Operation, BaseStream {
bytesReceived += in.read(data, bytesReceived, data.length - bytesReceived);
}
byte[] body = ObexHelper.updateHeaderSet(requestHeaders, data);
byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);
if (body != null) {
isHasBody = true;
mHasBody = true;
}
if (requestHeaders.connectionID != null) {
listener.setConnectionID(ObexHelper.convertToLong(requestHeaders.connectionID));
if (requestHeader.mConnectionID != null) {
mListener.setConnectionId(ObexHelper.convertToLong(requestHeader.mConnectionID));
} else {
listener.setConnectionID(0);
mListener.setConnectionId(0);
}
if (requestHeaders.authResp != null) {
if (!parent.handleAuthResp(requestHeaders.authResp)) {
exceptionString = "Authentication Failed";
parent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
isClosed = true;
requestHeaders.authResp = null;
if (requestHeader.mAuthResp != null) {
if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
mExceptionString = "Authentication Failed";
mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
mClosed = true;
requestHeader.mAuthResp = null;
return;
}
}
if (requestHeaders.authChall != null) {
parent.handleAuthChall(requestHeaders);
if (requestHeader.mAuthChall != null) {
mParent.handleAuthChall(requestHeader);
// send the authResp to the client
replyHeaders.authResp = new byte[requestHeaders.authResp.length];
System.arraycopy(requestHeaders.authResp, 0, replyHeaders.authResp, 0,
replyHeaders.authResp.length);
requestHeaders.authResp = null;
requestHeaders.authChall = null;
replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
replyHeader.mAuthResp.length);
requestHeader.mAuthResp = null;
requestHeader.mAuthChall = null;
}
if (body != null) {
/*
* 0x49 is the end of body header. This signifies that no more
* body data will be sent from the client
*/
if (body[0] == 0x49) {
endOfBody = true;
}
//privateInput.writeBytes(body, body.length);
//byte [] body_tmp = new byte[body.length-1];
//System.arraycopy(body,1,body_tmp,0,body.length-1);
//privateInput.writeBytes(body_tmp, body.length-1);
privateInput.writeBytes(body, 1);
mPrivateInput.writeBytes(body, 1);
} else {
while ((!isGet) && (!finalBitSet)) {
sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
if (privateInput.available() > 0) {
while ((!mGetOperation) && (!finalBitSet)) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
if (mPrivateInput.available() > 0) {
break;
}
}
}// if (body != null)
}
}
}// if (length > 3)
while ((!isGet) && (!finalBitSet) && (privateInput.available() == 0)) {
sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
if (privateInput.available() > 0) {
while ((!mGetOperation) && (!finalBitSet) && (mPrivateInput.available() == 0)) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
if (mPrivateInput.available() > 0) {
break;
}
}
// wait for get request finished !!!!
while (isGet && !finalBitSet) {
sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
while (mGetOperation && !finalBitSet) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
}
if (finalBitSet && isGet) {
requestFinished = true;
if (finalBitSet && mGetOperation) {
mRequestFinished = true;
}
}
public synchronized boolean isValidBody() {
return isHasBody;
public boolean isValidBody() {
return mHasBody;
}
/**
@@ -268,21 +247,21 @@ public class ServerOperation implements Operation, BaseStream {
* operation even if no headers will be sent; if <code>false</code> then
* this method will only continue the operation if there are headers to
* send
* @param isStream if<code>true</code> the stream is input stream or
* is outputstream
* @param isStream if<code>true</code> the stream is input stream, otherwise
* output stream
* @return <code>true</code> if the operation was completed;
* <code>false</code> if no operation took place
*/
public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
throws IOException {
if (!isGet) {
if (!mGetOperation) {
if (!finalBitSet) {
if (sendEmpty) {
sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
return true;
} else {
if ((responseSize > 3) || (privateOutput.size() > 0)) {
sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
if ((mResponseSize > 3) || (mPrivateOutput.size() > 0)) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
return true;
} else {
return false;
@@ -292,7 +271,7 @@ public class ServerOperation implements Operation, BaseStream {
return false;
}
} else {
sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
return true;
}
}
@@ -309,52 +288,52 @@ public class ServerOperation implements Operation, BaseStream {
*
* @throws IOException if an IO error occurs
*/
protected synchronized boolean sendReply(int type) throws IOException {
public synchronized boolean sendReply(int type) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int bytesReceived;
long id = listener.getConnectionID();
long id = mListener.getConnectionId();
if (id == -1) {
replyHeaders.connectionID = null;
replyHeader.mConnectionID = null;
} else {
replyHeaders.connectionID = ObexHelper.convertToByteArray(id);
replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
}
byte[] headerArray = ObexHelper.createHeader(replyHeaders, true);
byte[] headerArray = ObexHelper.createHeader(replyHeader, true);
int bodyLength = -1;
int orginalBodyLength = -1;
if (privateOutput != null) {
bodyLength = privateOutput.size();
if (mPrivateOutput != null) {
bodyLength = mPrivateOutput.size();
orginalBodyLength = bodyLength;
}
if ((BASE_PACKET_LENGTH + headerArray.length) > maxPacketLength) {
if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) {
int end = 0;
int start = 0;
while (end != headerArray.length) {
end = ObexHelper.findHeaderEnd(headerArray, start, maxPacketLength
- BASE_PACKET_LENGTH);
end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketLength
- ObexHelper.BASE_PACKET_LENGTH);
if (end == -1) {
isClosed = true;
mClosed = true;
if (privateInput != null) {
privateInput.close();
if (mPrivateInput != null) {
mPrivateInput.close();
}
if (privateOutput != null) {
privateOutput.close();
if (mPrivateOutput != null) {
mPrivateOutput.close();
}
parent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
mParent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
throw new IOException("OBEX Packet exceeds max packet size");
}
byte[] sendHeader = new byte[end - start];
System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
parent.sendResponse(type, sendHeader);
mParent.sendResponse(type, sendHeader);
start = end;
}
@@ -368,48 +347,25 @@ public class ServerOperation implements Operation, BaseStream {
out.write(headerArray);
}
/*
* Determine if there is space to add a body reply. First, we need to
* verify that the client is finished sending the request. Next, there
* needs to be enough space to send the headers already defined along
* with the reply header (3 bytes) and the body header identifier
* (3 bytes).
*/
/* if ((finalBitSet) &&
((bodyLength + 6 + headerArray.length) > maxPacketLength)) {
exceptionString = "Header larger then can be sent in a packet";
isClosed = true;
privateInput.close();
if (privateOutput != null) {
privateOutput.close();
}
parent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR,
null);
throw new IOException("OBEX Packet exceeds max packet size");
}
*/
if ((finalBitSet) || (headerArray.length < (maxPacketLength - 20))) {
if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) {
if (bodyLength > 0) {
/*
* Determine if I can send the whole body or just part of
* the body. Remember that there is the 3 bytes for the
* response message and 3 bytes for the header ID and length
*/
if (bodyLength > (maxPacketLength - headerArray.length - 6)) {
bodyLength = maxPacketLength - headerArray.length - 6;
if (bodyLength > (mMaxPacketLength - headerArray.length - 6)) {
bodyLength = mMaxPacketLength - headerArray.length - 6;
}
byte[] body = privateOutput.readBytes(bodyLength);
byte[] body = mPrivateOutput.readBytes(bodyLength);
/*
* Since this is a put request if the final bit is set or
* the output stream is closed we need to send the 0x49
* (End of Body) otherwise, we need to send 0x48 (Body)
*/
if ((finalBitSet) || (privateOutput.isClosed())) {
if ((finalBitSet) || (mPrivateOutput.isClosed())) {
out.write(0x49);
} else {
out.write(0x48);
@@ -430,44 +386,46 @@ public class ServerOperation implements Operation, BaseStream {
}
responseSize = 3;
parent.sendResponse(type, out.toByteArray());
mResponseSize = 3;
mParent.sendResponse(type, out.toByteArray());
if (type == ObexHelper.OBEX_HTTP_CONTINUE) {
int headerID = socketInput.read();
int length = socketInput.read();
length = (length << 8) + socketInput.read();
if ((headerID != 0x02) && (headerID != 0x82) && (headerID != 0x03)
&& (headerID != 0x83)) {
if (type == ResponseCodes.OBEX_HTTP_CONTINUE) {
int headerID = mInput.read();
int length = mInput.read();
length = (length << 8) + mInput.read();
if ((headerID != ObexHelper.OBEX_OPCODE_PUT)
&& (headerID != ObexHelper.OBEX_OPCODE_PUT_FINAL)
&& (headerID != ObexHelper.OBEX_OPCODE_GET)
&& (headerID != ObexHelper.OBEX_OPCODE_GET_FINAL)) {
if (length > 3) {
byte[] temp = new byte[length];
bytesReceived = socketInput.read(temp);
bytesReceived = mInput.read(temp);
while (bytesReceived != length) {
bytesReceived += socketInput.read(temp, bytesReceived, length
- bytesReceived);
bytesReceived += mInput.read(temp, bytesReceived, length - bytesReceived);
}
}
/*
* Determine if an ABORT was sent as the reply
*/
if (headerID == 0xFF) {
parent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
isClosed = true;
if (headerID == ObexHelper.OBEX_OPCODE_ABORT) {
mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
mClosed = true;
isAborted = true;
exceptionString = "Abort Received";
mExceptionString = "Abort Received";
throw new IOException("Abort Received");
} else {
parent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
isClosed = true;
exceptionString = "Bad Request Received";
mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
mClosed = true;
mExceptionString = "Bad Request Received";
throw new IOException("Bad Request Received");
}
} else {
if ((headerID == 0x82) || (headerID == 0x83)) {
if ((headerID == ObexHelper.OBEX_OPCODE_PUT_FINAL)
|| (headerID == ObexHelper.OBEX_OPCODE_GET_FINAL)) {
finalBitSet = true;
}
@@ -475,7 +433,7 @@ public class ServerOperation implements Operation, BaseStream {
* Determine if the packet length is larger then this device can receive
*/
if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
parent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
throw new IOException("Packet received was too large");
}
@@ -484,54 +442,46 @@ public class ServerOperation implements Operation, BaseStream {
*/
if (length > 3) {
byte[] data = new byte[length - 3];
bytesReceived = socketInput.read(data);
bytesReceived = mInput.read(data);
while (bytesReceived != data.length) {
bytesReceived += socketInput.read(data, bytesReceived, data.length
bytesReceived += mInput.read(data, bytesReceived, data.length
- bytesReceived);
}
byte[] body = ObexHelper.updateHeaderSet(requestHeaders, data);
byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);
if (body != null) {
isHasBody = true;
mHasBody = true;
}
if (requestHeaders.connectionID != null) {
listener.setConnectionID(ObexHelper
.convertToLong(requestHeaders.connectionID));
if (requestHeader.mConnectionID != null) {
mListener.setConnectionId(ObexHelper
.convertToLong(requestHeader.mConnectionID));
} else {
listener.setConnectionID(1);
mListener.setConnectionId(1);
}
if (requestHeaders.authResp != null) {
if (!parent.handleAuthResp(requestHeaders.authResp)) {
exceptionString = "Authentication Failed";
parent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
isClosed = true;
requestHeaders.authResp = null;
if (requestHeader.mAuthResp != null) {
if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
mExceptionString = "Authentication Failed";
mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
mClosed = true;
requestHeader.mAuthResp = null;
return false;
}
requestHeaders.authResp = null;
requestHeader.mAuthResp = null;
}
if (requestHeaders.authChall != null) {
parent.handleAuthChall(requestHeaders);
if (requestHeader.mAuthChall != null) {
mParent.handleAuthChall(requestHeader);
// send the auhtResp to the client
replyHeaders.authResp = new byte[requestHeaders.authResp.length];
System.arraycopy(requestHeaders.authResp, 0, replyHeaders.authResp, 0,
replyHeaders.authResp.length);
requestHeaders.authResp = null;
requestHeaders.authChall = null;
replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
replyHeader.mAuthResp.length);
requestHeader.mAuthResp = null;
requestHeader.mAuthChall = null;
}
if (body != null) {
if (body[0] == 0x49) {
endOfBody = true;
}
/*byte [] body_tmp = new byte[body.length-1];
System.arraycopy(body,1,body_tmp,0,body.length-1);
privateInput.writeBytes(body_tmp, body.length-1);*/
privateInput.writeBytes(body, 1);
mPrivateInput.writeBytes(body, 1);
}
}
}
@@ -562,9 +512,9 @@ public class ServerOperation implements Operation, BaseStream {
*
* @throws IOException if this <code>Operation</code> has been closed
*/
public HeaderSet getReceivedHeaders() throws IOException {
public HeaderSet getReceivedHeader() throws IOException {
ensureOpen();
return requestHeaders;
return requestHeader;
}
/**
@@ -583,13 +533,13 @@ public class ServerOperation implements Operation, BaseStream {
ensureOpen();
if (headers == null) {
throw new NullPointerException("Headers may not be null");
throw new IOException("Headers may not be null");
}
int[] headerList = headers.getHeaderList();
if (headerList != null) {
for (int i = 0; i < headerList.length; i++) {
replyHeaders.setHeader(headerList[i], headers.getHeader(headerList[i]));
replyHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
}
}
@@ -629,7 +579,7 @@ public class ServerOperation implements Operation, BaseStream {
*/
public String getType() {
try {
return (String)requestHeaders.getHeader(HeaderSet.TYPE);
return (String)requestHeader.getHeader(HeaderSet.TYPE);
} catch (IOException e) {
return null;
}
@@ -645,7 +595,7 @@ public class ServerOperation implements Operation, BaseStream {
*/
public long getLength() {
try {
Long temp = (Long)requestHeaders.getHeader(HeaderSet.LENGTH);
Long temp = (Long)requestHeader.getHeader(HeaderSet.LENGTH);
if (temp == null) {
return -1;
@@ -658,7 +608,7 @@ public class ServerOperation implements Operation, BaseStream {
}
public int getMaxPacketSize() {
return maxPacketLength - 6;
return mMaxPacketLength - 6;
}
/**
@@ -670,7 +620,7 @@ public class ServerOperation implements Operation, BaseStream {
*/
public InputStream openInputStream() throws IOException {
ensureOpen();
return privateInput;
return mPrivateInput;
}
/**
@@ -694,17 +644,19 @@ public class ServerOperation implements Operation, BaseStream {
public OutputStream openOutputStream() throws IOException {
ensureOpen();
if (outputStreamOpened)
if (mPrivateOutputOpen) {
throw new IOException("no more input streams available, stream already opened");
if (!requestFinished)
throw new IOException("no output streams available ,request not finished");
if (privateOutput == null) {
privateOutput = new PrivateOutputStream(this, maxPacketLength - 6);
}
outputStreamOpened = true;
return privateOutput;
if (!mRequestFinished) {
throw new IOException("no output streams available ,request not finished");
}
if (mPrivateOutput == null) {
mPrivateOutput = new PrivateOutputStream(this, mMaxPacketLength - 6);
}
mPrivateOutputOpen = true;
return mPrivateOutput;
}
/**
@@ -725,7 +677,7 @@ public class ServerOperation implements Operation, BaseStream {
*/
public void close() throws IOException {
ensureOpen();
isClosed = true;
mClosed = true;
}
/**
@@ -734,10 +686,10 @@ public class ServerOperation implements Operation, BaseStream {
* @throws IOException if an exception needs to be thrown
*/
public void ensureOpen() throws IOException {
if (exceptionString != null) {
throw new IOException(exceptionString);
if (mExceptionString != null) {
throw new IOException(mExceptionString);
}
if (isClosed) {
if (mClosed) {
throw new IOException("Operation has already ended");
}
}

View File

@@ -71,7 +71,7 @@ package javax.obex;
*/
public class ServerRequestHandler {
private long connectionID;
private long mConnectionId;
/**
* Creates a <code>ServerRequestHandler</code>.
@@ -80,33 +80,23 @@ public class ServerRequestHandler {
/*
* A connection ID of -1 implies there is no conenction ID
*/
connectionID = -1;
}
/**
* Creates a <code>HeaderSet</code> object that may be used in put and get
* operations.
*
* @return the <code>HeaderSet</code> object to use in put and get operations
*/
public final HeaderSet createHeaderSet() {
return new HeaderSet();
mConnectionId = -1;
}
/**
* Sets the connection ID header to include in the reply packets.
*
* @param id the connection ID to use; -1 if no connection ID should be
* @param connectionId the connection ID to use; -1 if no connection ID should be
* sent
*
* @throws IllegalArgumentException if <code>id</code> is not in the
* range -1 to 2<sup>32</sup>-1
*/
public void setConnectionID(long id) {
if ((id < -1) || (id > 0xFFFFFFFFL)) {
public void setConnectionId(final long connectionId) {
if ((connectionId < -1) || (connectionId > 0xFFFFFFFFL)) {
throw new IllegalArgumentException("Illegal Connection ID");
}
connectionID = id;
mConnectionId = connectionId;
}
/**
@@ -116,8 +106,8 @@ public class ServerRequestHandler {
* @return the connection id being used or -1 if no connection ID is being
* used
*/
public long getConnectionID() {
return connectionID;
public long getConnectionId() {
return mConnectionId;
}
/**
@@ -231,7 +221,7 @@ public class ServerRequestHandler {
* If an ABORT request is received during the processing of a PUT request,
* <code>op</code> will be closed by the implementation.
*
* @param op contains the headers sent by the client and allows new
* @param operation contains the headers sent by the client and allows new
* headers to be sent in the reply; <code>op</code> will never be
* <code>null</code>
*
@@ -239,7 +229,7 @@ public class ServerRequestHandler {
* returned to the client; if an invalid response code is provided, the
* <code>OBEX_HTTP_INTERNAL_ERROR</code> response code will be used
*/
public int onPut(Operation op) {
public int onPut(Operation operation) {
return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
}
@@ -253,7 +243,7 @@ public class ServerRequestHandler {
* If an ABORT request is received during the processing of a GET request,
* <code>op</code> will be closed by the implementation.
*
* @param op contains the headers sent by the client and allows new
* @param operation contains the headers sent by the client and allows new
* headers to be sent in the reply; <code>op</code> will never be
* <code>null</code>
*
@@ -261,7 +251,7 @@ public class ServerRequestHandler {
* returned to the client; if an invalid response code is provided, the
* <code>OBEX_HTTP_INTERNAL_ERROR</code> response code will be used
*/
public int onGet(Operation op) {
public int onGet(Operation operation) {
return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
}
@@ -279,10 +269,23 @@ public class ServerRequestHandler {
public void onAuthenticationFailure(byte[] userName) {
}
/**Called by ServerSession to update the status of current transaction */
/**
* Called by ServerSession to update the status of current transaction
* <P>
* If this method is not implemented by the class that extends this class,
* this method will do nothing.
*
*/
public void updateStatus(String message) {
}
/**
* Called when session is closed.
* <P>
* If this method is not implemented by the class that extends this class,
* this method will do nothing.
*
*/
public void onClose() {
}
}

View File

@@ -32,39 +32,39 @@
package javax.obex;
import android.util.Log;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* This class in an implementation of the ServerSession interface.
* This class in an implementation of the OBEX ServerSession.
*
* @hide
*/
public class ServerSession implements Runnable, ObexSession {
public final class ServerSession extends ObexSession implements Runnable {
private ObexTransport client;
private static final String TAG = "Obex ServerSession";
private InputStream input;
private ObexTransport mTransport;
private OutputStream output;
private InputStream mInput;
private ServerRequestHandler listener;
private OutputStream mOutput;
private Thread processThread;
private ServerRequestHandler mListener;
private int maxPacketLength;
private Thread mProcessThread;
private Authenticator authenticator;
private int mMaxPacketLength;
byte[] challengeDigest;
private boolean isClosed;
private boolean mClosed;
/**
* Creates new ServerSession.
*
* @param conn
* @param trans
* the connection to the client
*
* @param handler
@@ -77,50 +77,20 @@ public class ServerSession implements Runnable, ObexSession {
* if an error occurred while opening the input and output
* streams
*/
public ServerSession(ObexTransport conn, ServerRequestHandler handler, Authenticator auth)
public ServerSession(ObexTransport trans, ServerRequestHandler handler, Authenticator auth)
throws IOException {
authenticator = auth;
client = conn;
input = client.openInputStream();
output = client.openOutputStream();
listener = handler;
maxPacketLength = 256;
mAuthenticator = auth;
mTransport = trans;
mInput = mTransport.openInputStream();
mOutput = mTransport.openOutputStream();
mListener = handler;
mMaxPacketLength = 256;
isClosed = false;
processThread = new Thread(this);
processThread.start();
mClosed = false;
mProcessThread = new Thread(this);
mProcessThread.start();
}
/* removed as they're provided to the API user. Not used internally. */
/*
public boolean isCreatedServer() {
if (client instanceof BTConnection)
return ((BTConnection)client).isServerCreated();
else
return false;
}
public boolean isClosed() {
if (client instanceof BTConnection)
return ((BTConnection)client).isClosed();
else
return false;
}
public int getConnectionHandle() {
if (client instanceof BTConnection)
return ((BTConnection)client).getConnectionHandle();
else
return -1;
}
public RemoteDevice getRemoteDevice() {
if (client instanceof BTConnection)
return ((BTConnection)client).getRemoteDevice();
else
return null;
}*/
/**
* Processes requests made to the server and forwards them to the
* appropriate event listener.
@@ -129,29 +99,29 @@ public class ServerSession implements Runnable, ObexSession {
try {
boolean done = false;
while (!done && !isClosed) {
int requestType = input.read();
while (!done && !mClosed) {
int requestType = mInput.read();
switch (requestType) {
case 0x80:
case ObexHelper.OBEX_OPCODE_CONNECT:
handleConnectRequest();
break;
case 0x81:
case ObexHelper.OBEX_OPCODE_DISCONNECT:
handleDisconnectRequest();
done = true;
break;
case 0x03:
case 0x83:
case ObexHelper.OBEX_OPCODE_GET:
case ObexHelper.OBEX_OPCODE_GET_FINAL:
handleGetRequest(requestType);
break;
case 0x02:
case 0x82:
case ObexHelper.OBEX_OPCODE_PUT:
case ObexHelper.OBEX_OPCODE_PUT_FINAL:
handlePutRequest(requestType);
break;
case 0x85:
case ObexHelper.OBEX_OPCODE_SETPATH:
handleSetPathRequest();
break;
@@ -166,19 +136,19 @@ public class ServerSession implements Runnable, ObexSession {
* just going to read the packet and send a not implemented
* to the client
*/
int length = input.read();
length = (length << 8) + input.read();
int length = mInput.read();
length = (length << 8) + mInput.read();
for (int i = 3; i < length; i++) {
input.read();
mInput.read();
}
sendResponse(ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED, null);
// done = true;
}
}
} catch (NullPointerException e) {
Log.d(TAG, e.toString());
} catch (Exception e) {
Log.d(TAG, e.toString());
}
close();
}
@@ -201,24 +171,24 @@ public class ServerSession implements Runnable, ObexSession {
* if an error occurred at the transport layer
*/
private void handlePutRequest(int type) throws IOException {
ServerOperation client = new ServerOperation(this, input, type, maxPacketLength, listener);
ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
try {
int response = -1;
if ((client.finalBitSet) && !client.isValidBody()) {
response = validateResponseCode(listener.onDelete(client.requestHeaders,
client.replyHeaders));
if ((op.finalBitSet) && !op.isValidBody()) {
response = validateResponseCode(mListener
.onDelete(op.requestHeader, op.replyHeader));
} else {
response = validateResponseCode(listener.onPut(client));
response = validateResponseCode(mListener.onPut(op));
}
if (response != ResponseCodes.OBEX_HTTP_OK) {
client.sendReply(response);
} else if (!client.isAborted) {
op.sendReply(response);
} else if (!op.isAborted) {
// wait for the final bit
while (!client.finalBitSet) {
client.sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
while (!op.finalBitSet) {
op.sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
}
client.sendReply(response);
op.sendReply(response);
}
} catch (Exception e) {
sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
@@ -243,12 +213,12 @@ public class ServerSession implements Runnable, ObexSession {
* if an error occurred at the transport layer
*/
private void handleGetRequest(int type) throws IOException {
ServerOperation client = new ServerOperation(this, input, type, maxPacketLength, listener);
ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
try {
int response = validateResponseCode(listener.onGet(client));
int response = validateResponseCode(mListener.onGet(op));
if (!client.isAborted) {
client.sendReply(response);
if (!op.isAborted) {
op.sendReply(response);
}
} catch (Exception e) {
sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
@@ -267,7 +237,7 @@ public class ServerSession implements Runnable, ObexSession {
* @throws IOException
* if an IO error occurs
*/
protected void sendResponse(int code, byte[] header) throws IOException {
public void sendResponse(int code, byte[] header) throws IOException {
int totalLength = 3;
byte[] data = null;
@@ -284,8 +254,8 @@ public class ServerSession implements Runnable, ObexSession {
data[1] = (byte)0x00;
data[2] = (byte)totalLength;
}
output.write(data);
output.flush();
mOutput.write(data);
mOutput.flush();
}
/**
@@ -302,6 +272,7 @@ public class ServerSession implements Runnable, ObexSession {
private void handleSetPathRequest() throws IOException {
int length;
int flags;
@SuppressWarnings("unused")
int constants;
int totalLength = 3;
byte[] head = null;
@@ -310,10 +281,10 @@ public class ServerSession implements Runnable, ObexSession {
HeaderSet request = new HeaderSet();
HeaderSet reply = new HeaderSet();
length = input.read();
length = (length << 8) + input.read();
flags = input.read();
constants = input.read();
length = mInput.read();
length = (length << 8) + mInput.read();
flags = mInput.read();
constants = mInput.read();
if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
@@ -321,41 +292,41 @@ public class ServerSession implements Runnable, ObexSession {
} else {
if (length > 5) {
byte[] headers = new byte[length - 5];
bytesReceived = input.read(headers);
bytesReceived = mInput.read(headers);
while (bytesReceived != headers.length) {
bytesReceived += input.read(headers, bytesReceived, headers.length
bytesReceived += mInput.read(headers, bytesReceived, headers.length
- bytesReceived);
}
ObexHelper.updateHeaderSet(request, headers);
if (request.connectionID != null) {
listener.setConnectionID(ObexHelper.convertToLong(request.connectionID));
if (request.mConnectionID != null) {
mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
} else {
listener.setConnectionID(-1);
mListener.setConnectionId(-1);
}
// the Auth chan is initiated by the server.
// client sent back the authResp .
if (request.authResp != null) {
if (!handleAuthResp(request.authResp)) {
// the Auth chan is initiated by the server, client sent back the authResp .
if (request.mAuthResp != null) {
if (!handleAuthResp(request.mAuthResp)) {
code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
request.authResp));
mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
request.mAuthResp));
}
request.authResp = null;
request.mAuthResp = null;
}
}
if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
// the Auth chan is initiated by the client
// the Auth challenge is initiated by the client
// the server will send back the authResp to the client
if (request.authChall != null) {
if (request.mAuthChall != null) {
handleAuthChall(request);
reply.authResp = new byte[request.authResp.length];
System.arraycopy(request.authResp, 0, reply.authResp, 0, reply.authResp.length);
request.authChall = null;
request.authResp = null;
reply.mAuthResp = new byte[request.mAuthResp.length];
System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
reply.mAuthResp.length);
request.mAuthChall = null;
request.mAuthResp = null;
}
boolean backup = false;
boolean create = true;
@@ -367,7 +338,7 @@ public class ServerSession implements Runnable, ObexSession {
}
try {
code = listener.onSetPath(request, reply, backup, create);
code = mListener.onSetPath(request, reply, backup, create);
} catch (Exception e) {
sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
return;
@@ -376,23 +347,23 @@ public class ServerSession implements Runnable, ObexSession {
code = validateResponseCode(code);
if (reply.nonce != null) {
challengeDigest = new byte[16];
System.arraycopy(reply.nonce, 0, challengeDigest, 0, 16);
mChallengeDigest = new byte[16];
System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
} else {
challengeDigest = null;
mChallengeDigest = null;
}
long id = listener.getConnectionID();
long id = mListener.getConnectionId();
if (id == -1) {
reply.connectionID = null;
reply.mConnectionID = null;
} else {
reply.connectionID = ObexHelper.convertToByteArray(id);
reply.mConnectionID = ObexHelper.convertToByteArray(id);
}
head = ObexHelper.createHeader(reply, false);
totalLength += head.length;
if (totalLength > maxPacketLength) {
if (totalLength > mMaxPacketLength) {
totalLength = 3;
head = null;
code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -412,8 +383,8 @@ public class ServerSession implements Runnable, ObexSession {
* Write the OBEX SETPATH packet to the server. Byte 0: response code
* Byte 1&2: Connect Packet Length Byte 3 to n: headers
*/
output.write(replyData);
output.flush();
mOutput.write(replyData);
mOutput.flush();
}
/**
@@ -435,8 +406,8 @@ public class ServerSession implements Runnable, ObexSession {
HeaderSet request = new HeaderSet();
HeaderSet reply = new HeaderSet();
length = input.read();
length = (length << 8) + input.read();
length = mInput.read();
length = (length << 8) + mInput.read();
if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
@@ -444,66 +415,56 @@ public class ServerSession implements Runnable, ObexSession {
} else {
if (length > 3) {
byte[] headers = new byte[length - 3];
bytesReceived = input.read(headers);
bytesReceived = mInput.read(headers);
while (bytesReceived != headers.length) {
bytesReceived += input.read(headers, bytesReceived, headers.length
bytesReceived += mInput.read(headers, bytesReceived, headers.length
- bytesReceived);
}
ObexHelper.updateHeaderSet(request, headers);
}
if (request.connectionID != null) {
listener.setConnectionID(ObexHelper.convertToLong(request.connectionID));
if (request.mConnectionID != null) {
mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
} else {
listener.setConnectionID(1);
mListener.setConnectionId(1);
}
if (request.authResp != null) {
if (!handleAuthResp(request.authResp)) {
if (request.mAuthResp != null) {
if (!handleAuthResp(request.mAuthResp)) {
code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
request.authResp));
mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
request.mAuthResp));
}
request.authResp = null;
request.mAuthResp = null;
}
if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
if (request.authChall != null) {
if (request.mAuthChall != null) {
handleAuthChall(request);
request.authChall = null;
request.mAuthChall = null;
}
try {
listener.onDisconnect(request, reply);
mListener.onDisconnect(request, reply);
} catch (Exception e) {
sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
return;
}
/*
* Since a client will never response to an authentication
* challenge on a DISCONNECT, there is no reason to keep track
* of the challenge.
*
* if (reply.nonce != null) { challengeDigest = new byte[16];
* System.arraycopy(reply.nonce, 0, challengeDigest, 0, 16); }
* else { challengeDigest = null; }
*/
long id = listener.getConnectionID();
long id = mListener.getConnectionId();
if (id == -1) {
reply.connectionID = null;
reply.mConnectionID = null;
} else {
reply.connectionID = ObexHelper.convertToByteArray(id);
reply.mConnectionID = ObexHelper.convertToByteArray(id);
}
head = ObexHelper.createHeader(reply, false);
totalLength += head.length;
if (totalLength > maxPacketLength) {
if (totalLength > mMaxPacketLength) {
totalLength = 3;
head = null;
code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -528,8 +489,8 @@ public class ServerSession implements Runnable, ObexSession {
* Write the OBEX DISCONNECT packet to the server. Byte 0: response code
* Byte 1&2: Connect Packet Length Byte 3 to n: headers
*/
output.write(replyData);
output.flush();
mOutput.write(replyData);
mOutput.flush();
}
/**
@@ -545,7 +506,9 @@ public class ServerSession implements Runnable, ObexSession {
*/
private void handleConnectRequest() throws IOException {
int packetLength;
@SuppressWarnings("unused")
int version;
@SuppressWarnings("unused")
int flags;
int totalLength = 7;
byte[] head = null;
@@ -558,16 +521,16 @@ public class ServerSession implements Runnable, ObexSession {
* Read in the length of the OBEX packet, OBEX version, flags, and max
* packet length
*/
packetLength = input.read();
packetLength = (packetLength << 8) + input.read();
version = input.read();
flags = input.read();
maxPacketLength = input.read();
maxPacketLength = (maxPacketLength << 8) + input.read();
packetLength = mInput.read();
packetLength = (packetLength << 8) + mInput.read();
version = mInput.read();
flags = mInput.read();
mMaxPacketLength = mInput.read();
mMaxPacketLength = (mMaxPacketLength << 8) + mInput.read();
// should we check it?
if (maxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
maxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
}
if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) {
@@ -576,61 +539,62 @@ public class ServerSession implements Runnable, ObexSession {
} else {
if (packetLength > 7) {
byte[] headers = new byte[packetLength - 7];
bytesReceived = input.read(headers);
bytesReceived = mInput.read(headers);
while (bytesReceived != headers.length) {
bytesReceived += input.read(headers, bytesReceived, headers.length
bytesReceived += mInput.read(headers, bytesReceived, headers.length
- bytesReceived);
}
ObexHelper.updateHeaderSet(request, headers);
}
if (request.connectionID != null) {
listener.setConnectionID(ObexHelper.convertToLong(request.connectionID));
if (request.mConnectionID != null) {
mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
} else {
listener.setConnectionID(1);
mListener.setConnectionId(1);
}
if (request.authResp != null) {
if (!handleAuthResp(request.authResp)) {
if (request.mAuthResp != null) {
if (!handleAuthResp(request.mAuthResp)) {
code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
request.authResp));
mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
request.mAuthResp));
}
request.authResp = null;
request.mAuthResp = null;
}
if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
if (request.authChall != null) {
if (request.mAuthChall != null) {
handleAuthChall(request);
reply.authResp = new byte[request.authResp.length];
System.arraycopy(request.authResp, 0, reply.authResp, 0, reply.authResp.length);
request.authChall = null;
request.authResp = null;
reply.mAuthResp = new byte[request.mAuthResp.length];
System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
reply.mAuthResp.length);
request.mAuthChall = null;
request.mAuthResp = null;
}
try {
code = listener.onConnect(request, reply);
code = mListener.onConnect(request, reply);
code = validateResponseCode(code);
if (reply.nonce != null) {
challengeDigest = new byte[16];
System.arraycopy(reply.nonce, 0, challengeDigest, 0, 16);
mChallengeDigest = new byte[16];
System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
} else {
challengeDigest = null;
mChallengeDigest = null;
}
long id = listener.getConnectionID();
long id = mListener.getConnectionId();
if (id == -1) {
reply.connectionID = null;
reply.mConnectionID = null;
} else {
reply.connectionID = ObexHelper.convertToByteArray(id);
reply.mConnectionID = ObexHelper.convertToByteArray(id);
}
head = ObexHelper.createHeader(reply, false);
totalLength += head.length;
if (totalLength > maxPacketLength) {
if (totalLength > mMaxPacketLength) {
totalLength = 7;
head = null;
code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -667,8 +631,8 @@ public class ServerSession implements Runnable, ObexSession {
System.arraycopy(head, 0, sendData, 7, head.length);
}
output.write(sendData);
output.flush();
mOutput.write(sendData);
mOutput.flush();
}
/**
@@ -677,20 +641,20 @@ public class ServerSession implements Runnable, ObexSession {
* attempt to read/write will throw an exception.
*/
public synchronized void close() {
if (listener != null) {
listener.onClose();
if (mListener != null) {
mListener.onClose();
}
try {
input.close();
output.close();
client.close();
isClosed = true;
mInput.close();
mOutput.close();
mTransport.close();
mClosed = true;
} catch (Exception e) {
}
client = null;
input = null;
output = null;
listener = null;
mTransport = null;
mInput = null;
mOutput = null;
mListener = null;
}
/**
@@ -727,196 +691,4 @@ public class ServerSession implements Runnable, ObexSession {
return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
}
/**
* Called when the server received an authentication challenge header. This
* will cause the authenticator to handle the authentication challenge.
*
* @param header
* the header with the authentication challenge
*
* @return <code>true</code> if the last request should be resent;
* <code>false</code> if the last request should not be resent
*/
protected boolean handleAuthChall(HeaderSet header) {
if (authenticator == null) {
return false;
}
/*
* An authentication challenge is made up of one required and two
* optional tag length value triplets. The tag 0x00 is required to be in
* the authentication challenge and it represents the challenge digest
* that was received. The tag 0x01 is the options tag. This tag tracks
* if user ID is required and if full access will be granted. The tag
* 0x02 is the realm, which provides a description of which user name
* and password to use.
*/
byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.authChall);
byte[] option = ObexHelper.getTagValue((byte)0x01, header.authChall);
byte[] description = ObexHelper.getTagValue((byte)0x02, header.authChall);
String realm = "";
if (description != null) {
byte[] realmString = new byte[description.length - 1];
System.arraycopy(description, 1, realmString, 0, realmString.length);
switch (description[0] & 0xFF) {
case 0x00:
// ASCII encoding
// Fall through
case 0x01:
// ISO-8859-1 encoding
try {
realm = new String(realmString, "ISO8859_1");
} catch (Exception e) {
throw new RuntimeException("Unsupported Encoding Scheme");
}
break;
case 0xFF:
// UNICODE Encoding
realm = ObexHelper.convertToUnicode(realmString, false);
break;
case 0x02:
// ISO-8859-2 encoding
// Fall through
case 0x03:
// ISO-8859-3 encoding
// Fall through
case 0x04:
// ISO-8859-4 encoding
// Fall through
case 0x05:
// ISO-8859-5 encoding
// Fall through
case 0x06:
// ISO-8859-6 encoding
// Fall through
case 0x07:
// ISO-8859-7 encoding
// Fall through
case 0x08:
// ISO-8859-8 encoding
// Fall through
case 0x09:
// ISO-8859-9 encoding
// Fall through
default:
throw new RuntimeException("Unsupported Encoding Scheme");
}
}
boolean isUserIDRequired = false;
boolean isFullAccess = true;
if (option != null) {
if ((option[0] & 0x01) != 0) {
isUserIDRequired = true;
}
if ((option[0] & 0x02) != 0) {
isFullAccess = false;
}
}
PasswordAuthentication result = null;
header.authChall = null;
try {
result = authenticator.onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
} catch (Exception e) {
return false;
}
/*
* If no password is provided then we not resent the request
*/
if (result == null) {
return false;
}
byte[] password = result.getPassword();
if (password == null) {
return false;
}
byte[] userName = result.getUserName();
/*
* Create the authentication response header. It includes 1 required and
* 2 option tag length value triples. The required triple has a tag of
* 0x00 and is the response digest. The first optional tag is 0x01 and
* represents the user ID. If no user ID is provided, then no user ID
* will be sent. The second optional tag is 0x02 and is the challenge
* that was received. This will always be sent
*/
if (userName != null) {
header.authResp = new byte[38 + userName.length];
header.authResp[36] = (byte)0x01;
header.authResp[37] = (byte)userName.length;
System.arraycopy(userName, 0, header.authResp, 38, userName.length);
} else {
header.authResp = new byte[36];
}
// Create the secret String
byte[] digest = new byte[challenge.length + password.length + 1];
System.arraycopy(challenge, 0, digest, 0, challenge.length);
// Insert colon between challenge and password
digest[challenge.length] = (byte)0x3A;
System.arraycopy(password, 0, digest, challenge.length + 1, password.length);
// Add the Response Digest
header.authResp[0] = (byte)0x00;
header.authResp[1] = (byte)0x10;
System.arraycopy(ObexHelper.computeMd5Hash(digest), 0, header.authResp, 2, 16);
// Add the challenge
header.authResp[18] = (byte)0x02;
header.authResp[19] = (byte)0x10;
System.arraycopy(challenge, 0, header.authResp, 20, 16);
return true;
}
/**
* Called when the server received an authentication response header. This
* will cause the authenticator to handle the authentication response.
*
* @param authResp
* the authentication response
*
* @return <code>true</code> if the response passed; <code>false</code> if
* the response failed
*/
protected boolean handleAuthResp(byte[] authResp) {
if (authenticator == null) {
return false;
}
// get the correct password from the application
byte[] correctPassword = authenticator.onAuthenticationResponse(ObexHelper.getTagValue(
(byte)0x01, authResp));
if (correctPassword == null) {
return false;
}
byte[] temp = new byte[correctPassword.length + 16];
System.arraycopy(challengeDigest, 0, temp, 0, 16);
System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length);
byte[] correctResponse = ObexHelper.computeMd5Hash(temp);
byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp);
// compare the MD5 hash array .
for (int i = 0; i < 16; i++) {
if (correctResponse[i] != actualResponse[i]) {
return false;
}
}
return true;
}
}

View File

@@ -61,7 +61,7 @@ public interface SessionNotifier {
* does not have a <code>ServiceRecord</code> in the SDDB, the
* <code>ServiceRecord</code> for this object will be added to the SDDB.
* This method requests the BCC to put the
* local device in connectable mode so that it will respond to
* local device in connectible mode so that it will respond to
* connection attempts by clients.
* <P>
* The following checks are done to verify that the service record
@@ -101,10 +101,10 @@ public interface SessionNotifier {
* be due to insufficient disk space, database locks, etc.
*
* @throws BluetoothStateException if the server device could
* not be placed in connectable mode because the device user has
* configured the device to be non-connectable
* not be placed in connectible mode because the device user has
* configured the device to be non-connectible
*/
public ObexSession acceptAndOpen(ServerRequestHandler handler) throws IOException;
ObexSession acceptAndOpen(ServerRequestHandler handler) throws IOException;
/**
* Waits for a transport layer connection to be established and specifies
@@ -117,7 +117,7 @@ public interface SessionNotifier {
* does not have a <code>ServiceRecord</code> in the SDDB, the
* <code>ServiceRecord</code> for this object will be added to the SDDB.
* This method requests the BCC to put the
* local device in connectable mode so that it will respond to
* local device in connectible mode so that it will respond to
* connection attempts by clients.
* <P>
* The following checks are done to verify that the service record
@@ -160,9 +160,8 @@ public interface SessionNotifier {
* be due to insufficient disk space, database locks, etc.
*
* @throws BluetoothStateException if the server device could
* not be placed in connectable mode because the device user has
* configured the device to be non-connectable
* not be placed in connectible mode because the device user has
* configured the device to be non-connectible
*/
public ObexSession acceptAndOpen(ServerRequestHandler handler, Authenticator auth)
throws IOException;
ObexSession acceptAndOpen(ServerRequestHandler handler, Authenticator auth) throws IOException;
}