/** * Receive MSRP response * * @param code Response code * @param txId Transaction ID * @param headers MSRP headers */ public void receiveMsrpResponse(int code, String txId, Hashtable<String, String> headers) { // Consider media is established when we received something mIsEstablished = true; if (sLogger.isActivated()) { sLogger.info("Response received (code=" + code + ", transaction=" + txId + ")"); } if (mFailureReportOption) { // Notify progress if (!mCancelTransfer && mProgress.size() > 0) { mMsrpEventListener.msrpTransferProgress(mProgress.elementAt(0), mTotalSize); mProgress.removeElementAt(0); } } // Notify request transaction if (mRequestTransaction != null) { mRequestTransaction.notifyResponse(code, headers); } // Notify MSRP transaction if (mMsrpTransaction != null) { mMsrpTransaction.handleResponse(); } // Notify event listener if (code != 200) { // Changed by Deutsche Telekom String cpimMsgId = null; TypeMsrpChunk typeMsrpChunk = TypeMsrpChunk.Unknown; MsrpTransactionInfo msrpTransactionInfo = getMsrpTransactionInfo(txId); if (msrpTransactionInfo != null) { cpimMsgId = msrpTransactionInfo.mCpimMsgId; typeMsrpChunk = msrpTransactionInfo.mTypeMsrpChunk; } mMsrpEventListener.msrpTransferError(cpimMsgId, "error response " + code, typeMsrpChunk); // Changed by Deutsche Telekom // If an error is received it couldn't get any better nor worse; transaction has reached // final state removeMsrpTransactionInfo(txId); } // Don't remove transaction info in general from list as this could be a preliminary answer }
/** * Receive MSRP REPORT request * * @param txId Transaction ID * @param headers MSRP headers * @throws NetworkException * @throws FileAccessException */ public void receiveMsrpReport(String txId, Hashtable<String, String> headers) throws FileAccessException, NetworkException { // Changed by Deutsche Telekom // Example of an MSRP REPORT request: // MSRP b276bb5b0adb22f6 SEND // To-Path: msrp://10.108.25.89:19494/n02s00i2t0+519;tcp // From-Path: msrp://10.102.192.68:20000/1375944013409;tcp // Message-ID: MID-3BCqcBUXKA // Byte-Range: 1-305/305 // Content-Type: message/cpim // // From: <sip:[email protected]> // To: <sip:[email protected]> // NS: imdn <urn:ietf:params:imdn> // imdn.Message-ID: Msg2BCqcBUWKA // DateTime: 2013-08-08T06:40:56.000Z // imdn.Disposition-Notification: positive-delivery, display // // Content-type: text/plain; charset=utf-8 // Content-length: 1 // // F // -------b276bb5b0adb22f6$ // // MSRP b276bb5b0adb22f6 200 OK // To-Path: msrp://10.102.192.68:20000/1375944013409;tcp // From-Path: msrp://10.108.25.89:19494/n02s00i2t0+519;tcp // -------b276bb5b0adb22f6$ // // MSRP n02s00i2t0+1937 REPORT // To-Path: msrp://10.102.192.68:20000/1375944013409;tcp // From-Path: msrp://10.108.25.89:19494/n02s00i2t0+519;tcp // Status: 000 413 413 // Message-ID: MID-3BCqcBUXKA // Byte-Range: 1-305/305 // -------n02s00i2t0+1937$ if (sLogger.isActivated()) { sLogger.info("REPORT request received (transaction=" + txId + ")"); } // Changed by Deutsche Telekom String msrpMsgId = headers.get(MsrpConstants.HEADER_MESSAGE_ID); String cpimMsgId = null; String originalTransactionId = null; TypeMsrpChunk typeMsrpChunk = TypeMsrpChunk.Unknown; MsrpTransactionInfo msrpTransactionInfo = getMsrpTransactionInfoByMessageId(msrpMsgId); if (msrpTransactionInfo != null) { typeMsrpChunk = msrpTransactionInfo.mTypeMsrpChunk; originalTransactionId = msrpTransactionInfo.mTransactionId; cpimMsgId = msrpTransactionInfo.mCpimMsgId; if (sLogger.isActivated()) { sLogger.debug( "REPORT request details; originalTransactionId=" + originalTransactionId + "; cpimMsgId=" + cpimMsgId + "; typeMsrpChunk=" + typeMsrpChunk); } } // Changed by Deutsche Telekom // Test if a failure report is needed boolean failureReportNeeded = true; String failureHeader = headers.get(MsrpConstants.HEADER_FAILURE_REPORT); if ((failureHeader != null) && failureHeader.equalsIgnoreCase("no")) { failureReportNeeded = false; } // Send MSRP response if requested if (failureReportNeeded) { sendMsrpResponse(MsrpConstants.STATUS_200_OK, txId, headers); } // Check status code int statusCode = ReportTransaction.parseStatusCode(headers); if (statusCode != 200) { // Changed by Deutsche Telekom mMsrpEventListener.msrpTransferError(cpimMsgId, "error report " + statusCode, typeMsrpChunk); } // Notify report transaction if (mReportTransaction != null) { mReportTransaction.notifyReport(statusCode, headers); } // Changed by Deutsche Telekom // Remove transaction info from list as transaction has reached a final state removeMsrpTransactionInfo(originalTransactionId); }
/** * Receive MSRP SEND request * * @param txId Transaction ID * @param headers Request headers * @param flag Continuation flag * @param data Received data * @param totalSize Total size of the content * @throws NetworkException * @throws PayloadException * @throws ContactManagerException */ public void receiveMsrpSend( String txId, Hashtable<String, String> headers, int flag, byte[] data, long totalSize) throws PayloadException, NetworkException, ContactManagerException { mIsEstablished = true; if (sLogger.isActivated()) { sLogger.debug( new StringBuilder("SEND request received (flag=") .append(flag) .append(", transaction=") .append(txId) .append(", totalSize=") .append(totalSize) .append(")") .toString()); } String msgId = headers.get(MsrpConstants.HEADER_MESSAGE_ID); boolean failureReportNeeded = true; String failureHeader = headers.get(MsrpConstants.HEADER_FAILURE_REPORT); if ((failureHeader != null) && failureHeader.equalsIgnoreCase("no")) { failureReportNeeded = false; } if (failureReportNeeded) { sendMsrpResponse(MsrpConstants.STATUS_200_OK, txId, headers); } if (data == null) { if (sLogger.isActivated()) { sLogger.debug("Empty chunk"); } return; } mReceivedChunks.addChunk(data); if (flag == MsrpConstants.FLAG_LAST_CHUNK) { if (sLogger.isActivated()) { sLogger.info("Transfer terminated"); } byte[] dataContent = mReceivedChunks.getReceivedData(); mReceivedChunks.resetCache(); String contentTypeHeader = headers.get(MsrpConstants.HEADER_CONTENT_TYPE); mMsrpEventListener.receiveMsrpData(msgId, dataContent, contentTypeHeader); boolean successReportNeeded = false; String reportHeader = headers.get(MsrpConstants.HEADER_SUCCESS_REPORT); if ((reportHeader != null) && reportHeader.equalsIgnoreCase("yes")) { successReportNeeded = true; } if (successReportNeeded) { sendMsrpReportRequest(txId, headers, dataContent.length, totalSize); } } else if (flag == MsrpConstants.FLAG_ABORT_CHUNK) { if (sLogger.isActivated()) { sLogger.info("Transfer aborted"); } mMsrpEventListener.msrpTransferAborted(); } else if (flag == MsrpConstants.FLAG_MORE_CHUNK) { if (sLogger.isActivated()) { sLogger.debug("Transfer in progress..."); } byte[] dataContent = mReceivedChunks.getReceivedData(); boolean resetCache = mMsrpEventListener.msrpTransferProgress( mReceivedChunks.getCurrentSize(), totalSize, dataContent); /* * Data are only consumed chunk by chunk in file transfer & image share. In a chat * session only the whole message is consumed after receiving the last chunk. */ if (resetCache) { mReceivedChunks.resetCache(); } } }
/** * Send chunks * * @param inputStream Input stream * @param msgId Message ID * @param contentType Content type to be sent * @param totalSize Total size of content * @param typeMsrpChunk Type of MSRP chunk * @throws NetworkException */ public void sendChunks( InputStream inputStream, String msgId, String contentType, final long totalSize, TypeMsrpChunk typeMsrpChunk) throws NetworkException { if (sLogger.isActivated()) { sLogger.info("Send content (" + contentType + " - MSRP chunk type: " + typeMsrpChunk + ")"); } this.mTotalSize = totalSize; try { byte data[] = new byte[MsrpConstants.CHUNK_MAX_SIZE]; long firstByte = 1; long lastByte = 0; mCancelTransfer = false; if (mSuccessReportOption) { mReportTransaction = new ReportTransaction(); } else { mReportTransaction = null; } if (mFailureReportOption) { mMsrpTransaction = new MsrpTransaction(); } else { mMsrpTransaction = null; } // Changed by Deutsche Telekom // Calculate number of needed chunks final int totalChunks = (int) Math.ceil(totalSize / (double) MsrpConstants.CHUNK_MAX_SIZE); new Thread( new Runnable() { @Override public void run() { if (mMsrpTransaction != null) { while ((totalChunks - mMsrpTransaction.getNumberReceivedOk()) > 0 && !mCancelTransfer) { mMsrpEventListener.msrpTransferProgress( mMsrpTransaction.getNumberReceivedOk() * MsrpConstants.CHUNK_MAX_SIZE, totalSize); try { Thread.sleep(500); } catch (InterruptedException e) { /* Nothing to be done here */ } } } } }) .start(); // Changed by Deutsche Telekom String newTransactionId = null; // Changed by Deutsche Telekom // RFC4975, section 7.1.1. Sending SEND Requests // When an endpoint has a message to deliver, it first generates a new // Message-ID. The value MUST be highly unlikely to be repeated by // another endpoint instance, or by the same instance in the future. // Message-ID value follows the definition in RFC4975, section 9 String msrpMsgId = IdGenerator.generateMessageID(); // Send data chunk by chunk for (int i = inputStream.read(data); (!mCancelTransfer) & (i > -1); i = inputStream.read(data)) { // Update upper byte range lastByte += i; // Changed by Deutsche Telekom newTransactionId = generateTransactionId(); addMsrpTransactionInfo(newTransactionId, msrpMsgId, msgId, typeMsrpChunk); // Send a chunk // Changed by Deutsche Telekom sendMsrpSendRequest( newTransactionId, mTo, mFrom, msrpMsgId, contentType, i, data, firstByte, lastByte, totalSize); // Update lower byte range firstByte += i; // Progress management if (mFailureReportOption) { // Add value in progress vector mProgress.add(lastByte); } else { // Direct notification if (!mCancelTransfer) { mMsrpEventListener.msrpTransferProgress(lastByte, totalSize); } } } if (mCancelTransfer) { // Transfer has been aborted return; } // Waiting msrpTransaction if (mMsrpTransaction != null) { // Wait until all data have been reported mMsrpTransaction.waitAllResponses(); // Notify event listener if (mMsrpTransaction.isAllResponsesReceived()) { mMsrpEventListener.msrpDataTransfered(msgId); } else { if (!mMsrpTransaction.isTerminated()) { // Changed by Deutsche Telekom mMsrpEventListener.msrpTransferError(msgId, "response timeout 408", typeMsrpChunk); } } } // Waiting reportTransaction if (mReportTransaction != null) { // Wait until all data have been reported while (!mReportTransaction.isTransactionFinished(totalSize)) { mReportTransaction.waitReport(); if (mReportTransaction.getStatusCode() != 200) { // Error break; } } // Notify event listener if (mReportTransaction.getStatusCode() == 200) { mMsrpEventListener.msrpDataTransfered(msgId); } else { // Changed by Deutsche Telekom mMsrpEventListener.msrpTransferError( msgId, "error report " + mReportTransaction.getStatusCode(), typeMsrpChunk); } } // No transaction if (mMsrpTransaction == null && mReportTransaction == null) { // Notify event listener mMsrpEventListener.msrpDataTransfered(msgId); } } catch (IOException e) { throw new NetworkException( new StringBuilder("Send chunk failed for msgId : ").append(msgId).toString(), e); } finally { CloseableUtils.tryToClose(inputStream); } }