/** * Receive CANCEL request * * @param cancel CANCEL request */ public void receiveCancel(SipRequest cancel) { if (logger.isActivated()) { logger.info("ABC Receive a CANCEL message from the remote"); } if (getDialogPath().isSigEstablished()) { if (logger.isActivated()) { logger.info( "Ignore the received CANCEL message from the remote (session already established)"); } return; } // Close media session closeMediaSession(); // Update dialog path getDialogPath().sessionCancelled(); // Send a 487 Request terminated try { if (logger.isActivated()) { logger.info("Send 487 Request terminated"); } SipResponse terminatedResp = SipMessageFactory.createResponse( getDialogPath().getInvite(), getDialogPath().getLocalTag(), 487); getImsService().getImsModule().getSipManager().sendSipResponse(terminatedResp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 487 error response", e); } } // Remove the current session getImsService().removeSession(this); // Set invitation status invitationStatus = ImsServiceSession.INVITATION_CANCELED; // Unblock semaphore synchronized (waitUserAnswer) { waitUserAnswer.notifyAll(); } // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionTerminatedByRemote(); } // Request capabilities to the remote getImsService() .getImsModule() .getCapabilityService() .requestContactCapabilities(getDialogPath().getRemoteParty()); }
/** * Send a 180 Ringing response to the remote party * * @param request SIP request * @param localTag Local tag */ public void send180Ringing(SipRequest request, String localTag) { try { SipResponse progress = SipMessageFactory.createResponse(request, localTag, 180); getImsService().getImsModule().getSipManager().sendSipResponse(progress); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send a 180 Ringing response"); } } }
/** * Handle 422 response * * @param resp 422 response */ private void handle422SessionTooSmall(SipResponse resp) { try { // 422 response received if (logger.isActivated()) { logger.info("422 response received"); } // Extract the Min-SE value int minExpire = SipUtils.getMinSessionExpirePeriod(resp); if (minExpire == -1) { if (logger.isActivated()) { logger.error("Can't read the Min-SE value"); } handleError( new FileSharingError(FileSharingError.UNEXPECTED_EXCEPTION, "No Min-SE value found")); return; } // Set the min expire value getDialogPath().setMinSessionExpireTime(minExpire); // Set the expire value getDialogPath().setSessionExpireTime(minExpire); // Increment the Cseq number of the dialog path getDialogPath().incrementCseq(); // Create a new INVITE with the right expire period if (logger.isActivated()) { logger.info("Send new INVITE"); } SipRequest invite = SipMessageFactory.createInvite( getDialogPath(), InstantMessagingService.FT_FEATURE_TAGS, getDialogPath().getLocalContent()); // Set the Authorization header getAuthenticationAgent().setAuthorizationHeader(invite); // Reset initial request in the dialog path getDialogPath().setInvite(invite); // Send INVITE request sendInvite(invite); } catch (Exception e) { if (logger.isActivated()) { logger.error("Session initiation has failed", e); } // Unexpected error handleError(new FileSharingError(FileSharingError.UNEXPECTED_EXCEPTION, e.getMessage())); } }
/** * Send a 415 "Unsupported Media Type" to the remote party * * @param request SIP request */ public void send415Error(SipRequest request) { try { if (logger.isActivated()) { logger.info("Send 415 Unsupported Media Type"); } SipResponse resp = SipMessageFactory.createResponse(request, 415); // TODO: set Accept-Encoding header getImsService().getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 415 error response", e); } } }
/** * Send a 486 "Busy" to the remote party * * @param request SIP request * @param localTag Local tag */ public void send486Busy(SipRequest request, String localTag) { try { // Send a 486 Busy error if (logger.isActivated()) { logger.info("Send 486 Busy"); } SipResponse resp = SipMessageFactory.createResponse(request, localTag, 486); getImsService().getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 486 Busy response", e); } } }
/** * Send an error response to the remote party * * @param request SIP request * @param localTag Local tag * @param code Response code */ public void sendErrorResponse(SipRequest request, String localTag, int code) { try { // Send error if (logger.isActivated()) { logger.info("Send " + code + " error response"); } SipResponse resp = SipMessageFactory.createResponse(request, localTag, code); getImsService().getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send error response", e); } } }
/** * Create INVITE request * * @param content Content part * @return Request * @throws SipException */ private SipRequest createInviteRequest(String content) throws SipException { SipRequest invite = SipMessageFactory.createInvite( getDialogPath(), getFeatureTags(), getAcceptContactTags(), content); // Test if there is a subject if (getSubject() != null) { // Add a subject header invite.addHeader(SubjectHeader.NAME, StringUtils.encodeUTF8(getSubject())); } // Add a contribution ID header invite.addHeader(ChatUtils.HEADER_CONTRIBUTION_ID, getContributionID()); return invite; }
/** * Handle 407 Proxy Authentication Required * * @param resp 407 response */ public void handle407Authentication(SipResponse resp) { try { if (logger.isActivated()) { logger.info("407 response received"); } // Set the remote tag getDialogPath().setRemoteTag(resp.getToTag()); // Update the authentication agent getAuthenticationAgent().readProxyAuthenticateHeader(resp); // Increment the Cseq number of the dialog path getDialogPath().incrementCseq(); // Create a second INVITE request with the right token if (logger.isActivated()) { logger.info("Send second INVITE"); } SipRequest invite = SipMessageFactory.createInvite( getDialogPath(), InstantMessagingService.FT_FEATURE_TAGS, getDialogPath().getLocalContent()); // Reset initial request in the dialog path getDialogPath().setInvite(invite); // Set the Proxy-Authorization header getAuthenticationAgent().setProxyAuthorizationHeader(invite); // Send INVITE request sendInvite(invite); } catch (Exception e) { if (logger.isActivated()) { logger.error("Session initiation has failed", e); } // Unexpected error handleError(new FileSharingError(FileSharingError.UNEXPECTED_EXCEPTION, e.getMessage())); } }
/** * Receive a capability request (options procedure) * * @param options Received options message */ public void receiveCapabilityRequest(SipRequest options) { String contact = SipUtils.getAssertedIdentity(options); if (logger.isActivated()) { logger.debug("OPTIONS request received during a call from " + contact); } try { // Create 200 OK response String ipAddress = getImsModule().getCurrentNetworkInterface().getNetworkAccess().getIpAddress(); boolean richcall = getImsModule().getCallManager().isRichcallSupportedWith(contact); SipResponse resp = SipMessageFactory.create200OkOptionsResponse( options, getImsModule().getSipManager().getSipStack().getLocalContact(), CapabilityUtils.getSupportedFeatureTags(richcall), CapabilityUtils.buildSdp(ipAddress, richcall)); // Send 200 OK response getImsModule().getSipManager().sendSipResponse(resp); } catch (Exception e) { if (logger.isActivated()) { logger.error("Can't send 200 OK for OPTIONS", e); } } // Extract capabilities from the request Capabilities capabilities = CapabilityUtils.extractCapabilities(options); logger.debug("capabilities = " + capabilities); if (capabilities.isImSessionSupported()) { // The contact is RCS capable ContactsManager.getInstance() .setContactCapabilities( contact, capabilities, ContactInfo.RCS_CAPABLE, ContactInfo.REGISTRATION_STATUS_ONLINE); /** M: Added to fix the issue that RCS-e icon does not display in contact list of People.@{ */ capabilities.setRcseContact(true); /** @} */ } else { // The contact is not RCS ContactsManager.getInstance() .setContactCapabilities( contact, capabilities, ContactInfo.NOT_RCS, ContactInfo.REGISTRATION_STATUS_UNKNOWN); /** M: Added to fix the issue that RCS-e icon does not display in contact list of People.@{ */ capabilities.setRcseContact(false); /** @} */ } /** M: Added to fix the issue that RCS-e icon does not display in contact list of People.@{ */ if (logger.isActivated()) { logger.debug( "receiveCapabilityRequest setRcseContact contact: " + contact + " " + capabilities.isImSessionSupported()); } /** @} */ // Notify listener getImsModule().getCore().getListener().handleCapabilitiesNotification(contact, capabilities); }
/** * Add a list of participants to the session * * @param participants List of participants */ public void addParticipants(List<String> participants) { try { if (participants.size() == 1) { addParticipant(participants.get(0)); return; } if (logger.isActivated()) { logger.debug("Add " + participants.size() + " participants to the session"); } // Re-use INVITE dialog path SessionAuthenticationAgent authenticationAgent = getAuthenticationAgent(); // Increment the Cseq number of the dialog path getDialogPath().incrementCseq(); // Send REFER request if (logger.isActivated()) { logger.debug("Send REFER"); } SipRequest refer = SipMessageFactory.createRefer(getDialogPath(), participants); SipTransactionContext ctx = getImsService().getImsModule().getSipManager().sendSipMessageAndWait(refer); // Wait response if (logger.isActivated()) { logger.debug("Wait response"); } ctx.waitResponse(SipManager.TIMEOUT); // Analyze received message if (ctx.getStatusCode() == 407) { // 407 response received if (logger.isActivated()) { logger.debug("407 response received"); } // Set the Proxy-Authorization header authenticationAgent.readProxyAuthenticateHeader(ctx.getSipResponse()); // Increment the Cseq number of the dialog path getDialogPath().incrementCseq(); // Create a second REFER request with the right token if (logger.isActivated()) { logger.info("Send second REFER"); } refer = SipMessageFactory.createRefer(getDialogPath(), participants); // Set the Authorization header authenticationAgent.setProxyAuthorizationHeader(refer); // Send REFER request ctx = getImsService().getImsModule().getSipManager().sendSipMessageAndWait(refer); // Wait response if (logger.isActivated()) { logger.debug("Wait response"); } ctx.waitResponse(SipManager.TIMEOUT); // Analyze received message if ((ctx.getStatusCode() >= 200) && (ctx.getStatusCode() < 300)) { // 200 OK response if (logger.isActivated()) { logger.debug("20x OK response received"); } // Notify listeners for (int i = 0; i < getListeners().size(); i++) { ((ChatSessionListener) getListeners().get(i)).handleAddParticipantSuccessful(); } } else { // Error if (logger.isActivated()) { logger.debug("REFER has failed (" + ctx.getStatusCode() + ")"); } // Notify listeners for (int i = 0; i < getListeners().size(); i++) { ((ChatSessionListener) getListeners().get(i)) .handleAddParticipantFailed(ctx.getReasonPhrase()); } } } else if ((ctx.getStatusCode() >= 200) && (ctx.getStatusCode() < 300)) { // 200 OK received if (logger.isActivated()) { logger.debug("20x OK response received"); } // Notify listeners for (int i = 0; i < getListeners().size(); i++) { ((ChatSessionListener) getListeners().get(i)).handleAddParticipantSuccessful(); } } else { // Error responses if (logger.isActivated()) { logger.debug("No response received"); } // Notify listeners for (int i = 0; i < getListeners().size(); i++) { ((ChatSessionListener) getListeners().get(i)) .handleAddParticipantFailed(ctx.getReasonPhrase()); } } } catch (Exception e) { if (logger.isActivated()) { logger.error("REFER request has failed", e); } // Notify listeners for (int i = 0; i < getListeners().size(); i++) { ((ChatSessionListener) getListeners().get(i)).handleAddParticipantFailed(e.getMessage()); } } }
private SipRequest createSipInvite() { logger.debug("createSipInvite()"); // Set setup mode String localSetup = createSetupOffer(); if (logger.isActivated()) { logger.debug("Local setup attribute is " + localSetup); } // Set local port int localMsrpPort = 9; // See RFC4145, Page 4 // Create the MSRP manager String localIpAddress = getImsService() .getImsModule() .getCurrentNetworkInterface() .getNetworkAccess() .getIpAddress(); msrpMgr = new MsrpManager(localIpAddress, localMsrpPort); // Build SDP part String ntpTime = SipUtils.constructNTPtime(System.currentTimeMillis()); String ipAddress = getDialogPath().getSipStack().getLocalIpAddress(); /** M: add for MSRPoTLS @{ */ String protocol = getCurrentProtocol(); String sdp = null; if (PROTOCOL_TLS.equals(protocol)) { sdp = "v=0" + SipUtils.CRLF + "o=- " + ntpTime + " " + ntpTime + " IN IP4 " + ipAddress + SipUtils.CRLF + "s=-" + SipUtils.CRLF + "c=IN IP4 " + ipAddress + SipUtils.CRLF + "t=0 0" + SipUtils.CRLF + "m=message " + localMsrpPort + " TCP/TLS/MSRP *" + SipUtils.CRLF + "a=path:" + msrpMgr.getLocalMsrpsPath() + SipUtils.CRLF + "a=fingerprint:" + KeyStoreManager.getFingerPrint() + SipUtils.CRLF + "a=setup:" + localSetup + SipUtils.CRLF + "a=accept-types: " + getContent().getEncoding() + SipUtils.CRLF + "a=file-transfer-id:" + getFileTransferId() + SipUtils.CRLF + "a=file-disposition:attachment" + SipUtils.CRLF + "a=sendonly" + SipUtils.CRLF; } else { sdp = "v=0" + SipUtils.CRLF + "o=- " + ntpTime + " " + ntpTime + " IN IP4 " + ipAddress + SipUtils.CRLF + "s=-" + SipUtils.CRLF + "c=IN IP4 " + ipAddress + SipUtils.CRLF + "t=0 0" + SipUtils.CRLF + "m=message " + localMsrpPort + " TCP/MSRP *" + SipUtils.CRLF + "a=path:" + msrpMgr.getLocalMsrpPath() + SipUtils.CRLF + "a=setup:" + localSetup + SipUtils.CRLF + "a=accept-types: " + getContent().getEncoding() + SipUtils.CRLF + "a=file-transfer-id:" + getFileTransferId() + SipUtils.CRLF + "a=file-disposition:attachment" + SipUtils.CRLF + "a=sendonly" + SipUtils.CRLF; } int maxSize = FileSharingSession.getMaxFileSharingSize(); if (maxSize > 0) { sdp += "a=max-size:" + maxSize + SipUtils.CRLF; } /** @} */ // Set File-selector attribute String selector = getFileSelectorAttribute(); if (selector != null) { sdp += "a=file-selector:" + selector + SipUtils.CRLF; } // Set File-location attribute String location = getFileLocationAttribute(); if (location != null) { sdp += "a=file-location:" + location + SipUtils.CRLF; } // Set the local SDP part in the dialog path getDialogPath().setLocalContent(sdp); // Create an INVITE request if (logger.isActivated()) { logger.info("Create INVITE"); } try { SipRequest invite; invite = SipMessageFactory.createInvite( getDialogPath(), InstantMessagingService.FT_FEATURE_TAGS, sdp); // Set the Authorization header getAuthenticationAgent().setAuthorizationHeader(invite); // Set initial request in the dialog path getDialogPath().setInvite(invite); return invite; } catch (SipException e) { e.printStackTrace(); } catch (CoreException e) { e.printStackTrace(); } logger.error("Create sip invite failed, return null."); return null; }
/** Background processing */ public void run() { try { if (logger.isActivated()) { logger.info("Initiate a new 1-1 chat session as terminating"); } // Send message delivery report if requested if ((ChatUtils.isImdnDeliveredRequested(getDialogPath().getInvite())) || (ChatUtils.isFileTransferOverHttp(getDialogPath().getInvite()))) { // Check notification disposition String msgId = ChatUtils.getMessageId(getDialogPath().getInvite()); if (msgId != null) { // Send message delivery status via a SIP MESSAGE getImdnManager() .sendMessageDeliveryStatusImmediately( getDialogPath().getRemoteParty(), msgId, ImdnDocument.DELIVERY_STATUS_DELIVERED, SipUtils.getRemoteInstanceID(getDialogPath().getInvite())); } } // Check if Auto-accept (FT HTTP force auto-accept for the chat session) if (RcsSettings.getInstance().isChatAutoAccepted() || ChatUtils.getHttpFTInfo(getDialogPath().getInvite()) != null) { if (logger.isActivated()) { logger.info("Auto accept chat invitation"); } } else { if (logger.isActivated()) { logger.info("Accept manually chat invitation"); } // Send a 180 Ringing response send180Ringing(getDialogPath().getInvite(), getDialogPath().getLocalTag()); // Wait invitation answer int answer = waitInvitationAnswer(); if (answer == ImsServiceSession.INVITATION_REJECTED) { if (logger.isActivated()) { logger.info("Session has been rejected by user"); } // Remove the current session getImsService().removeSession(this); // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionAborted(ImsServiceSession.TERMINATION_BY_USER); } return; } else if (answer == ImsServiceSession.INVITATION_NOT_ANSWERED) { if (logger.isActivated()) { logger.info("Session has been rejected on timeout"); } // Ringing period timeout send486Busy(getDialogPath().getInvite(), getDialogPath().getLocalTag()); // Remove the current session getImsService().removeSession(this); // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionAborted(ImsServiceSession.TERMINATION_BY_TIMEOUT); } return; } else if (answer == ImsServiceSession.INVITATION_CANCELED) { if (logger.isActivated()) { logger.info("Session has been canceled"); } return; } } // Parse the remote SDP part String remoteSdp = getDialogPath().getInvite().getSdpContent(); SdpParser parser = new SdpParser(remoteSdp.getBytes()); Vector<MediaDescription> media = parser.getMediaDescriptions(); MediaDescription mediaDesc = media.elementAt(0); MediaAttribute attr1 = mediaDesc.getMediaAttribute("path"); String remotePath = attr1.getValue(); String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc); int remotePort = mediaDesc.port; // Extract the "setup" parameter String remoteSetup = "passive"; MediaAttribute attr2 = mediaDesc.getMediaAttribute("setup"); if (attr2 != null) { remoteSetup = attr2.getValue(); } if (logger.isActivated()) { logger.info("Remote setup attribute is " + remoteSetup); } // Set setup mode String localSetup = createSetupAnswer(remoteSetup); if (logger.isActivated()) { logger.debug("Local setup attribute is " + localSetup); } // Set local port int localMsrpPort; if (localSetup.equals("active")) { localMsrpPort = 9; // See RFC4145, Page 4 } else { localMsrpPort = getMsrpMgr().getLocalMsrpPort(); } // Build SDP part String ntpTime = SipUtils.constructNTPtime(System.currentTimeMillis()); String ipAddress = getDialogPath().getSipStack().getLocalIpAddress(); String sdp = null; if (isSecureProtocolMessage()) { sdp = "v=0" + SipUtils.CRLF + "o=- " + ntpTime + " " + ntpTime + " " + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + "s=-" + SipUtils.CRLF + "c=" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + "t=0 0" + SipUtils.CRLF + "m=message " + localMsrpPort + " " + getMsrpMgr().getLocalSocketProtocol() + " *" + SipUtils.CRLF + "a=accept-types:" + getAcceptTypes() + SipUtils.CRLF + "a=accept-wrapped-types:" + getWrappedTypes() + SipUtils.CRLF + "a=setup:" + localSetup + SipUtils.CRLF + "a=path:" + getMsrpMgr().getLocalMsrpPath() + SipUtils.CRLF + "a=fingerprint:" + KeyStoreManager.getFingerPrint() + SipUtils.CRLF + "a=sendrecv" + SipUtils.CRLF; } else { sdp = "v=0" + SipUtils.CRLF + "o=- " + ntpTime + " " + ntpTime + " " + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + "s=-" + SipUtils.CRLF + "c=" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + "t=0 0" + SipUtils.CRLF + "m=message " + localMsrpPort + " " + getMsrpMgr().getLocalSocketProtocol() + " *" + SipUtils.CRLF + "a=accept-types:" + getAcceptTypes() + SipUtils.CRLF + "a=accept-wrapped-types:" + getWrappedTypes() + SipUtils.CRLF + "a=setup:" + localSetup + SipUtils.CRLF + "a=path:" + getMsrpMgr().getLocalMsrpPath() + SipUtils.CRLF + "a=sendrecv" + SipUtils.CRLF; } // Set the local SDP part in the dialog path getDialogPath().setLocalContent(sdp); // Test if the session should be interrupted if (isInterrupted()) { if (logger.isActivated()) { logger.info("Session has been interrupted: end of processing"); } return; } // Create the MSRP server session if (localSetup.equals("passive")) { // Passive mode: client wait a connection MsrpSession session = getMsrpMgr().createMsrpServerSession(remotePath, this); session.setFailureReportOption(false); session.setSuccessReportOption(false); // Open the connection Thread thread = new Thread() { public void run() { try { // Open the MSRP session getMsrpMgr().openMsrpSession(); // Send an empty packet sendEmptyDataChunk(); } catch (IOException e) { if (logger.isActivated()) { logger.error("Can't create the MSRP server session", e); } } } }; thread.start(); } // Create a 200 OK response if (logger.isActivated()) { logger.info("Send 200 OK"); } SipResponse resp = null; if (!RcsSettings.getInstance().isCPMSupported()) { resp = SipMessageFactory.create200OkInviteResponse(getDialogPath(), getFeatureTags(), sdp); } else { if (logger.isActivated()) { logger.info("TerminatingFOne2OneSession2 CPMS"); } resp = SipMessageFactory.createCpm200OkInviteResponse( getDialogPath(), getCpimFeatureTags(), sdp); } if (RcsSettings.getInstance().isCPMSupported()) { if (logger.isActivated()) { logger.info("TerminatingFOne2OneSession3 CPMS"); } if (getContributionID() != null) { resp.addHeader(ChatUtils.HEADER_CONTRIBUTION_ID, getContributionID()); } if (getConversationID() != null) { resp.addHeader(ChatUtils.HEADER_CONVERSATION_ID, getConversationID()); } if (getInReplyID() != null) { resp.addHeader(ChatUtils.HEADER_INREPLY_TO_CONTRIBUTION_ID, getInReplyID()); } } // The signalisation is established getDialogPath().sigEstablished(); // Send response SipTransactionContext ctx = getImsService().getImsModule().getSipManager().sendSipMessageAndWait(resp); // Analyze the received response if (ctx.isSipAck()) { // ACK received if (logger.isActivated()) { logger.info("ACK request received"); } // The session is established getDialogPath().sessionEstablished(); // Create the MSRP client session if (localSetup.equals("active")) { // Active mode: client should connect MsrpSession session = getMsrpMgr().createMsrpClientSession(remoteHost, remotePort, remotePath, this); session.setFailureReportOption(false); session.setSuccessReportOption(false); // Open the MSRP session getMsrpMgr().openMsrpSession(); // Send an empty packet sendEmptyDataChunk(); } // Notify listeners for (int i = 0; i < getListeners().size(); i++) { getListeners().get(i).handleSessionStarted(); } if (logger.isActivated()) { logger.info( "ABC ACK request received Dialog expire time: " + getDialogPath().getSessionExpireTime()); } // Start session timer if (getSessionTimerManager().isSessionTimerActivated(resp)) { getSessionTimerManager() .start(SessionTimerManager.UAS_ROLE, getDialogPath().getSessionExpireTime()); } // Start the activity manager getActivityManager().start(); } else { if (logger.isActivated()) { logger.info("No ACK received for INVITE"); } // No response received: timeout handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED)); } } catch (Exception e) { if (logger.isActivated()) { logger.error("Session initiation has failed", e); } // Unexpected error handleError(new ChatError(ChatError.UNEXPECTED_EXCEPTION, e.getMessage())); } }