public int getHeaderLength() { long id = mListener.getConnectionId(); if (id == -1) { replyHeader.mConnectionID = null; } else { replyHeader.mConnectionID = ObexHelper.convertToByteArray(id); } byte[] headerArray = ObexHelper.createHeader(replyHeader, false); return headerArray.length; }
/** * Specifies the headers that should be sent in the next OBEX message that is sent. * * @param headers the headers to send in the next message * @throws IOException if this <code>Operation</code> has been closed or the transaction has ended * and no further messages will be exchanged * @throws IllegalArgumentException if <code>headers</code> was not created by a call to <code> * ServerRequestHandler.createHeaderSet()</code> */ public void sendHeaders(HeaderSet headers) throws IOException { ensureOpen(); if (headers == null) { throw new IOException("Headers may not be null"); } int[] headerList = headers.getHeaderList(); if (headerList != null) { for (int i = 0; i < headerList.length; i++) { replyHeader.setHeader(headerList[i], headers.getHeader(headerList[i])); } } }
/** * Returns the type of content that the resource connected to is providing. E.g. if the connection * is via HTTP, then the value of the content-type header field is returned. * * @return the content type of the resource that the URL references, or <code>null</code> if not * known */ public String getType() { try { return (String) requestHeader.getHeader(HeaderSet.TYPE); } catch (IOException e) { return null; } }
/** * Returns the length of the content which is being provided. E.g. if the connection is via HTTP, * then the value of the content-length header field is returned. * * @return the content length of the resource that this connection's URL references, or -1 if the * content length is not known */ public long getLength() { try { Long temp = (Long) requestHeader.getHeader(HeaderSet.LENGTH); if (temp == null) { return -1; } else { return temp.longValue(); } } catch (IOException e) { return -1; } }
/** * Sends a reply to the client. If the reply is a OBEX_HTTP_CONTINUE, it will wait for a response * from the client before ending. * * @param type the response code to send back to the client * @return <code>true</code> if the final bit was not set on the reply; <code>false</code> if no * reply was received because the operation ended, an abort was received, or the final bit was * set in the reply * @throws IOException if an IO error occurs */ public synchronized boolean sendReply(int type) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); int bytesReceived; long id = mListener.getConnectionId(); if (id == -1) { replyHeader.mConnectionID = null; } else { replyHeader.mConnectionID = ObexHelper.convertToByteArray(id); } byte[] headerArray = ObexHelper.createHeader(replyHeader, true); int bodyLength = -1; int orginalBodyLength = -1; if (mPrivateOutput != null) { bodyLength = mPrivateOutput.size(); orginalBodyLength = bodyLength; } if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) { int end = 0; int start = 0; while (end != headerArray.length) { end = ObexHelper.findHeaderEnd( headerArray, start, mMaxPacketLength - ObexHelper.BASE_PACKET_LENGTH); if (end == -1) { mClosed = true; if (mPrivateInput != null) { mPrivateInput.close(); } if (mPrivateOutput != null) { mPrivateOutput.close(); } 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); mParent.sendResponse(type, sendHeader); start = end; } if (bodyLength > 0) { return true; } else { return false; } } else { out.write(headerArray); } // For Get operation: if response code is OBEX_HTTP_OK, then this is the // last packet; so set finalBitSet to true. if (mGetOperation && type == ResponseCodes.OBEX_HTTP_OK) { finalBitSet = true; } 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 > (mMaxPacketLength - headerArray.length - 6)) { bodyLength = mMaxPacketLength - headerArray.length - 6; } 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) || (mPrivateOutput.isClosed())) { out.write(0x49); } else { out.write(0x48); } bodyLength += 3; out.write((byte) (bodyLength >> 8)); out.write((byte) bodyLength); out.write(body); } } if ((finalBitSet) && (type == ResponseCodes.OBEX_HTTP_OK) && (orginalBodyLength <= 0)) { out.write(0x49); orginalBodyLength = 3; out.write((byte) (orginalBodyLength >> 8)); out.write((byte) orginalBodyLength); } mResponseSize = 3; mParent.sendResponse(type, out.toByteArray()); 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 - 3]; // First three bytes already read, compensating for this bytesReceived = mInput.read(temp); while (bytesReceived != temp.length) { bytesReceived += mInput.read(temp, bytesReceived, temp.length - bytesReceived); } } /* * Determine if an ABORT was sent as the reply */ if (headerID == ObexHelper.OBEX_OPCODE_ABORT) { mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null); mClosed = true; isAborted = true; mExceptionString = "Abort Received"; throw new IOException("Abort Received"); } else { mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null); mClosed = true; mExceptionString = "Bad Request Received"; throw new IOException("Bad Request Received"); } } else { if ((headerID == ObexHelper.OBEX_OPCODE_PUT_FINAL)) { finalBitSet = true; } else if (headerID == ObexHelper.OBEX_OPCODE_GET_FINAL) { mRequestFinished = true; } /* * Determine if the packet length is larger then this device can receive */ if (length > ObexHelper.MAX_PACKET_SIZE_INT) { mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null); throw new IOException("Packet received was too large"); } /* * Determine if any headers were sent in the initial request */ if (length > 3) { byte[] data = new byte[length - 3]; bytesReceived = mInput.read(data); while (bytesReceived != data.length) { bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived); } byte[] body = ObexHelper.updateHeaderSet(requestHeader, data); if (body != null) { mHasBody = true; } if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) { mListener.setConnectionId(ObexHelper.convertToLong(requestHeader.mConnectionID)); } else { mListener.setConnectionId(1); } 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; } requestHeader.mAuthResp = null; } if (requestHeader.mAuthChall != null) { mParent.handleAuthChall(requestHeader); // send the auhtResp to the client 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) { mPrivateInput.writeBytes(body, 1); } } } return true; } else { return false; } }
/** * Creates new ServerOperation * * @param p the parent that created this object * @param in the input stream to read from * @param out the output stream to write to * @param request the initial request that was received from the client * @param maxSize the max packet size that the client will accept * @param listen the listener that is responding to the request * @throws IOException if an IO error occurs */ public ServerOperation( ServerSession p, InputStream in, int request, int maxSize, ServerRequestHandler listen) throws IOException { isAborted = 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; /* * Determine if this is a PUT request */ if ((request == 0x02) || (request == 0x82)) { /* * It is a PUT request. */ mGetOperation = false; /* * Determine if the final bit is set */ if ((request & 0x80) == 0) { finalBitSet = false; } else { finalBitSet = true; mRequestFinished = true; } } else if ((request == 0x03) || (request == 0x83)) { /* * It is a GET request. */ mGetOperation = true; // For Get request, final bit set is decided by server side logic finalBitSet = false; if (request == 0x83) { mRequestFinished = true; } } else { throw new IOException("ServerOperation can not handle such request"); } int length = in.read(); length = (length << 8) + in.read(); /* * Determine if the packet length is larger than this device can receive */ if (length > ObexHelper.MAX_PACKET_SIZE_INT) { mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null); throw new IOException("Packet received was too large"); } /* * Determine if any headers were sent in the initial request */ if (length > 3) { byte[] data = new byte[length - 3]; bytesReceived = in.read(data); while (bytesReceived != data.length) { bytesReceived += in.read(data, bytesReceived, data.length - bytesReceived); } byte[] body = ObexHelper.updateHeaderSet(requestHeader, data); if (body != null) { mHasBody = true; } if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) { mListener.setConnectionId(ObexHelper.convertToLong(requestHeader.mConnectionID)); } else { mListener.setConnectionId(1); } 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 (requestHeader.mAuthChall != null) { mParent.handleAuthChall(requestHeader); // send the authResp to the client 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) { mPrivateInput.writeBytes(body, 1); } else { while ((!mGetOperation) && (!finalBitSet)) { sendReply(ResponseCodes.OBEX_HTTP_CONTINUE); if (mPrivateInput.available() > 0) { break; } } } } while ((!mGetOperation) && (!finalBitSet) && (mPrivateInput.available() == 0)) { sendReply(ResponseCodes.OBEX_HTTP_CONTINUE); if (mPrivateInput.available() > 0) { break; } } // wait for get request finished !!!! while (mGetOperation && !mRequestFinished) { sendReply(ResponseCodes.OBEX_HTTP_CONTINUE); } }
/** * Handles a connect request from a client. This method will read the rest of the request from the * client. Assuming the request is valid, it will create a <code>HeaderSet</code> object to pass * to the <code>ServerRequestHandler</code> object. After the handler processes the request, this * method will create a reply message to send to the server with the response code provided. * * @throws IOException if an error occurred at the transport layer */ private void handleConnectRequest() throws IOException { int packetLength; @SuppressWarnings("unused") int version; @SuppressWarnings("unused") int flags; int totalLength = 7; byte[] head = null; int code = -1; HeaderSet request = new HeaderSet(); HeaderSet reply = new HeaderSet(); /* * Read in the length of the OBEX packet, OBEX version, flags, and max * packet length */ 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 (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) { mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT; } if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) { code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; totalLength = 7; } else { if (packetLength > 7) { mData.reset(); mData.write(mInput, packetLength - 7); ObexHelper.updateHeaderSet(request, mData, null, mHeaderBuffer); } if (mListener.getConnectionId() != -1 && request.mConnectionID != null) { mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID)); } else { mListener.setConnectionId(1); } if (request.mAuthResp != null) { if (!handleAuthResp(request.mAuthResp)) { code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED; mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte) 0x01, request.mAuthResp)); } request.mAuthResp = null; } if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) { if (request.mAuthChall != null) { handleAuthChall(request); 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 = mListener.onConnect(request, reply); code = validateResponseCode(code); if (reply.nonce != null) { mChallengeDigest = new byte[16]; System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16); } else { mChallengeDigest = null; } long id = mListener.getConnectionId(); if (id == -1) { reply.mConnectionID = null; } else { reply.mConnectionID = ObexHelper.convertToByteArray(id); } head = ObexHelper.createHeader(reply, false); totalLength += head.length; if (totalLength > mMaxPacketLength) { totalLength = 7; head = null; code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } } catch (Exception e) { e.printStackTrace(); totalLength = 7; head = null; code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } } } // Compute Length of OBEX CONNECT packet byte[] length = ObexHelper.convertToByteArray(totalLength); /* * Write the OBEX CONNECT packet to the server. Byte 0: response code * Byte 1&2: Connect Packet Length Byte 3: OBEX Version Number * (Presently, 0x10) Byte 4: Flags (For TCP 0x00) Byte 5&6: Max OBEX * Packet Length (Defined in MAX_PACKET_SIZE) Byte 7 to n: headers */ byte[] sendData = new byte[totalLength]; sendData[0] = (byte) code; sendData[1] = length[2]; sendData[2] = length[3]; sendData[3] = (byte) 0x10; sendData[4] = (byte) 0x00; sendData[5] = (byte) (ObexHelper.MAX_PACKET_SIZE_INT >> 8); sendData[6] = (byte) (ObexHelper.MAX_PACKET_SIZE_INT & 0xFF); if (head != null) { System.arraycopy(head, 0, sendData, 7, head.length); } mOutput.write(sendData); mOutput.flush(); }
/** * Handles a disconnect request from a client. This method will read the rest of the request from * the client. Assuming the request is valid, it will create a <code>HeaderSet</code> object to * pass to the <code>ServerRequestHandler</code> object. After the handler processes the request, * this method will create a reply message to send to the server. * * @throws IOException if an error occurred at the transport layer */ private void handleDisconnectRequest() throws IOException { int length; int code = ResponseCodes.OBEX_HTTP_OK; int totalLength = 3; byte[] head = null; HeaderSet request = new HeaderSet(); HeaderSet reply = new HeaderSet(); length = mInput.read(); length = (length << 8) + mInput.read(); if (length > ObexHelper.MAX_PACKET_SIZE_INT) { code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; totalLength = 3; } else { if (length > 3) { mData.reset(); mData.write(mInput, length - 3); ObexHelper.updateHeaderSet(request, mData, null, mHeaderBuffer); } if (mListener.getConnectionId() != -1 && request.mConnectionID != null) { mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID)); } else { mListener.setConnectionId(1); } if (request.mAuthResp != null) { if (!handleAuthResp(request.mAuthResp)) { code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED; mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte) 0x01, request.mAuthResp)); } request.mAuthResp = null; } if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) { if (request.mAuthChall != null) { handleAuthChall(request); request.mAuthChall = null; } try { mListener.onDisconnect(request, reply); } catch (Exception e) { sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null); return; } long id = mListener.getConnectionId(); if (id == -1) { reply.mConnectionID = null; } else { reply.mConnectionID = ObexHelper.convertToByteArray(id); } head = ObexHelper.createHeader(reply, false); totalLength += head.length; if (totalLength > mMaxPacketLength) { totalLength = 3; head = null; code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } } } // Compute Length of OBEX CONNECT packet mData.reset(); mData.write((byte) code); mData.write((byte) (totalLength >> 8)); mData.write((byte) totalLength); if (head != null) { mData.write(head); } /* * Write the OBEX DISCONNECT packet to the server. Byte 0: response code * Byte 1&2: Connect Packet Length Byte 3 to n: headers */ mData.read(mOutput); mOutput.flush(); }
/** * Handles a SETPATH request from a client. This method will read the rest of the request from the * client. Assuming the request is valid, it will create a <code>HeaderSet</code> object to pass * to the <code>ServerRequestHandler</code> object. After the handler processes the request, this * method will create a reply message to send to the server with the response code provided. * * @throws IOException if an error occurred at the transport layer */ private void handleSetPathRequest() throws IOException { int length; int flags; @SuppressWarnings("unused") int constants; int totalLength = 3; byte[] head = null; int code = -1; HeaderSet request = new HeaderSet(); HeaderSet reply = new HeaderSet(); 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; totalLength = 3; } else { if (length > 5) { mData.reset(); mData.write(mInput, length - 5); ObexHelper.updateHeaderSet(request, mData, null, mHeaderBuffer); if (mListener.getConnectionId() != -1 && request.mConnectionID != null) { mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID)); } else { mListener.setConnectionId(1); } // 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; mListener.onAuthenticationFailure( ObexHelper.getTagValue((byte) 0x01, request.mAuthResp)); } request.mAuthResp = null; } } if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) { // the Auth challenge is initiated by the client // the server will send back the authResp to the client if (request.mAuthChall != null) { handleAuthChall(request); 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; if (!((flags & 1) == 0)) { backup = true; } if (!((flags & 2) == 0)) { create = false; } try { code = mListener.onSetPath(request, reply, backup, create); } catch (Exception e) { sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null); return; } code = validateResponseCode(code); if (reply.nonce != null) { mChallengeDigest = new byte[16]; System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16); } else { mChallengeDigest = null; } long id = mListener.getConnectionId(); if (id == -1) { reply.mConnectionID = null; } else { reply.mConnectionID = ObexHelper.convertToByteArray(id); } head = ObexHelper.createHeader(reply, false); totalLength += head.length; if (totalLength > mMaxPacketLength) { totalLength = 3; head = null; code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } } } // Compute Length of OBEX SETPATH packet mData.reset(); mData.write((byte) code); mData.write((byte) (totalLength >> 8)); mData.write((byte) totalLength); if (head != null) { mData.write(head); } /* * Write the OBEX SETPATH packet to the server. Byte 0: response code * Byte 1&2: Connect Packet Length Byte 3 to n: headers */ mData.read(mOutput); mOutput.flush(); }