Пример #1
0
  /**
   * @param response
   * @throws IOException
   */
  public static void forwardResponse(final SipServletResponse response) throws IOException {
    if (logger.isInfoEnabled()) {
      logger.info(String.format("B2BUA: Got response: \n %s", response));
    }
    CallDetailRecordsDao records = daoManager.getCallDetailRecordsDao();

    // container handles CANCEL related responses no need to forward them
    if (response.getStatus() == 487
        || (response.getStatus() == 200 && response.getMethod().equalsIgnoreCase("CANCEL"))) {
      if (logger.isDebugEnabled()) {
        logger.debug("response to CANCEL not forwarding");
      }
      // Update CallDetailRecord
      SipServletRequest request =
          (SipServletRequest) getLinkedSession(response).getAttribute(B2BUA_LAST_REQUEST);
      CallDetailRecord callRecord =
          records.getCallDetailRecord((Sid) request.getSession().getAttribute(CDR_SID));

      if (callRecord != null) {
        logger.info("CDR found! Updating");
        callRecord = callRecord.setStatus(CallStateChanged.State.CANCELED.name());
        final DateTime now = DateTime.now();
        callRecord = callRecord.setEndTime(now);
        final int seconds =
            (int) (DateTime.now().getMillis() - callRecord.getStartTime().getMillis()) / 1000;
        callRecord = callRecord.setDuration(seconds);
        records.updateCallDetailRecord(callRecord);
      }
      return;
    }
    // forward the response
    response.getSession().setAttribute(B2BUA_LAST_RESPONSE, response);
    SipServletRequest request =
        (SipServletRequest) getLinkedSession(response).getAttribute(B2BUA_LAST_REQUEST);
    SipServletResponse resp = request.createResponse(response.getStatus());
    CallDetailRecord callRecord =
        records.getCallDetailRecord((Sid) request.getSession().getAttribute(CDR_SID));

    if (response.getContent() != null) {
      final byte[] sdp = response.getRawContent();
      String offer = null;
      if (response.getContentType().equalsIgnoreCase("application/sdp")) {
        // Issue 306: https://telestax.atlassian.net/browse/RESTCOMM-306
        Registration registration =
            daoManager.getRegistrationsDao().getRegistration(callRecord.getTo());
        final String externalIp = registration.getLocation().split(":")[1].split("@")[1];
        try {
          logger.debug("Got original address from Registration :" + externalIp);
          offer = patch(sdp, externalIp);
        } catch (SdpException e) {
          logger.error("Unexpected exception while patching sdp ", e);
        }
        if (offer != null) {
          resp.setContent(offer, response.getContentType());
        } else {
          resp.setContent(sdp, response.getContentType());
        }
      }
    }
    resp.send();

    //        CallDetailRecord callRecord = records.getCallDetailRecord((Sid)
    // request.getSession().getAttribute(CDR_SID));
    if (callRecord != null) {
      logger.info("CDR found! Updating");
      if (!request.getMethod().equalsIgnoreCase("BYE")) {
        if (response.getStatus() == 100 || response.getStatus() == 180) {
          callRecord = callRecord.setStatus(CallStateChanged.State.RINGING.name());
        } else if (response.getStatus() == 200 || response.getStatus() == 202) {
          callRecord = callRecord.setStatus(CallStateChanged.State.IN_PROGRESS.name());
          callRecord = callRecord.setAnsweredBy(((SipURI) response.getTo().getURI()).getUser());
          final DateTime now = DateTime.now();
          callRecord = callRecord.setStartTime(now);

        } else if (response.getStatus() == 486 || response.getStatus() == 600) {
          callRecord = callRecord.setStatus(CallStateChanged.State.BUSY.name());
        } else if (response.getStatus() > 400) {
          callRecord = callRecord.setStatus(CallStateChanged.State.FAILED.name());
        }
      } else {
        callRecord = callRecord.setStatus(CallStateChanged.State.COMPLETED.name());
        final DateTime now = DateTime.now();
        callRecord = callRecord.setEndTime(now);
        final int seconds =
            (int) ((DateTime.now().getMillis() - callRecord.getStartTime().getMillis()) / 1000);
        callRecord = callRecord.setDuration(seconds);
      }

      records.updateCallDetailRecord(callRecord);
    }
  }
Пример #2
0
  /**
   * @param request
   * @param client
   * @param toClient
   * @throws IOException
   */
  public static boolean redirectToB2BUA(
      final SipServletRequest request,
      final Client client,
      Client toClient,
      DaoManager storage,
      SipFactory sipFactory)
      throws IOException {
    request.getSession().setAttribute("lastRequest", request);
    if (logger.isInfoEnabled()) {
      logger.info("B2BUA (p2p proxy): Got request:\n" + request.getMethod());
      logger.info(
          String.format(
              "B2BUA: Proxying a session between %s and %s", client.getUri(), toClient.getUri()));
    }

    if (daoManager == null) {
      daoManager = storage;
    }

    String user = ((SipURI) request.getTo().getURI()).getUser();

    final RegistrationsDao registrations = daoManager.getRegistrationsDao();
    final Registration registration = registrations.getRegistration(user);
    if (registration != null) {
      final String location = registration.getLocation();
      SipURI to;
      SipURI from;
      try {
        to = (SipURI) sipFactory.createURI(location);
        from =
            (SipURI)
                sipFactory.createURI(
                    (registrations.getRegistration(client.getLogin())).getLocation());

        final SipSession incomingSession = request.getSession();
        // create and send the outgoing invite and do the session linking
        incomingSession.setAttribute(B2BUA_LAST_REQUEST, request);
        SipServletRequest outRequest =
            sipFactory.createRequest(
                request.getApplicationSession(),
                request.getMethod(),
                request.getFrom().getURI(),
                request.getTo().getURI());
        outRequest.setRequestURI(to);

        if (request.getContent() != null) {
          final byte[] sdp = request.getRawContent();
          String offer = null;
          if (request.getContentType().equalsIgnoreCase("application/sdp")) {
            // Issue 308: https://telestax.atlassian.net/browse/RESTCOMM-308
            String externalIp = request.getInitialRemoteAddr();
            // Issue 306: https://telestax.atlassian.net/browse/RESTCOMM-306
            final String initialIpBeforeLB = request.getHeader("X-Sip-Balancer-InitialRemoteAddr");
            try {
              if (initialIpBeforeLB != null && !initialIpBeforeLB.isEmpty()) {
                offer = patch(sdp, initialIpBeforeLB);
              } else {
                offer = patch(sdp, externalIp);
              }
            } catch (SdpException e) {
              logger.error("Unexpected exception while patching sdp ", e);
            }
          }
          if (offer != null) {
            outRequest.setContent(offer, request.getContentType());
          } else {
            outRequest.setContent(sdp, request.getContentType());
          }
        }

        final SipSession outgoingSession = outRequest.getSession();
        if (request.isInitial()) {
          incomingSession.setAttribute(B2BUA_LINKED_SESSION, outgoingSession);
          outgoingSession.setAttribute(B2BUA_LINKED_SESSION, incomingSession);
        }
        outgoingSession.setAttribute(B2BUA_LAST_REQUEST, outRequest);
        request.createResponse(100).send();
        // Issue #307: https://telestax.atlassian.net/browse/RESTCOMM-307
        request.getSession().setAttribute("toInetUri", to);
        outRequest.send();
        outRequest.getSession().setAttribute("fromInetUri", from);

        final CallDetailRecord.Builder builder = CallDetailRecord.builder();
        builder.setSid(Sid.generate(Sid.Type.CALL));
        builder.setDateCreated(DateTime.now());
        builder.setAccountSid(client.getAccountSid());
        builder.setTo(toClient.getFriendlyName());
        builder.setCallerName(client.getFriendlyName());
        builder.setFrom(client.getFriendlyName());
        // builder.setForwardedFrom(callInfo.forwardedFrom());
        // builder.setPhoneNumberSid(phoneId);
        builder.setStatus(CallStateChanged.State.QUEUED.name());
        builder.setDirection("Client-To-Client");
        builder.setApiVersion(client.getApiVersion());
        builder.setPrice(new BigDecimal("0.00"));
        // TODO implement currency property to be read from Configuration
        builder.setPriceUnit(Currency.getInstance("USD"));
        final StringBuilder buffer = new StringBuilder();
        buffer.append("/").append(client.getApiVersion()).append("/Accounts/");
        buffer.append(client.getAccountSid().toString()).append("/Calls/");
        buffer.append(client.getSid().toString());
        final URI uri = URI.create(buffer.toString());
        builder.setUri(uri);

        CallDetailRecordsDao records = daoManager.getCallDetailRecordsDao();
        CallDetailRecord callRecord = builder.build();
        records.addCallDetailRecord(callRecord);

        incomingSession.setAttribute(CDR_SID, callRecord.getSid());
        outgoingSession.setAttribute(CDR_SID, callRecord.getSid());

        return true; // successfully proxied the SIP request between two registered clients
      } catch (ServletParseException badUriEx) {
        if (logger.isInfoEnabled()) {
          logger.info(
              String.format("B2BUA: Error parsing Client Contact URI: %s", location), badUriEx);
        }
      }
    }
    return false;
  }
Пример #3
0
  // Issue 139: https://bitbucket.org/telestax/telscale-restcomm/issue/139
  @SuppressWarnings("unchecked")
  protected Response updateCall(
      final String sid,
      final String callSid,
      final MultivaluedMap<String, String> data,
      final MediaType responseType) {
    final Sid accountSid = new Sid(sid);
    try {
      secure(daos.getAccountsDao().getAccount(accountSid), "RestComm:Modify:Calls");
    } catch (final AuthorizationException exception) {
      return status(UNAUTHORIZED).build();
    }

    final Timeout expires = new Timeout(Duration.create(60, TimeUnit.SECONDS));

    final CallDetailRecordsDao dao = daos.getCallDetailRecordsDao();
    final CallDetailRecord cdr = dao.getCallDetailRecord(new Sid(callSid));

    final String url = data.getFirst("Url");
    String method = data.getFirst("Method");
    final String status = data.getFirst("Status");
    final String fallBackUrl = data.getFirst("FallbackUrl");
    String fallBackMethod = data.getFirst("FallbackMethod");
    final String statusCallBack = data.getFirst("StatusCallback");
    String statusCallbackMethod = data.getFirst("StatusCallbackMethod");
    // Restcomm-  Move connected call leg (if exists) to the new URL
    Boolean moveConnectedCallLeg = Boolean.valueOf(data.getFirst("MoveConnectedCallLeg"));

    String callPath = null;
    final ActorRef call;
    final CallInfo callInfo;

    try {
      callPath = cdr.getCallPath();
      Future<Object> future = (Future<Object>) ask(callManager, new GetCall(callPath), expires);
      call = (ActorRef) Await.result(future, Duration.create(10, TimeUnit.SECONDS));

      future = (Future<Object>) ask(call, new GetCallInfo(), expires);
      CallResponse<CallInfo> response =
          (CallResponse<CallInfo>) Await.result(future, Duration.create(10, TimeUnit.SECONDS));
      callInfo = response.get();
    } catch (Exception exception) {
      return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build();
    }

    if (method == null) method = "POST";

    if (url != null && status != null) {
      // Throw exception. We can either redirect a running call using Url or change the state of a
      // Call with Status
      final String errorMessage =
          "You can either redirect a running call using \"Url\" or change the state of a Call with \"Status\"";
      return status(javax.ws.rs.core.Response.Status.CONFLICT).entity(errorMessage).build();
    }

    // Modify state of a call
    if (status != null) {
      if (status.equalsIgnoreCase("canceled")) {
        if (callInfo.state().name().equalsIgnoreCase("queued")
            || callInfo.state().name().equalsIgnoreCase("ringing")) {
          if (call != null) {
            call.tell(new Hangup(), null);
          }
        } else {
          // Do Nothing. We can only cancel Queued or Ringing calls
        }
      }

      if (status.equalsIgnoreCase("completed")) {
        // Specifying "completed" will attempt to hang up a call even if it's already in progress.
        if (call != null) {
          call.tell(new Hangup(), null);
        }
      }
    }

    if (url != null && call != null) {
      try {
        final String version = getApiVersion(data);
        final URI uri = (new URL(url)).toURI();

        URI fallbackUri = (fallBackUrl != null) ? (new URL(fallBackUrl)).toURI() : null;
        fallBackMethod = (fallBackMethod == null) ? "POST" : fallBackMethod;
        URI callbackUri = (statusCallBack != null) ? (new URL(statusCallBack)).toURI() : null;
        statusCallbackMethod = (statusCallbackMethod == null) ? "POST" : statusCallbackMethod;

        final UpdateCallScript update =
            new UpdateCallScript(
                call,
                accountSid,
                version,
                uri,
                method,
                fallbackUri,
                fallBackMethod,
                callbackUri,
                statusCallbackMethod,
                moveConnectedCallLeg);
        callManager.tell(update, null);
      } catch (Exception exception) {
        return status(INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build();
      }
    }

    if (APPLICATION_JSON_TYPE == responseType) {
      return ok(gson.toJson(cdr), APPLICATION_JSON).build();
    } else if (APPLICATION_XML_TYPE == responseType) {
      return ok(xstream.toXML(new RestCommResponse(cdr)), APPLICATION_XML).build();
    } else {
      return null;
    }
  }