Beispiel #1
0
  /** Done with treatments for call end, now terminate the call */
  public void terminateCall() {
    if (receivedBye == false) {
      if (gotOk == false || (getState() == CallState.INVITED && callAnswered == false)) {

        try {
          Logger.writeFile("Call " + cp + ":  sendCancel");
          sipUtil.sendCancel(clientTransaction);
        } catch (Exception e) {
          Logger.println("sendCancel " + e.getMessage());
        }
      } else {
        /*
         * Try sending a BYE as well.
         * Seems that when we treat SESSION_PROGRESS
         * as OK, sometimes we need to send a CANCEL
         * and other times a BYE.  We'll send both.
         */
        try {
          Logger.writeFile("Call " + cp + ":  sendBye");
          sipUtil.sendBye(clientTransaction);
        } catch (Exception e) {
          Logger.println("Call " + cp + ":  sendBye" + e.getMessage());
        }
      }
    }
  }
Beispiel #2
0
  private void handleReInvite(Request request, ServerTransaction st) {
    Logger.println("Call " + cp + " Re-INVITE\n" + request);

    if (request.getRawContent() == null) {
      Logger.error("Call " + cp + " no SDP in INVITE Request!");
      return;
    }

    String sdpBody = new String(request.getRawContent());

    SdpInfo sdpInfo;

    try {
      sdpInfo = sipUtil.getSdpInfo(sdpBody);
    } catch (ParseException e) {
      Logger.error("Call " + cp + " invalid SDP in re-INVITE Request! " + e.getMessage());
      return;
    }

    MediaInfo mediaInfo = sdpInfo.getMediaInfo();

    InetSocketAddress isa = new InetSocketAddress(sdpInfo.getRemoteHost(), sdpInfo.getRemotePort());

    InetSocketAddress rtcpAddress = sdpInfo.getRtcpAddress();

    setEndpointAddress(
        isa,
        mediaInfo.getPayload(),
        sdpInfo.getTransmitMediaInfo().getPayload(),
        sdpInfo.getTelephoneEventPayload(),
        rtcpAddress);

    isa = callHandler.getReceiveAddress();

    try {
      sipUtil.sendOkWithSdp(request, st, isa, sdpInfo);
    } catch (Exception e) {
      Logger.println("Call " + cp + " Failed to send ok with sdp for re-invite " + e.getMessage());
      return;
    }
  }
Beispiel #3
0
  /*
   * Begin Third-Party Call Control.
   */
  public void initiateCall() throws IOException {
    try {
      try {
        busyTreatment = new TreatmentManager("busy.au", 0);
      } catch (IOException e) {
        Logger.println("Invalid busy treatment:  " + e.getMessage());
      }

      Logger.writeFile("Call " + cp + ":   Begin SIP third party call");

      setState(CallState.INVITED);

      InetSocketAddress isa = callHandler.getReceiveAddress();

      if (isa == null) {
        throw new IOException("can't get receiver socket!");
      }

      // send INVITE to the CallParticipant
      clientTransaction = sipUtil.sendInvite(cp, isa);

      if (clientTransaction == null) {
        Logger.error("Error placing call:  " + cp);
        setState(CallState.ENDED, "Reason='Error placing call'");
        throw new IOException("Error placing call:  " + cp);
      }

      CallIdHeader callIdHeader =
          (CallIdHeader) clientTransaction.getRequest().getHeader(CallIdHeader.NAME);

      sipCallId = callIdHeader.getCallId();

      sipServerCallback = SipServer.getSipServerCallback();
      sipServerCallback.addSipListener(sipCallId, this);
    } catch (java.text.ParseException e) {
      Logger.println("Call " + cp + " Error placing call " + cp + ":  " + e.getMessage());
      setState(CallState.ENDED, "Reason='Error placing call " + cp + " " + e.getMessage() + "'");
      throw new IOException("Error placing call " + cp + " " + e.getMessage());
    } catch (InvalidArgumentException e) {
      Logger.println("Call " + cp + " Error placing call " + cp + ":  " + e.getMessage());
      setState(CallState.ENDED, "Reason='Error placing call " + cp + " " + e.getMessage() + "'");
      throw new IOException("Error placing call " + cp + " " + e.getMessage());
    } catch (SipException e) {
      Logger.println("Call " + cp + " Error placing call " + cp + ":  " + e.getMessage());
      setState(CallState.ENDED, "Reason='Error placing call " + cp + " " + e.getMessage() + "'");
      throw new IOException("Error placing call " + cp + " " + e.getMessage());
    }
  }
Beispiel #4
0
  /**
   * handles a BYE request
   *
   * @param request the request
   * @param transId the transaction Id
   * @throws TransactionDoesNotExistException when the transaction record does not exist.
   */
  private void handleBye(Request request, ServerTransaction st) {
    try {
      CallIdHeader callIdHeader = (CallIdHeader) request.getHeader("Call-Id");

      String sipCallId = callIdHeader.getCallId();

      if (sipCallId.equals(this.sipCallId)) {
        receivedBye = true;

        try {
          Logger.writeFile("Call " + cp + " has hung up.");

          // sipUtil.sendOK(clientTransaction, st, cp);
          sipUtil.sendOK(request, st);
        } catch (Exception e) {
          /*
           * We sometimes get a null ServerTransaction
           */
        }
        cancelRequest("hung up");
        sipServerCallback.removeSipListener(sipCallId);
      } else {
        /*
         * this should not happen since the message has been
         * delegated to this sip agent.
         */
        throw new TransactionDoesNotExistException(
            cp + "BYE request received did not " + "match either party:  " + request);
      }
    } catch (TransactionDoesNotExistException e) {
      Logger.error("Call " + cp + " Transaction not found " + e.getMessage());
    } catch (SipException e) {
      Logger.exception("Call " + cp + " SIP Stack error", e);
      cancelRequest("handleBye:  SIP Stack error " + e.getMessage());
    } catch (Exception e) {
      Logger.exception("Call " + cp + " Unknown error ", e);
      cancelRequest("handleBye:  SIP Stack error " + e.getMessage());
    }
  }
Beispiel #5
0
  /**
   * handles the INVITED state.
   *
   * @param response the response
   * @param clientTransaction the client transaction
   * @throws SipException SIP stack related error
   */
  private void handleCallParticipantInvited(Response response, ClientTransaction clientTransaction)
      throws ParseException, SipException, InvalidArgumentException {
    FromHeader fromHeader = (FromHeader) response.getHeader(FromHeader.NAME);

    String displayName = fromHeader.getAddress().getDisplayName();

    int statusCode = response.getStatusCode();

    Logger.println(
        "handleCallParticipantInvited "
            + cp
            + " status "
            + statusCode
            + " "
            + response.getReasonPhrase());
    Logger.println("handleCallParticipantInvited , displayname " + displayName);

    CallIdHeader callIdHeader = (CallIdHeader) response.getHeader(CallIdHeader.NAME);

    if (sipCallId.equals(callIdHeader.getCallId())
        && displayName.equals(cp.getDisplayName())
        && (statusCode == Response.OK || statusCode == Response.SESSION_PROGRESS)
        && ((CSeqHeader) response.getHeader(CSeqHeader.NAME)).getMethod().equals(Request.INVITE)) {
      if (statusCode == Response.SESSION_PROGRESS) {
        /*
         * For some calls, we never get an OK.  Instead we just get
         * SESSION_PROGRESS.  In order to handle these calls, we treat
         * SESSION_PROGRESS as OK.  If an OK arrives later, we'll
         * send an ACK.  This flag allows us to enable or
         * disable this workaround for each call.
         *
         * The problem with always treating SESSION_PROGRESS as OK
         * is that in a conference everybody will hear the ringing sound
         * which the remote call sends until the call is actually answered.
         * This can be avoided if joinConfirmation is specified.
         * The other problem is that if we treat SESSION_PROGRESS
         * as though the call has been answered, then we'll start
         * playing the treatment before a person really answers to
         * hear the treatment.
         */

        if (cp.getHandleSessionProgress() == false) {
          Logger.writeFile("Call " + cp + " Ignoring SESSION_PROGRESS");
          return;
        }

        Logger.writeFile("Call " + cp + " Treating SESSION_PROGRESS as OK");
      }

      if (response.getRawContent() == null) {
        Logger.error("Call " + cp + " no SDP in OK Response!");
        cancelRequest("SIP error!  no SDP in OK Response!");
        return;
      }

      this.clientTransaction = clientTransaction;

      if (statusCode == Response.OK) {
        gotOk = true;
        Logger.writeFile("Call " + cp + " Got OK, call answered\n" + response);
      }

      ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME);

      /*
       * We got an OK response.
       *
       * send an ACK back to the CallParticipant
       */

      if (statusCode == Response.OK) {
        sipUtil.sendAck(clientTransaction);
        ackSent = true;
      }

      if (callAnswered) {
        Logger.writeFile("Call " + cp + " done processing OK");
        return;
      }

      /*
       * Remember the IP and port of where to send data to
       * the CallParticipant.
       */

      sdpBody = new String(response.getRawContent());

      SdpInfo sdpInfo;

      try {
        sdpInfo = sipUtil.getSdpInfo(sdpBody, false);

      } catch (ParseException e) {

        Logger.error("Call " + cp + " Invalid SDP in OK Response! " + e.getMessage());
        cancelRequest("SIP error!  Invalid SDP in OK Response!");
        return;
      }

      MediaInfo mediaInfo = sdpInfo.getMediaInfo();
      InetSocketAddress isa =
          new InetSocketAddress(sdpInfo.getRemoteHost(), sdpInfo.getRemotePort());
      InetSocketAddress rtcpAddress = sdpInfo.getRtcpAddress();
      setEndpointAddress(
          isa,
          mediaInfo.getPayload(),
          sdpInfo.getTransmitMediaInfo().getPayload(),
          sdpInfo.getTelephoneEventPayload(),
          rtcpAddress);

      /*
       * The CallParticipant has answered.
       * If join confirmation is required, we remain in the
       * INVITED state.  We set the callAnswered flag so that
       * if the join confirmation times out we know to
       * send a BYE rather than a CANCEL.
       */

      callAnswered = true;

      if (cp.getJoinConfirmationTimeout() == 0) {
        setState(CallState.ANSWERED);
      }

      /*
       * Start treatment if any and wait for it to finish.
       * When the treatment finishes, notification will
       * be delivered to our parent which will indicate
       * we're ready for the conference.
       *
       * If there's no treatment to be played, we're ready now
       * unless we're waiting for join confirmation..
       */
      initializeCallAnsweredTreatment();

      if (callAnsweredTreatment != null) {
        startCallAnsweredTreatment();
      } else {

        if (cp.getJoinConfirmationTimeout() == 0) {
          setState(CallState.ESTABLISHED);
        }
      }

    } else {
      Logger.writeFile("Call " + cp + " Ignoring response: " + response.getReasonPhrase());

      if (Logger.logLevel >= Logger.LOG_SIP) {
        Logger.println("Call " + cp + " Response: " + response);
      }
    }
  }
Beispiel #6
0
  public synchronized void processResponse(ResponseEvent responseReceivedEvent) {

    try {
      Response response = (Response) responseReceivedEvent.getResponse();
      ClientTransaction clientTransaction = responseReceivedEvent.getClientTransaction();

      int statusCode = response.getStatusCode();

      FromHeader fromHeader = (FromHeader) response.getHeader(FromHeader.NAME);

      String displayName = fromHeader.getAddress().getDisplayName();

      if (Logger.logLevel >= Logger.LOG_SIP) {
        Logger.println(
            "Response:  statusCode "
                + statusCode
                + " state "
                + getCallState()
                + " fromHeader "
                + displayName
                + " call participant "
                + cp.getName());
      }

      if (reasonCallTerminated != null) {
        /*
         * Ignore OK and Request Terminated.
         * XXX what's the symbol for 487?
         */
        if (statusCode != Response.OK && statusCode != 487) {
          if (Logger.logLevel >= Logger.LOG_SIP) {
            Logger.println("Call " + cp + ":  request cancelled, ignoring response");
          }
        }

        CallIdHeader callIdHeader = (CallIdHeader) response.getHeader("Call-Id");

        String sipCallId = callIdHeader.getCallId();
        sipServerCallback.removeSipListener(sipCallId);
        return;
      }

      /*
       * Some type of global failure that prevents the
       * CallParticipant from being contacted, report failure.
       */
      if (forceGatewayError) {
        statusCode = 500;
        forceGatewayError = false;
      }

      if (statusCode >= 500 && getState() == CallState.INVITED) {
        Logger.error(
            "Call " + cp + " gateway error:  " + statusCode + " " + response.getReasonPhrase());
        cancelRequest("gateway error: " + statusCode + " " + response.getReasonPhrase());
        return;

      } else if (statusCode == Response.PROXY_AUTHENTICATION_REQUIRED
          || statusCode == Response.UNAUTHORIZED) {

        if (cp.getProxyCredentials() != null) {
          try {
            SipServer.handleChallenge(response, clientTransaction, cp.getProxyCredentials())
                .sendRequest();

          } catch (Exception e) {

            Logger.println("Proxy authentification failed  " + e);
          }
        }
        return;

      } else if (statusCode >= 400) {

        // if we get a busy or an unknown error, play busy.
        Logger.println("Call " + cp + " got status code :" + statusCode);

        cp.setCallEndTreatment(null);
        cp.setConferenceJoinTreatment(null);
        cp.setConferenceLeaveTreatment(null);

        /*
         * play busy treatment, but deallocate any resources
         * held up by ringBack first, if any.
         */
        // stopCallAnsweredTreatment();

        if (statusCode == Response.BUSY_HERE) {
          try {
            if (busyTreatment != null) {
              addTreatment(busyTreatment);
              // busyTreatment.waitForTreatment();
            } else {
              Logger.println("Unable to play busy treatment!!!");
            }
          } catch (Exception e) {
            Logger.error("can't start busy treatment!" + sdpBody);
          }

          CallEvent callEvent = new CallEvent(CallEvent.BUSY_HERE);

          callEvent.setInfo(response.getReasonPhrase());

          sendCallEventNotification(callEvent);
        }

        // sipUtil.sendBye(clientTransaction);
        cancelRequest(response.getReasonPhrase());
        return;
      }

      /* state machine */
      switch (getState()) {
          /*
           * CallParticipant picked up, send treatment if any,
           * and wait for it to finish.
           */
        case CallState.INVITED:
          if (rejectCall) {
            Logger.error(
                "Call " + cp + " gateway error:  " + statusCode + " " + response.getReasonPhrase());

            cancelRequest("gateway error: " + statusCode + " " + response.getReasonPhrase());
            return;
          }

          handleCallParticipantInvited(response, clientTransaction);
          break;

          /*
           * Call established, the ACK needs to be resent.
           * According to Ranga, this is done by the NIST SIP Stack.
           */
        case CallState.ESTABLISHED:
          if (statusCode == Response.OK) {
            gotOk = true;

            Logger.writeFile("Call " + cp + " Got OK, ESTABLISHED");

            if (ackSent == false) {
              sipUtil.sendAck(clientTransaction);
              ackSent = true;
            }
          }
          break;

        case CallState.ENDED:
          break; // ignore the response

        default:
          Logger.error("Process Response bad state " + getState() + "\n" + response);
      }
    } catch (SipException e) {
      Logger.exception("Call " + cp + " SIP Stack error ", e);

      cancelRequest("processResponse:  SIP Stack error " + e.getMessage());
    } catch (Exception e) {
      Logger.exception("processResponse:  " + cp, e);

      cancelRequest("processResponse:  SIP Stack error " + e.getMessage());
    }
  }