Search in sources :

Example 6 with SIPMessage

use of gov.nist.javax.sip.message.SIPMessage in project XobotOS by xamarin.

the class StringMsgParser method parseSIPMessage.

/**
     * Parse a buffer containing a single SIP Message where the body is an array
     * of un-interpreted bytes. This is intended for parsing the message from a
     * memory buffer when the buffer. Incorporates a bug fix for a bug that was
     * noted by Will Sullin of Callcast
     *
     * @param msgBuffer
     *            a byte buffer containing the messages to be parsed. This can
     *            consist of multiple SIP Messages concatenated together.
     * @return a SIPMessage[] structure (request or response) containing the
     *         parsed SIP message.
     * @exception ParseException
     *                is thrown when an illegal message has been encountered
     *                (and the rest of the buffer is discarded).
     * @see ParseExceptionListener
     */
public SIPMessage parseSIPMessage(byte[] msgBuffer) throws ParseException {
    if (msgBuffer == null || msgBuffer.length == 0)
        return null;
    int i = 0;
    // Squeeze out any leading control character.
    try {
        while (msgBuffer[i] < 0x20) i++;
    } catch (ArrayIndexOutOfBoundsException e) {
        // Array contains only control char, return null.
        return null;
    }
    // Iterate thru the request/status line and headers.
    String currentLine = null;
    String currentHeader = null;
    boolean isFirstLine = true;
    SIPMessage message = null;
    do {
        int lineStart = i;
        // Find the length of the line.
        try {
            while (msgBuffer[i] != '\r' && msgBuffer[i] != '\n') i++;
        } catch (ArrayIndexOutOfBoundsException e) {
            // End of the message.
            break;
        }
        int lineLength = i - lineStart;
        // Make it a String.
        try {
            currentLine = new String(msgBuffer, lineStart, lineLength, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new ParseException("Bad message encoding!", 0);
        }
        currentLine = trimEndOfLine(currentLine);
        if (currentLine.length() == 0) {
            // Last header line, process the previous buffered header.
            if (currentHeader != null && message != null) {
                processHeader(currentHeader, message);
            }
        } else {
            if (isFirstLine) {
                message = processFirstLine(currentLine);
            } else {
                char firstChar = currentLine.charAt(0);
                if (firstChar == '\t' || firstChar == ' ') {
                    if (currentHeader == null)
                        throw new ParseException("Bad header continuation.", 0);
                    // This is a continuation, append it to the previous line.
                    currentHeader += currentLine.substring(1);
                } else {
                    if (currentHeader != null && message != null) {
                        processHeader(currentHeader, message);
                    }
                    currentHeader = currentLine;
                }
            }
        }
        if (msgBuffer[i] == '\r' && msgBuffer.length > i + 1 && msgBuffer[i + 1] == '\n')
            i++;
        i++;
        isFirstLine = false;
    } while (// End do - while
    currentLine.length() > 0);
    if (message == null)
        throw new ParseException("Bad message", 0);
    message.setSize(i);
    if (readBody && message.getContentLength() != null && message.getContentLength().getContentLength() != 0) {
        int bodyLength = msgBuffer.length - i;
        byte[] body = new byte[bodyLength];
        System.arraycopy(msgBuffer, i, body, 0, bodyLength);
        message.setMessageContent(body, computeContentLengthFromMessage, message.getContentLength().getContentLength());
    }
    return message;
}
Also used : SIPMessage(gov.nist.javax.sip.message.SIPMessage) UnsupportedEncodingException(java.io.UnsupportedEncodingException) ParseException(java.text.ParseException)

Example 7 with SIPMessage

use of gov.nist.javax.sip.message.SIPMessage in project XobotOS by xamarin.

the class SIPServerTransaction method sendResponse.

/*
     * (non-Javadoc)
     *
     * @see javax.sip.ServerTransaction#sendResponse(javax.sip.message.Response)
     */
public void sendResponse(Response response) throws SipException {
    SIPResponse sipResponse = (SIPResponse) response;
    SIPDialog dialog = this.dialog;
    if (response == null)
        throw new NullPointerException("null response");
    try {
        sipResponse.checkHeaders();
    } catch (ParseException ex) {
        throw new SipException(ex.getMessage());
    }
    // check for meaningful response.
    if (!sipResponse.getCSeq().getMethod().equals(this.getMethod())) {
        throw new SipException("CSeq method does not match Request method of request that created the tx.");
    }
    /*
         * 200-class responses to SUBSCRIBE requests also MUST contain an "Expires" header. The
         * period of time in the response MAY be shorter but MUST NOT be longer than specified in
         * the request.
         */
    if (this.getMethod().equals(Request.SUBSCRIBE) && response.getStatusCode() / 100 == 2) {
        if (response.getHeader(ExpiresHeader.NAME) == null) {
            throw new SipException("Expires header is mandatory in 2xx response of SUBSCRIBE");
        } else {
            Expires requestExpires = (Expires) this.getOriginalRequest().getExpires();
            Expires responseExpires = (Expires) response.getExpires();
            /*
                 * If no "Expires" header is present in a SUBSCRIBE request, the implied default
                 * is defined by the event package being used.
                 */
            if (requestExpires != null && responseExpires.getExpires() > requestExpires.getExpires()) {
                throw new SipException("Response Expires time exceeds request Expires time : See RFC 3265 3.1.1");
            }
        }
    }
    // Check for mandatory header.
    if (sipResponse.getStatusCode() == 200 && sipResponse.getCSeq().getMethod().equals(Request.INVITE) && sipResponse.getHeader(ContactHeader.NAME) == null)
        throw new SipException("Contact Header is mandatory for the OK to the INVITE");
    if (!this.isMessagePartOfTransaction((SIPMessage) response)) {
        throw new SipException("Response does not belong to this transaction.");
    }
    // Fix up the response if the dialog has already been established.
    try {
        /*
             * The UAS MAY send a final response to the initial request before
             * having received PRACKs for all unacknowledged reliable provisional responses,
             * unless the final response is 2xx and any of the unacknowledged reliable provisional
             * responses contained a session description. In that case, it MUST NOT send a final
             * response until those provisional responses are acknowledged.
             */
        if (this.pendingReliableResponse != null && this.getDialog() != null && this.getState() != TransactionState.TERMINATED && ((SIPResponse) response).getContentTypeHeader() != null && response.getStatusCode() / 100 == 2 && ((SIPResponse) response).getContentTypeHeader().getContentType().equalsIgnoreCase("application") && ((SIPResponse) response).getContentTypeHeader().getContentSubType().equalsIgnoreCase("sdp")) {
            try {
                boolean acquired = this.provisionalResponseSem.tryAcquire(1, TimeUnit.SECONDS);
                if (!acquired) {
                    throw new SipException("cannot send response -- unacked povisional");
                }
            } catch (Exception ex) {
                this.sipStack.getStackLogger().logError("Could not acquire PRACK sem ", ex);
            }
        } else {
            // pending response task.
            if (this.pendingReliableResponse != null && sipResponse.isFinalResponse()) {
                this.provisionalResponseTask.cancel();
                this.provisionalResponseTask = null;
            }
        }
        // being sent makes sense.
        if (dialog != null) {
            if (sipResponse.getStatusCode() / 100 == 2 && sipStack.isDialogCreated(sipResponse.getCSeq().getMethod())) {
                if (dialog.getLocalTag() == null && sipResponse.getTo().getTag() == null) {
                    // Trying to send final response and user forgot to set
                    // to
                    // tag on the response -- be nice and assign the tag for
                    // the user.
                    sipResponse.getTo().setTag(Utils.getInstance().generateTag());
                } else if (dialog.getLocalTag() != null && sipResponse.getToTag() == null) {
                    sipResponse.setToTag(dialog.getLocalTag());
                } else if (dialog.getLocalTag() != null && sipResponse.getToTag() != null && !dialog.getLocalTag().equals(sipResponse.getToTag())) {
                    throw new SipException("Tag mismatch dialogTag is " + dialog.getLocalTag() + " responseTag is " + sipResponse.getToTag());
                }
            }
            if (!sipResponse.getCallId().getCallId().equals(dialog.getCallId().getCallId())) {
                throw new SipException("Dialog mismatch!");
            }
        }
        // Backward compatibility slippery slope....
        // Only set the from tag in the response when the
        // incoming request has a from tag.
        String fromTag = ((SIPRequest) this.getRequest()).getFrom().getTag();
        if (fromTag != null && sipResponse.getFromTag() != null && !sipResponse.getFromTag().equals(fromTag)) {
            throw new SipException("From tag of request does not match response from tag");
        } else if (fromTag != null) {
            sipResponse.getFrom().setTag(fromTag);
        } else {
            if (sipStack.isLoggingEnabled())
                sipStack.getStackLogger().logDebug("WARNING -- Null From tag in request!!");
        }
        // or if the state of the dialog needs to be changed.
        if (dialog != null && response.getStatusCode() != 100) {
            dialog.setResponseTags(sipResponse);
            DialogState oldState = dialog.getState();
            dialog.setLastResponse(this, (SIPResponse) response);
            if (oldState == null && dialog.getState() == DialogState.TERMINATED) {
                DialogTerminatedEvent event = new DialogTerminatedEvent(dialog.getSipProvider(), dialog);
                // Provide notification to the listener that the dialog has
                // ended.
                dialog.getSipProvider().handleEvent(event, this);
            }
        } else if (dialog == null && this.getMethod().equals(Request.INVITE) && this.retransmissionAlertEnabled && this.retransmissionAlertTimerTask == null && response.getStatusCode() / 100 == 2) {
            String dialogId = ((SIPResponse) response).getDialogId(true);
            this.retransmissionAlertTimerTask = new RetransmissionAlertTimerTask(dialogId);
            sipStack.retransmissionAlertTransactions.put(dialogId, this);
            sipStack.getTimer().schedule(this.retransmissionAlertTimerTask, 0, SIPTransactionStack.BASE_TIMER_INTERVAL);
        }
        // Send message after possibly inserting the Dialog
        // into the dialog table to avoid a possible race condition.
        this.sendMessage((SIPResponse) response);
        if (dialog != null) {
            dialog.startRetransmitTimer(this, (SIPResponse) response);
        }
    } catch (IOException ex) {
        if (sipStack.isLoggingEnabled())
            sipStack.getStackLogger().logException(ex);
        this.setState(TransactionState.TERMINATED);
        raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);
        throw new SipException(ex.getMessage());
    } catch (java.text.ParseException ex1) {
        if (sipStack.isLoggingEnabled())
            sipStack.getStackLogger().logException(ex1);
        this.setState(TransactionState.TERMINATED);
        throw new SipException(ex1.getMessage());
    }
}
Also used : DialogState(javax.sip.DialogState) IOException(java.io.IOException) ParseException(java.text.ParseException) SipException(javax.sip.SipException) IOException(java.io.IOException) ObjectInUseException(javax.sip.ObjectInUseException) SIPResponse(gov.nist.javax.sip.message.SIPResponse) DialogTerminatedEvent(javax.sip.DialogTerminatedEvent) SIPMessage(gov.nist.javax.sip.message.SIPMessage) ParseException(java.text.ParseException) Expires(gov.nist.javax.sip.header.Expires) SipException(javax.sip.SipException) ParseException(java.text.ParseException)

Aggregations

SIPMessage (gov.nist.javax.sip.message.SIPMessage)7 ParseException (java.text.ParseException)6 SIPResponse (gov.nist.javax.sip.message.SIPResponse)3 IOException (java.io.IOException)3 Via (gov.nist.javax.sip.header.Via)2 SIPRequest (gov.nist.javax.sip.message.SIPRequest)2 SipException (javax.sip.SipException)2 Hop (javax.sip.address.Hop)2 Expires (gov.nist.javax.sip.header.Expires)1 ViaList (gov.nist.javax.sip.header.ViaList)1 HopImpl (gov.nist.javax.sip.stack.HopImpl)1 MessageChannel (gov.nist.javax.sip.stack.MessageChannel)1 SIPServerTransaction (gov.nist.javax.sip.stack.SIPServerTransaction)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 DatagramPacket (java.net.DatagramPacket)1 DialogState (javax.sip.DialogState)1 DialogTerminatedEvent (javax.sip.DialogTerminatedEvent)1 ListeningPoint (javax.sip.ListeningPoint)1 ObjectInUseException (javax.sip.ObjectInUseException)1