Home | History | Annotate | Download | only in obex
      1 /* Copyright (c) 2015 The Android Open Source Project
      2  * Copyright (C) 2015 Samsung LSI
      3  * Copyright (c) 2008-2009, Motorola, Inc.
      4  *
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions are met:
      9  *
     10  * - Redistributions of source code must retain the above copyright notice,
     11  * this list of conditions and the following disclaimer.
     12  *
     13  * - Redistributions in binary form must reproduce the above copyright notice,
     14  * this list of conditions and the following disclaimer in the documentation
     15  * and/or other materials provided with the distribution.
     16  *
     17  * - Neither the name of the Motorola, Inc. nor the names of its contributors
     18  * may be used to endorse or promote products derived from this software
     19  * without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
     25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 package javax.obex;
     35 
     36 import java.io.IOException;
     37 import java.io.InputStream;
     38 import java.io.DataInputStream;
     39 import java.io.OutputStream;
     40 import java.io.DataOutputStream;
     41 import java.io.ByteArrayOutputStream;
     42 
     43 import android.util.Log;
     44 
     45 /**
     46  * This class implements the Operation interface for server side connections.
     47  * <P>
     48  * <STRONG>Request Codes</STRONG> There are four different request codes that
     49  * are in this class. 0x02 is a PUT request that signals that the request is not
     50  * complete and requires an additional OBEX packet. 0x82 is a PUT request that
     51  * says that request is complete. In this case, the server can begin sending the
     52  * response. The 0x03 is a GET request that signals that the request is not
     53  * finished. When the server receives a 0x83, the client is signaling the server
     54  * that it is done with its request. TODO: Extend the ClientOperation and reuse
     55  * the methods defined TODO: in that class.
     56  * @hide
     57  */
     58 public final class ServerOperation implements Operation, BaseStream {
     59 
     60     private static final String TAG = "ServerOperation";
     61 
     62     private static final boolean V = ObexHelper.VDBG; // Verbose debugging
     63 
     64     public boolean isAborted;
     65 
     66     public HeaderSet requestHeader;
     67 
     68     public HeaderSet replyHeader;
     69 
     70     public boolean finalBitSet;
     71 
     72     private InputStream mInput;
     73 
     74     private ServerSession mParent;
     75 
     76     private int mMaxPacketLength;
     77 
     78     private int mResponseSize;
     79 
     80     private boolean mClosed;
     81 
     82     private boolean mGetOperation;
     83 
     84     private PrivateInputStream mPrivateInput;
     85 
     86     private PrivateOutputStream mPrivateOutput;
     87 
     88     private ObexTransport mTransport;
     89 
     90     private boolean mPrivateOutputOpen;
     91 
     92     private String mExceptionString;
     93 
     94     private ServerRequestHandler mListener;
     95 
     96     private boolean mRequestFinished;
     97 
     98     private boolean mHasBody;
     99 
    100     private boolean mSendBodyHeader = true;
    101     // Assume SRM disabled - needs to be explicit
    102     // enabled by client
    103     private boolean mSrmEnabled = false;
    104     // A latch - when triggered, there is not way back ;-)
    105     private boolean mSrmActive = false;
    106     // Set to true when a SRM enable response have been send
    107     private boolean mSrmResponseSent = false;
    108     // keep waiting until final-bit is received in request
    109     // to handle the case where the SRM enable header is in
    110     // a different OBEX packet than the SRMP header.
    111     private boolean mSrmWaitingForRemote = true;
    112     // Why should we wait? - currently not exposed to apps.
    113     private boolean mSrmLocalWait = false;
    114 
    115     /**
    116      * Creates new ServerOperation
    117      * @param p the parent that created this object
    118      * @param in the input stream to read from
    119      * @param out the output stream to write to
    120      * @param request the initial request that was received from the client
    121      * @param maxSize the max packet size that the client will accept
    122      * @param listen the listener that is responding to the request
    123      * @throws IOException if an IO error occurs
    124      */
    125     public ServerOperation(ServerSession p, InputStream in, int request, int maxSize,
    126             ServerRequestHandler listen) throws IOException {
    127 
    128         isAborted = false;
    129         mParent = p;
    130         mInput = in;
    131         mMaxPacketLength = maxSize;
    132         mClosed = false;
    133         requestHeader = new HeaderSet();
    134         replyHeader = new HeaderSet();
    135         mPrivateInput = new PrivateInputStream(this);
    136         mResponseSize = 3;
    137         mListener = listen;
    138         mRequestFinished = false;
    139         mPrivateOutputOpen = false;
    140         mHasBody = false;
    141         ObexPacket packet;
    142         mTransport = p.getTransport();
    143 
    144         /*
    145          * Determine if this is a PUT request
    146          */
    147         if ((request == ObexHelper.OBEX_OPCODE_PUT) ||
    148                 (request == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
    149             /*
    150              * It is a PUT request.
    151              */
    152             mGetOperation = false;
    153 
    154             /*
    155              * Determine if the final bit is set
    156              */
    157             if ((request & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) == 0) {
    158                 finalBitSet = false;
    159             } else {
    160                 finalBitSet = true;
    161                 mRequestFinished = true;
    162             }
    163         } else if ((request == ObexHelper.OBEX_OPCODE_GET) ||
    164                 (request == ObexHelper.OBEX_OPCODE_GET_FINAL)) {
    165             /*
    166              * It is a GET request.
    167              */
    168             mGetOperation = true;
    169 
    170             // For Get request, final bit set is decided by server side logic
    171             finalBitSet = false;
    172 
    173             if (request == ObexHelper.OBEX_OPCODE_GET_FINAL) {
    174                 mRequestFinished = true;
    175             }
    176         } else {
    177             throw new IOException("ServerOperation can not handle such request");
    178         }
    179 
    180         packet = ObexPacket.read(request, mInput);
    181 
    182         /*
    183          * Determine if the packet length is larger than this device can receive
    184          */
    185         if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
    186             mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
    187             throw new IOException("Packet received was too large. Length: "
    188                     + packet.mLength + " maxLength: " + ObexHelper.getMaxRxPacketSize(mTransport));
    189         }
    190 
    191         /*
    192          * Determine if any headers were sent in the initial request
    193          */
    194         if (packet.mLength > 3) {
    195             if(!handleObexPacket(packet)) {
    196                 return;
    197             }
    198             /* Don't Pre-Send continue when Remote requested for SRM
    199              * Let the Application confirm.
    200              */
    201             if (V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
    202                     + " not hasBody case: " + mHasBody);
    203             if (!mHasBody && !mSrmEnabled) {
    204                 while ((!mGetOperation) && (!finalBitSet)) {
    205                     sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
    206                     if (mPrivateInput.available() > 0) {
    207                         break;
    208                     }
    209                 }
    210             }
    211         }
    212         /* Don't Pre-Send continue when Remote requested for SRM
    213           * Let the Application confirm.
    214           */
    215         if (V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
    216             + " not finalPacket: " + finalBitSet + " not GETOp Case: " + mGetOperation);
    217         while ((!mSrmEnabled) && (!mGetOperation) && (!finalBitSet)
    218                 && (mPrivateInput.available() == 0)) {
    219             sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
    220             if (mPrivateInput.available() > 0) {
    221                 break;
    222             }
    223         }
    224 
    225         // wait for get request finished !!!!
    226         while (mGetOperation && !mRequestFinished) {
    227             sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
    228         }
    229     }
    230 
    231     /**
    232      * Parse headers and update member variables
    233      * @param packet the received obex packet
    234      * @return false for failing authentication - and a OBEX_HTTP_UNAUTHORIZED
    235      * response have been send. Else true.
    236      * @throws IOException
    237      */
    238     private boolean handleObexPacket(ObexPacket packet) throws IOException {
    239         byte[] body = updateRequestHeaders(packet);
    240 
    241         if (body != null) {
    242             mHasBody = true;
    243         }
    244         if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) {
    245             mListener.setConnectionId(ObexHelper
    246                     .convertToLong(requestHeader.mConnectionID));
    247         } else {
    248             mListener.setConnectionId(1);
    249         }
    250 
    251         if (requestHeader.mAuthResp != null) {
    252             if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
    253                 mExceptionString = "Authentication Failed";
    254                 mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
    255                 mClosed = true;
    256                 requestHeader.mAuthResp = null;
    257                 return false;
    258             }
    259             requestHeader.mAuthResp = null;
    260         }
    261 
    262         if (requestHeader.mAuthChall != null) {
    263             mParent.handleAuthChall(requestHeader);
    264             // send the auhtResp to the client
    265             replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
    266             System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
    267                     replyHeader.mAuthResp.length);
    268             requestHeader.mAuthResp = null;
    269             requestHeader.mAuthChall = null;
    270         }
    271 
    272         if (body != null) {
    273             mPrivateInput.writeBytes(body, 1);
    274         }
    275         return true;
    276     }
    277 
    278     /**
    279      * Update the request header set, and sniff on SRM headers to update local state.
    280      * @param data the OBEX packet data
    281      * @return any bytes in a body/end-of-body header returned by {@link ObexHelper.updateHeaderSet}
    282      * @throws IOException
    283      */
    284     private byte[] updateRequestHeaders(ObexPacket packet) throws IOException {
    285         byte[] body = null;
    286         if (packet.mPayload != null) {
    287             body = ObexHelper.updateHeaderSet(requestHeader, packet.mPayload);
    288         }
    289         Byte srmMode = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
    290         if(mTransport.isSrmSupported() && srmMode != null
    291                 && srmMode == ObexHelper.OBEX_SRM_ENABLE) {
    292             mSrmEnabled = true;
    293             if(V) Log.d(TAG,"SRM is now ENABLED (but not active) for this operation");
    294         }
    295         checkForSrmWait(packet.mHeaderId);
    296         if((!mSrmWaitingForRemote) && (mSrmEnabled)) {
    297             if(V) Log.d(TAG,"SRM is now ACTIVE for this operation");
    298             mSrmActive = true;
    299         }
    300         return body;
    301     }
    302 
    303     /**
    304      * Call this only when a complete request have been received.
    305      * (This is not optimal, but the current design is not really suited to
    306      * the way SRM is specified.)
    307      */
    308     private void checkForSrmWait(int headerId){
    309         if (mSrmEnabled && (headerId == ObexHelper.OBEX_OPCODE_GET
    310                 || headerId == ObexHelper.OBEX_OPCODE_GET_FINAL
    311                 || headerId == ObexHelper.OBEX_OPCODE_PUT)) {
    312             try {
    313                 mSrmWaitingForRemote = false;
    314                 Byte srmp = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
    315                 if(srmp != null && srmp == ObexHelper.OBEX_SRMP_WAIT) {
    316                     mSrmWaitingForRemote = true;
    317                     // Clear the wait header, as the absents of the header when the final bit is set
    318                     // indicates don't wait.
    319                     requestHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null);
    320                 }
    321             } catch (IOException e) {if(V){Log.w(TAG,"Exception while extracting header",e);}}
    322         }
    323     }
    324 
    325     public boolean isValidBody() {
    326         return mHasBody;
    327     }
    328 
    329     /**
    330      * Determines if the operation should continue or should wait. If it should
    331      * continue, this method will continue the operation.
    332      * @param sendEmpty if <code>true</code> then this will continue the
    333      *        operation even if no headers will be sent; if <code>false</code>
    334      *        then this method will only continue the operation if there are
    335      *        headers to send
    336      * @param inStream if<code>true</code> the stream is input stream, otherwise
    337      *        output stream
    338      * @return <code>true</code> if the operation was completed;
    339      *         <code>false</code> if no operation took place
    340      */
    341     public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
    342             throws IOException {
    343         if (!mGetOperation) {
    344             if (!finalBitSet) {
    345                 if (sendEmpty) {
    346                     sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
    347                     return true;
    348                 } else {
    349                     if ((mResponseSize > 3) || (mPrivateOutput.size() > 0)) {
    350                         sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
    351                         return true;
    352                     } else {
    353                         return false;
    354                     }
    355                 }
    356             } else {
    357                 return false;
    358             }
    359         } else {
    360             sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
    361             return true;
    362         }
    363     }
    364 
    365     /**
    366      * Sends a reply to the client. If the reply is a OBEX_HTTP_CONTINUE, it
    367      * will wait for a response from the client before ending unless SRM is active.
    368      * @param type the response code to send back to the client
    369      * @return <code>true</code> if the final bit was not set on the reply;
    370      *         <code>false</code> if no reply was received because the operation
    371      *         ended, an abort was received, the final bit was set in the
    372      *         reply or SRM is active.
    373      * @throws IOException if an IO error occurs
    374      */
    375     public synchronized boolean sendReply(int type) throws IOException {
    376         ByteArrayOutputStream out = new ByteArrayOutputStream();
    377         boolean skipSend = false;
    378         boolean skipReceive = false;
    379         boolean srmRespSendPending = false;
    380 
    381         long id = mListener.getConnectionId();
    382         if (id == -1) {
    383             replyHeader.mConnectionID = null;
    384         } else {
    385             replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
    386         }
    387 
    388         if(mSrmEnabled && !mSrmResponseSent) {
    389             // As we are not ensured that the SRM enable is in the first OBEX packet
    390             // We must check for each reply.
    391             if(V)Log.v(TAG, "mSrmEnabled==true, sending SRM enable response.");
    392             replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRM_ENABLE);
    393             srmRespSendPending = true;
    394         }
    395 
    396         if(mSrmEnabled && !mGetOperation && mSrmLocalWait) {
    397             replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRMP_WAIT);
    398         }
    399 
    400         byte[] headerArray = ObexHelper.createHeader(replyHeader, true); // This clears the headers
    401         int bodyLength = -1;
    402         int orginalBodyLength = -1;
    403 
    404         if (mPrivateOutput != null) {
    405             bodyLength = mPrivateOutput.size();
    406             orginalBodyLength = bodyLength;
    407         }
    408 
    409         if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) {
    410 
    411             int end = 0;
    412             int start = 0;
    413 
    414             while (end != headerArray.length) {
    415                 end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketLength
    416                         - ObexHelper.BASE_PACKET_LENGTH);
    417                 if (end == -1) {
    418 
    419                     mClosed = true;
    420 
    421                     if (mPrivateInput != null) {
    422                         mPrivateInput.close();
    423                     }
    424 
    425                     if (mPrivateOutput != null) {
    426                         mPrivateOutput.close();
    427                     }
    428                     mParent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
    429                     throw new IOException("OBEX Packet exceeds max packet size");
    430                 }
    431                 byte[] sendHeader = new byte[end - start];
    432                 System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
    433 
    434                 mParent.sendResponse(type, sendHeader);
    435                 start = end;
    436             }
    437 
    438             if (bodyLength > 0) {
    439                 return true;
    440             } else {
    441                 return false;
    442             }
    443 
    444         } else {
    445             out.write(headerArray);
    446         }
    447 
    448         // For Get operation: if response code is OBEX_HTTP_OK, then this is the
    449         // last packet; so set finalBitSet to true.
    450         if (mGetOperation && type == ResponseCodes.OBEX_HTTP_OK) {
    451             finalBitSet = true;
    452         }
    453 
    454         if(mSrmActive) {
    455             if(!mGetOperation && type == ResponseCodes.OBEX_HTTP_CONTINUE &&
    456                     mSrmResponseSent == true) {
    457                 // we are in the middle of a SRM PUT operation, don't send a continue.
    458                 skipSend = true;
    459             } else if(mGetOperation && mRequestFinished == false && mSrmResponseSent == true) {
    460                 // We are still receiving the get request, receive, but don't send continue.
    461                 skipSend = true;
    462             } else if(mGetOperation && mRequestFinished == true) {
    463                 // All done receiving the GET request, send data to the client, without
    464                 // expecting a continue.
    465                 skipReceive = true;
    466             }
    467             if(V)Log.v(TAG, "type==" + type + " skipSend==" + skipSend
    468                     + " skipReceive==" + skipReceive);
    469         }
    470         if(srmRespSendPending) {
    471             if(V)Log.v(TAG,
    472                     "SRM Enabled (srmRespSendPending == true)- sending SRM Enable response");
    473             mSrmResponseSent = true;
    474         }
    475 
    476         if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) {
    477             if (bodyLength > 0) {
    478                 /*
    479                  * Determine if I can send the whole body or just part of
    480                  * the body.  Remember that there is the 3 bytes for the
    481                  * response message and 3 bytes for the header ID and length
    482                  */
    483                 if (bodyLength > (mMaxPacketLength - headerArray.length - 6)) {
    484                     bodyLength = mMaxPacketLength - headerArray.length - 6;
    485                 }
    486 
    487                 byte[] body = mPrivateOutput.readBytes(bodyLength);
    488 
    489                 /*
    490                  * Since this is a put request if the final bit is set or
    491                  * the output stream is closed we need to send the 0x49
    492                  * (End of Body) otherwise, we need to send 0x48 (Body)
    493                  */
    494                 if ((finalBitSet) || (mPrivateOutput.isClosed())) {
    495                     if(mSendBodyHeader == true) {
    496                         out.write(0x49);
    497                         bodyLength += 3;
    498                         out.write((byte)(bodyLength >> 8));
    499                         out.write((byte)bodyLength);
    500                         out.write(body);
    501                     }
    502                 } else {
    503                     if(mSendBodyHeader == true) {
    504                     out.write(0x48);
    505                     bodyLength += 3;
    506                     out.write((byte)(bodyLength >> 8));
    507                     out.write((byte)bodyLength);
    508                     out.write(body);
    509                     }
    510                 }
    511 
    512             }
    513         }
    514 
    515         if ((finalBitSet) && (type == ResponseCodes.OBEX_HTTP_OK) && (orginalBodyLength <= 0)) {
    516             if(mSendBodyHeader) {
    517                 out.write(0x49);
    518                 orginalBodyLength = 3;
    519                 out.write((byte)(orginalBodyLength >> 8));
    520                 out.write((byte)orginalBodyLength);
    521             }
    522         }
    523 
    524         if(skipSend == false) {
    525             mResponseSize = 3;
    526             mParent.sendResponse(type, out.toByteArray());
    527         }
    528 
    529         if (type == ResponseCodes.OBEX_HTTP_CONTINUE) {
    530 
    531             if(mGetOperation && skipReceive) {
    532                 // Here we need to check for and handle abort (throw an exception).
    533                 // Any other signal received should be discarded silently (only on server side)
    534                 checkSrmRemoteAbort();
    535             } else {
    536                 // Receive and handle data (only send reply if !skipSend)
    537                 // Read a complete OBEX Packet
    538                 ObexPacket packet = ObexPacket.read(mInput);
    539 
    540                 int headerId = packet.mHeaderId;
    541                 if ((headerId != ObexHelper.OBEX_OPCODE_PUT)
    542                         && (headerId != ObexHelper.OBEX_OPCODE_PUT_FINAL)
    543                         && (headerId != ObexHelper.OBEX_OPCODE_GET)
    544                         && (headerId != ObexHelper.OBEX_OPCODE_GET_FINAL)) {
    545 
    546                     /*
    547                      * Determine if an ABORT was sent as the reply
    548                      */
    549                     if (headerId == ObexHelper.OBEX_OPCODE_ABORT) {
    550                         handleRemoteAbort();
    551                     } else {
    552                         // TODO:shall we send this if it occurs during SRM? Errata on the subject
    553                         mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
    554                         mClosed = true;
    555                         mExceptionString = "Bad Request Received";
    556                         throw new IOException("Bad Request Received");
    557                     }
    558                 } else {
    559 
    560                     if ((headerId == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
    561                         finalBitSet = true;
    562                     } else if (headerId == ObexHelper.OBEX_OPCODE_GET_FINAL) {
    563                         mRequestFinished = true;
    564                     }
    565 
    566                     /*
    567                      * Determine if the packet length is larger than the negotiated packet size
    568                      */
    569                     if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
    570                         mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
    571                         throw new IOException("Packet received was too large");
    572                     }
    573 
    574                     /*
    575                      * Determine if any headers were sent in the initial request
    576                      */
    577                     if (packet.mLength > 3 || (mSrmEnabled && packet.mLength == 3)) {
    578                         if(handleObexPacket(packet) == false) {
    579                             return false;
    580                         }
    581                     }
    582                 }
    583 
    584             }
    585             return true;
    586         } else {
    587             return false;
    588         }
    589     }
    590 
    591     /**
    592      * This method will look for an abort from the peer during a SRM transfer.
    593      * The function will not block if no data has been received from the remote device.
    594      * If data have been received, the function will block while reading the incoming
    595      * OBEX package.
    596      * An Abort request will be handled, and cause an IOException("Abort Received").
    597      * Other messages will be discarded silently as per GOEP specification.
    598      * @throws IOException if an abort request have been received.
    599      * TODO: I think this is an error in the specification. If we discard other messages,
    600      *       the peer device will most likely stall, as it will not receive the expected
    601      *       response for the message...
    602      *       I'm not sure how to understand "Receipt of invalid or unexpected SRM or SRMP
    603      *       header values shall be ignored by the receiving device."
    604      *       If any signal is received during an active SRM transfer it is unexpected regardless
    605      *       whether or not it contains SRM/SRMP headers...
    606      */
    607     private void checkSrmRemoteAbort() throws IOException {
    608         if(mInput.available() > 0) {
    609             ObexPacket packet = ObexPacket.read(mInput);
    610             /*
    611              * Determine if an ABORT was sent as the reply
    612              */
    613             if (packet.mHeaderId == ObexHelper.OBEX_OPCODE_ABORT) {
    614                 handleRemoteAbort();
    615             } else {
    616                 // TODO: should we throw an exception here anyway? - don't see how to
    617                 //       ignore SRM/SRMP headers without ignoring the complete signal
    618                 //       (in this particular case).
    619                 Log.w(TAG, "Received unexpected request from client - discarding...\n"
    620                         + "   headerId: " + packet.mHeaderId + " length: " + packet.mLength);
    621             }
    622         }
    623     }
    624 
    625     private void handleRemoteAbort() throws IOException {
    626         /* TODO: To increase the speed of the abort operation in SRM, we need
    627          *       to be able to flush the L2CAP queue for the PSM in use.
    628          *       This could be implemented by introducing a control
    629          *       message to be send over the socket, that in the abort case
    630          *       could carry a flush command. */
    631         mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
    632         mClosed = true;
    633         isAborted = true;
    634         mExceptionString = "Abort Received";
    635         throw new IOException("Abort Received");
    636     }
    637 
    638     /**
    639      * Sends an ABORT message to the server. By calling this method, the
    640      * corresponding input and output streams will be closed along with this
    641      * object.
    642      * @throws IOException if the transaction has already ended or if an OBEX
    643      *         server called this method
    644      */
    645     public void abort() throws IOException {
    646         throw new IOException("Called from a server");
    647     }
    648 
    649     /**
    650      * Returns the headers that have been received during the operation.
    651      * Modifying the object returned has no effect on the headers that are sent
    652      * or retrieved.
    653      * @return the headers received during this <code>Operation</code>
    654      * @throws IOException if this <code>Operation</code> has been closed
    655      */
    656     public HeaderSet getReceivedHeader() throws IOException {
    657         ensureOpen();
    658         return requestHeader;
    659     }
    660 
    661     /**
    662      * Specifies the headers that should be sent in the next OBEX message that
    663      * is sent.
    664      * @param headers the headers to send in the next message
    665      * @throws IOException if this <code>Operation</code> has been closed or the
    666      *         transaction has ended and no further messages will be exchanged
    667      * @throws IllegalArgumentException if <code>headers</code> was not created
    668      *         by a call to <code>ServerRequestHandler.createHeaderSet()</code>
    669      */
    670     public void sendHeaders(HeaderSet headers) throws IOException {
    671         ensureOpen();
    672 
    673         if (headers == null) {
    674             throw new IOException("Headers may not be null");
    675         }
    676 
    677         int[] headerList = headers.getHeaderList();
    678         if (headerList != null) {
    679             for (int i = 0; i < headerList.length; i++) {
    680                 replyHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
    681             }
    682 
    683         }
    684     }
    685 
    686     /**
    687      * Retrieves the response code retrieved from the server. Response codes are
    688      * defined in the <code>ResponseCodes</code> interface.
    689      * @return the response code retrieved from the server
    690      * @throws IOException if an error occurred in the transport layer during
    691      *         the transaction; if this method is called on a
    692      *         <code>HeaderSet</code> object created by calling
    693      *         <code>createHeaderSet</code> in a <code>ClientSession</code>
    694      *         object; if this is called from a server
    695      */
    696     public int getResponseCode() throws IOException {
    697         throw new IOException("Called from a server");
    698     }
    699 
    700     /**
    701      * Always returns <code>null</code>
    702      * @return <code>null</code>
    703      */
    704     public String getEncoding() {
    705         return null;
    706     }
    707 
    708     /**
    709      * Returns the type of content that the resource connected to is providing.
    710      * E.g. if the connection is via HTTP, then the value of the content-type
    711      * header field is returned.
    712      * @return the content type of the resource that the URL references, or
    713      *         <code>null</code> if not known
    714      */
    715     public String getType() {
    716         try {
    717             return (String)requestHeader.getHeader(HeaderSet.TYPE);
    718         } catch (IOException e) {
    719             return null;
    720         }
    721     }
    722 
    723     /**
    724      * Returns the length of the content which is being provided. E.g. if the
    725      * connection is via HTTP, then the value of the content-length header field
    726      * is returned.
    727      * @return the content length of the resource that this connection's URL
    728      *         references, or -1 if the content length is not known
    729      */
    730     public long getLength() {
    731         try {
    732             Long temp = (Long)requestHeader.getHeader(HeaderSet.LENGTH);
    733 
    734             if (temp == null) {
    735                 return -1;
    736             } else {
    737                 return temp.longValue();
    738             }
    739         } catch (IOException e) {
    740             return -1;
    741         }
    742     }
    743 
    744     public int getMaxPacketSize() {
    745         return mMaxPacketLength - 6 - getHeaderLength();
    746     }
    747 
    748     public int getHeaderLength() {
    749         long id = mListener.getConnectionId();
    750         if (id == -1) {
    751             replyHeader.mConnectionID = null;
    752         } else {
    753             replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
    754         }
    755 
    756         byte[] headerArray = ObexHelper.createHeader(replyHeader, false);
    757 
    758         return headerArray.length;
    759     }
    760 
    761     /**
    762      * Open and return an input stream for a connection.
    763      * @return an input stream
    764      * @throws IOException if an I/O error occurs
    765      */
    766     public InputStream openInputStream() throws IOException {
    767         ensureOpen();
    768         return mPrivateInput;
    769     }
    770 
    771     /**
    772      * Open and return a data input stream for a connection.
    773      * @return an input stream
    774      * @throws IOException if an I/O error occurs
    775      */
    776     public DataInputStream openDataInputStream() throws IOException {
    777         return new DataInputStream(openInputStream());
    778     }
    779 
    780     /**
    781      * Open and return an output stream for a connection.
    782      * @return an output stream
    783      * @throws IOException if an I/O error occurs
    784      */
    785     public OutputStream openOutputStream() throws IOException {
    786         ensureOpen();
    787 
    788         if (mPrivateOutputOpen) {
    789             throw new IOException("no more input streams available, stream already opened");
    790         }
    791 
    792         if (!mRequestFinished) {
    793             throw new IOException("no  output streams available ,request not finished");
    794         }
    795 
    796         if (mPrivateOutput == null) {
    797             mPrivateOutput = new PrivateOutputStream(this, getMaxPacketSize());
    798         }
    799         mPrivateOutputOpen = true;
    800         return mPrivateOutput;
    801     }
    802 
    803     /**
    804      * Open and return a data output stream for a connection.
    805      * @return an output stream
    806      * @throws IOException if an I/O error occurs
    807      */
    808     public DataOutputStream openDataOutputStream() throws IOException {
    809         return new DataOutputStream(openOutputStream());
    810     }
    811 
    812     /**
    813      * Closes the connection and ends the transaction
    814      * @throws IOException if the operation has already ended or is closed
    815      */
    816     public void close() throws IOException {
    817         ensureOpen();
    818         mClosed = true;
    819     }
    820 
    821     /**
    822      * Verifies that the connection is open and no exceptions should be thrown.
    823      * @throws IOException if an exception needs to be thrown
    824      */
    825     public void ensureOpen() throws IOException {
    826         if (mExceptionString != null) {
    827             throw new IOException(mExceptionString);
    828         }
    829         if (mClosed) {
    830             throw new IOException("Operation has already ended");
    831         }
    832     }
    833 
    834     /**
    835      * Verifies that additional information may be sent. In other words, the
    836      * operation is not done.
    837      * <P>
    838      * Included to implement the BaseStream interface only. It does not do
    839      * anything on the server side since the operation of the Operation object
    840      * is not done until after the handler returns from its method.
    841      * @throws IOException if the operation is completed
    842      */
    843     public void ensureNotDone() throws IOException {
    844     }
    845 
    846     /**
    847      * Called when the output or input stream is closed. It does not do anything
    848      * on the server side since the operation of the Operation object is not
    849      * done until after the handler returns from its method.
    850      * @param inStream <code>true</code> if the input stream is closed;
    851      *        <code>false</code> if the output stream is closed
    852      * @throws IOException if an IO error occurs
    853      */
    854     public void streamClosed(boolean inStream) throws IOException {
    855 
    856     }
    857 
    858     public void noBodyHeader(){
    859         mSendBodyHeader = false;
    860     }
    861 }
    862