Search in sources :

Example 16 with SIPResponse

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

the class SIPDialog method handlePrack.

/**
     * Do the processing necessary for the PRACK
     * 
     * @param prackRequest
     * @return true if this is the first time the tx has seen the prack ( and hence needs to be
     *         passed up to the TU)
     */
public boolean handlePrack(SIPRequest prackRequest) {
    /*
         * The RAck header is sent in a PRACK request to support reliability of provisional
         * responses. It contains two numbers and a method tag. The first number is the value from
         * the RSeq header in the provisional response that is being acknowledged. The next
         * number, and the method, are copied from the CSeq in the response that is being
         * acknowledged. The method name in the RAck header is case sensitive.
         */
    if (!this.isServer()) {
        if (sipStack.isLoggingEnabled())
            sipStack.getStackLogger().logDebug("Dropping Prack -- not a server Dialog");
        return false;
    }
    SIPServerTransaction sipServerTransaction = (SIPServerTransaction) this.getFirstTransaction();
    SIPResponse sipResponse = sipServerTransaction.getReliableProvisionalResponse();
    if (sipResponse == null) {
        if (sipStack.isLoggingEnabled())
            sipStack.getStackLogger().logDebug("Dropping Prack -- ReliableResponse not found");
        return false;
    }
    RAck rack = (RAck) prackRequest.getHeader(RAckHeader.NAME);
    if (rack == null) {
        if (sipStack.isLoggingEnabled())
            sipStack.getStackLogger().logDebug("Dropping Prack -- rack header not found");
        return false;
    }
    CSeq cseq = (CSeq) sipResponse.getCSeq();
    if (!rack.getMethod().equals(cseq.getMethod())) {
        if (sipStack.isLoggingEnabled())
            sipStack.getStackLogger().logDebug("Dropping Prack -- CSeq Header does not match PRACK");
        return false;
    }
    if (rack.getCSeqNumberLong() != cseq.getSeqNumber()) {
        if (sipStack.isLoggingEnabled())
            sipStack.getStackLogger().logDebug("Dropping Prack -- CSeq Header does not match PRACK");
        return false;
    }
    RSeq rseq = (RSeq) sipResponse.getHeader(RSeqHeader.NAME);
    if (rack.getRSequenceNumber() != rseq.getSeqNumber()) {
        if (sipStack.isLoggingEnabled())
            sipStack.getStackLogger().logDebug("Dropping Prack -- RSeq Header does not match PRACK");
        return false;
    }
    return sipServerTransaction.prackRecieved();
}
Also used : SIPResponse(gov.nist.javax.sip.message.SIPResponse) RAck(gov.nist.javax.sip.header.RAck) CSeq(gov.nist.javax.sip.header.CSeq) RSeq(gov.nist.javax.sip.header.RSeq)

Example 17 with SIPResponse

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

the class SIPDialog method createReliableProvisionalResponse.

/*
     * (non-Javadoc)
     * 
     * @see javax.sip.Dialog#createReliableProvisionalResponse(int)
     */
public Response createReliableProvisionalResponse(int statusCode) throws InvalidArgumentException, SipException {
    if (!(firstTransactionIsServerTransaction)) {
        throw new SipException("Not a Server Dialog!");
    }
    /*
         * A UAS MUST NOT attempt to send a 100 (Trying) response reliably. Only provisional
         * responses numbered 101 to 199 may be sent reliably. If the request did not include
         * either a Supported or Require header field indicating this feature, the UAS MUST NOT
         * send the provisional response reliably.
         */
    if (statusCode <= 100 || statusCode > 199)
        throw new InvalidArgumentException("Bad status code ");
    SIPRequest request = this.originalRequest;
    if (!request.getMethod().equals(Request.INVITE))
        throw new SipException("Bad method");
    ListIterator<SIPHeader> list = request.getHeaders(SupportedHeader.NAME);
    if (list == null || !optionPresent(list, "100rel")) {
        list = request.getHeaders(RequireHeader.NAME);
        if (list == null || !optionPresent(list, "100rel")) {
            throw new SipException("No Supported/Require 100rel header in the request");
        }
    }
    SIPResponse response = request.createResponse(statusCode);
    /*
         * The provisional response to be sent reliably is constructed by the UAS core according
         * to the procedures of Section 8.2.6 of RFC 3261. In addition, it MUST contain a Require
         * header field containing the option tag 100rel, and MUST include an RSeq header field.
         * The value of the header field for the first reliable provisional response in a
         * transaction MUST be between 1 and 2**31 - 1. It is RECOMMENDED that it be chosen
         * uniformly in this range. The RSeq numbering space is within a single transaction. This
         * means that provisional responses for different requests MAY use the same values for the
         * RSeq number.
         */
    Require require = new Require();
    try {
        require.setOptionTag("100rel");
    } catch (Exception ex) {
        InternalErrorHandler.handleException(ex);
    }
    response.addHeader(require);
    RSeq rseq = new RSeq();
    /*
         * set an arbitrary sequence number. This is actually set when the response is sent out
         */
    rseq.setSeqNumber(1L);
    /*
         * Copy the record route headers from the request to the response ( Issue 160 ). Note that
         * other 1xx headers do not get their Record Route headers copied over but reliable
         * provisional responses do. See RFC 3262 Table 2.
         */
    RecordRouteList rrl = request.getRecordRouteHeaders();
    if (rrl != null) {
        RecordRouteList rrlclone = (RecordRouteList) rrl.clone();
        response.setHeader(rrlclone);
    }
    return response;
}
Also used : SIPResponse(gov.nist.javax.sip.message.SIPResponse) Require(gov.nist.javax.sip.header.Require) InvalidArgumentException(javax.sip.InvalidArgumentException) SIPHeader(gov.nist.javax.sip.header.SIPHeader) RecordRouteList(gov.nist.javax.sip.header.RecordRouteList) RSeq(gov.nist.javax.sip.header.RSeq) SipException(javax.sip.SipException) SIPRequest(gov.nist.javax.sip.message.SIPRequest) DialogDoesNotExistException(javax.sip.DialogDoesNotExistException) InvalidArgumentException(javax.sip.InvalidArgumentException) ParseException(java.text.ParseException) ObjectInUseException(javax.sip.ObjectInUseException) SipException(javax.sip.SipException) IOException(java.io.IOException) TransactionDoesNotExistException(javax.sip.TransactionDoesNotExistException)

Example 18 with SIPResponse

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

the class SIPServerTransaction method sendMessage.

/**
     * Send a response message through this transactionand onto the client. The response drives
     * the state machine.
     *
     * @param messageToSend Response to process and send.
     */
public void sendMessage(SIPMessage messageToSend) throws IOException {
    try {
        // Message typecast as a response
        SIPResponse transactionResponse;
        // Status code of the response being sent to the client
        int statusCode;
        // Get the status code from the response
        transactionResponse = (SIPResponse) messageToSend;
        statusCode = transactionResponse.getStatusCode();
        try {
            // outgoing via.
            if (this.getOriginalRequest().getTopmostVia().getBranch() != null)
                transactionResponse.getTopmostVia().setBranch(this.getBranch());
            else
                transactionResponse.getTopmostVia().removeParameter(ParameterNames.BRANCH);
            // transaction rsponse.
            if (!this.getOriginalRequest().getTopmostVia().hasPort())
                transactionResponse.getTopmostVia().removePort();
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
        // create the transaction - transaction state does not change.
        if (!transactionResponse.getCSeq().getMethod().equals(getOriginalRequest().getMethod())) {
            sendResponse(transactionResponse);
            return;
        }
        if (getRealState() == TransactionState.TRYING) {
            if (statusCode / 100 == 1) {
                this.setState(TransactionState.PROCEEDING);
            } else if (200 <= statusCode && statusCode <= 699) {
                // check is necessary.
                if (!isInviteTransaction()) {
                    if (!isReliable()) {
                        // Linger in the completed state to catch
                        // retransmissions if the transport is not
                        // reliable.
                        this.setState(TransactionState.COMPLETED);
                        // Note that Timer J is only set for Unreliable
                        // transports -- see Issue 75.
                        /*
                             * From RFC 3261 Section 17.2.2 (non-invite server transaction)
                             *
                             * When the server transaction enters the "Completed" state, it MUST
                             * set Timer J to fire in 64*T1 seconds for unreliable transports, and
                             * zero seconds for reliable transports. While in the "Completed"
                             * state, the server transaction MUST pass the final response to the
                             * transport layer for retransmission whenever a retransmission of the
                             * request is received. Any other final responses passed by the TU to
                             * the server transaction MUST be discarded while in the "Completed"
                             * state. The server transaction remains in this state until Timer J
                             * fires, at which point it MUST transition to the "Terminated" state.
                             */
                        enableTimeoutTimer(TIMER_J);
                    } else {
                        this.setState(TransactionState.TERMINATED);
                    }
                } else {
                    // this is treated the same as as Proceeding.
                    if (statusCode / 100 == 2) {
                        // Status code is 2xx means that the
                        // transaction transitions to TERMINATED
                        // for both Reliable as well as unreliable
                        // transports. Note that the dialog layer
                        // takes care of retransmitting 2xx final
                        // responses.
                        /*
                             * RFC 3261 Section 13.3.1.4 Note, however, that the INVITE server
                             * transaction will be destroyed as soon as it receives this final
                             * response and passes it to the transport. Therefore, it is necessary
                             * to periodically pass the response directly to the transport until
                             * the ACK arrives. The 2xx response is passed to the transport with
                             * an interval that starts at T1 seconds and doubles for each
                             * retransmission until it reaches T2 seconds (T1 and T2 are defined
                             * in Section 17). Response retransmissions cease when an ACK request
                             * for the response is received. This is independent of whatever
                             * transport protocols are used to send the response.
                             */
                        this.disableRetransmissionTimer();
                        this.disableTimeoutTimer();
                        this.collectionTime = TIMER_J;
                        this.setState(TransactionState.TERMINATED);
                        if (this.dialog != null)
                            this.dialog.setRetransmissionTicks();
                    } else {
                        // This an error final response.
                        this.setState(TransactionState.COMPLETED);
                        if (!isReliable()) {
                            /*
                                 * RFC 3261
                                 *
                                 * While in the "Proceeding" state, if the TU passes a response
                                 * with status code from 300 to 699 to the server transaction, the
                                 * response MUST be passed to the transport layer for
                                 * transmission, and the state machine MUST enter the "Completed"
                                 * state. For unreliable transports, timer G is set to fire in T1
                                 * seconds, and is not set to fire for reliable transports.
                                 */
                            enableRetransmissionTimer();
                        }
                        enableTimeoutTimer(TIMER_H);
                    }
                }
            }
        // If the transaction is in the proceeding state,
        } else if (getRealState() == TransactionState.PROCEEDING) {
            if (isInviteTransaction()) {
                // If the response is a failure message,
                if (statusCode / 100 == 2) {
                    // Set up to catch returning ACKs
                    // The transaction lingers in the
                    // terminated state for some time
                    // to catch retransmitted INVITEs
                    this.disableRetransmissionTimer();
                    this.disableTimeoutTimer();
                    this.collectionTime = TIMER_J;
                    this.setState(TransactionState.TERMINATED);
                    if (this.dialog != null)
                        this.dialog.setRetransmissionTicks();
                } else if (300 <= statusCode && statusCode <= 699) {
                    // Set up to catch returning ACKs
                    this.setState(TransactionState.COMPLETED);
                    if (!isReliable()) {
                        /*
                             * While in the "Proceeding" state, if the TU passes a response with
                             * status code from 300 to 699 to the server transaction, the response
                             * MUST be passed to the transport layer for transmission, and the
                             * state machine MUST enter the "Completed" state. For unreliable
                             * transports, timer G is set to fire in T1 seconds, and is not set to
                             * fire for reliable transports.
                             */
                        enableRetransmissionTimer();
                    }
                    enableTimeoutTimer(TIMER_H);
                }
            // If the transaction is not an invite transaction
            // and this is a final response,
            } else if (200 <= statusCode && statusCode <= 699) {
                // This is for Non-invite server transactions.
                // Set up to retransmit this response,
                // or terminate the transaction
                this.setState(TransactionState.COMPLETED);
                if (!isReliable()) {
                    disableRetransmissionTimer();
                    enableTimeoutTimer(TIMER_J);
                } else {
                    this.setState(TransactionState.TERMINATED);
                }
            }
        // If the transaction has already completed,
        } else if (TransactionState.COMPLETED == this.getRealState()) {
            return;
        }
        try {
            // Record the last message sent out.
            if (sipStack.isLoggingEnabled()) {
                sipStack.getStackLogger().logDebug("sendMessage : tx = " + this + " getState = " + this.getState());
            }
            lastResponse = transactionResponse;
            this.sendResponse(transactionResponse);
        } catch (IOException e) {
            this.setState(TransactionState.TERMINATED);
            this.collectionTime = 0;
            throw e;
        }
    } finally {
        this.startTransactionTimer();
    }
}
Also used : SIPResponse(gov.nist.javax.sip.message.SIPResponse) ParseException(java.text.ParseException) IOException(java.io.IOException)

Example 19 with SIPResponse

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

the class DialogFilter method sendCallOrTransactionDoesNotExistResponse.

/**
     * Send a CALL OR TRANSACTION DOES NOT EXIST response.
     * 
     * @param sipRequest
     * @param transaction
     */
private void sendCallOrTransactionDoesNotExistResponse(SIPRequest sipRequest, SIPServerTransaction transaction) {
    SIPResponse sipResponse = sipRequest.createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);
    ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader();
    if (serverHeader != null) {
        sipResponse.setHeader(serverHeader);
    }
    try {
        if (sipRequest.getMethod().equals(Request.INVITE)) {
            sipStack.addTransactionPendingAck(transaction);
        }
        transaction.sendResponse(sipResponse);
        transaction.releaseSem();
    } catch (Exception ex) {
        sipStack.getStackLogger().logError("Problem sending error response", ex);
        transaction.releaseSem();
        sipStack.removeTransaction(transaction);
    }
}
Also used : SIPResponse(gov.nist.javax.sip.message.SIPResponse) ServerHeader(javax.sip.header.ServerHeader) InvalidArgumentException(javax.sip.InvalidArgumentException) SipException(javax.sip.SipException) IOException(java.io.IOException) ObjectInUseException(javax.sip.ObjectInUseException)

Example 20 with SIPResponse

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

the class DialogFilter method processResponse.

/**
     * Process the response.
     * 
     * @exception SIPServerException is thrown when there is an error processing the response
     * @param incomingMessageChannel -- message channel on which the response is received.
     */
public void processResponse(SIPResponse response, MessageChannel incomingMessageChannel, SIPDialog dialog) {
    if (sipStack.isLoggingEnabled()) {
        sipStack.getStackLogger().logDebug("PROCESSING INCOMING RESPONSE" + response.encodeMessage());
    }
    if (listeningPoint == null) {
        if (sipStack.isLoggingEnabled())
            sipStack.getStackLogger().logError("Dropping message: No listening point" + " registered!");
        return;
    }
    if (sipStack.checkBranchId() && !Utils.getInstance().responseBelongsToUs(response)) {
        if (sipStack.isLoggingEnabled()) {
            sipStack.getStackLogger().logError("Dropping response - topmost VIA header does not originate from this stack");
        }
        return;
    }
    SipProviderImpl sipProvider = listeningPoint.getProvider();
    if (sipProvider == null) {
        if (sipStack.isLoggingEnabled()) {
            sipStack.getStackLogger().logError("Dropping message:  no provider");
        }
        return;
    }
    if (sipProvider.getSipListener() == null) {
        if (sipStack.isLoggingEnabled()) {
            sipStack.getStackLogger().logError("No listener -- dropping response!");
        }
        return;
    }
    SIPClientTransaction transaction = (SIPClientTransaction) this.transactionChannel;
    SipStackImpl sipStackImpl = sipProvider.sipStack;
    if (sipStack.isLoggingEnabled()) {
        sipStackImpl.getStackLogger().logDebug("Transaction = " + transaction);
    }
    if (transaction == null) {
        // we cannot drop the response.
        if (dialog != null) {
            if (response.getStatusCode() / 100 != 2) {
                if (sipStack.isLoggingEnabled()) {
                    sipStack.getStackLogger().logDebug("Response is not a final response and dialog is found for response -- dropping response!");
                }
                return;
            } else if (dialog.getState() == DialogState.TERMINATED) {
                if (sipStack.isLoggingEnabled()) {
                    sipStack.getStackLogger().logDebug("Dialog is terminated -- dropping response!");
                }
                return;
            } else {
                boolean ackAlreadySent = false;
                if (dialog.isAckSeen() && dialog.getLastAckSent() != null) {
                    if (dialog.getLastAckSent().getCSeq().getSeqNumber() == response.getCSeq().getSeqNumber()) {
                        // the last ack sent corresponded to this 200
                        ackAlreadySent = true;
                    }
                }
                // 200 retransmission for the final response.
                if (ackAlreadySent && response.getCSeq().getMethod().equals(dialog.getMethod())) {
                    try {
                        // dont pass up the null transaction
                        if (sipStack.isLoggingEnabled()) {
                            sipStack.getStackLogger().logDebug("Retransmission of OK detected: Resending last ACK");
                        }
                        dialog.resendAck();
                        return;
                    } catch (SipException ex) {
                        // What to do here ?? kill the dialog?
                        sipStack.getStackLogger().logError("could not resend ack", ex);
                    }
                }
            }
        }
        if (sipStack.isLoggingEnabled()) {
            sipStack.getStackLogger().logDebug("could not find tx, handling statelessly Dialog =  " + dialog);
        }
        // Pass the response up to the application layer to handle
        // statelessly.
        ResponseEventExt sipEvent = new ResponseEventExt(sipProvider, transaction, dialog, (Response) response);
        if (response.getCSeqHeader().getMethod().equals(Request.INVITE)) {
            SIPClientTransaction forked = this.sipStack.getForkedTransaction(response.getTransactionId());
            sipEvent.setOriginalTransaction(forked);
        }
        sipProvider.handleEvent(sipEvent, transaction);
        return;
    }
    ResponseEventExt responseEvent = null;
    // Here if there is an assigned dialog
    responseEvent = new ResponseEventExt(sipProvider, (ClientTransactionExt) transaction, dialog, (Response) response);
    if (response.getCSeqHeader().getMethod().equals(Request.INVITE)) {
        SIPClientTransaction forked = this.sipStack.getForkedTransaction(response.getTransactionId());
        responseEvent.setOriginalTransaction(forked);
    }
    // Set the Dialog for the response.
    if (dialog != null && response.getStatusCode() != 100) {
        // set the last response for the dialog.
        dialog.setLastResponse(transaction, response);
        transaction.setDialog(dialog, dialog.getDialogId());
    }
    sipProvider.handleEvent(responseEvent, transaction);
}
Also used : SIPClientTransaction(gov.nist.javax.sip.stack.SIPClientTransaction) Response(javax.sip.message.Response) SIPResponse(gov.nist.javax.sip.message.SIPResponse) SipException(javax.sip.SipException)

Aggregations

SIPResponse (gov.nist.javax.sip.message.SIPResponse)23 SipException (javax.sip.SipException)14 IOException (java.io.IOException)12 ObjectInUseException (javax.sip.ObjectInUseException)10 SIPRequest (gov.nist.javax.sip.message.SIPRequest)9 InvalidArgumentException (javax.sip.InvalidArgumentException)8 ParseException (java.text.ParseException)7 ServerHeader (javax.sip.header.ServerHeader)5 RSeq (gov.nist.javax.sip.header.RSeq)4 SIPMessage (gov.nist.javax.sip.message.SIPMessage)3 SIPClientTransaction (gov.nist.javax.sip.stack.SIPClientTransaction)3 SIPServerTransaction (gov.nist.javax.sip.stack.SIPServerTransaction)3 Response (javax.sip.message.Response)3 RAck (gov.nist.javax.sip.header.RAck)2 Require (gov.nist.javax.sip.header.Require)2 RetryAfter (gov.nist.javax.sip.header.RetryAfter)2 Via (gov.nist.javax.sip.header.Via)2 SIPDialog (gov.nist.javax.sip.stack.SIPDialog)2 SIPTransaction (gov.nist.javax.sip.stack.SIPTransaction)2 DialogDoesNotExistException (javax.sip.DialogDoesNotExistException)2