예제 #1
0
void
SIPCall::hangup(int reason)
{
    // Stop all RTP streams
    stopAllMedia();

    if (not inv or not inv->dlg) {
        removeCall();
        throw VoipLinkException("No invite session for this call");
    }

    pjsip_route_hdr *route = inv->dlg->route_set.next;
    while (route and route != &inv->dlg->route_set) {
        char buf[1024];
        int printed = pjsip_hdr_print_on(route, buf, sizeof(buf));

        if (printed >= 0) {
            buf[printed] = '\0';
            RING_DBG("[call:%s] Route header %s", getCallId().c_str(), buf);
        }

        route = route->next;
    }

    const int status = reason ? reason :
                       inv->state <= PJSIP_INV_STATE_EARLY and inv->role != PJSIP_ROLE_UAC ?
                       PJSIP_SC_CALL_TSX_DOES_NOT_EXIST :
                       inv->state >= PJSIP_INV_STATE_DISCONNECTED ? PJSIP_SC_DECLINE : 0;

    // Notify the peer
    terminateSipSession(status);

    setState(Call::ConnectionState::DISCONNECTED, reason);
    removeCall();
}
예제 #2
0
bool
SIPCall::startIce()
{
    if (not iceTransport_ or iceTransport_->isFailed())
        return false;
    if (iceTransport_->isStarted()) {
        RING_DBG("[call:%s] ICE already started", getCallId().c_str());
        return true;
    }
    auto rem_ice_attrs = sdp_->getIceAttributes();
    if (rem_ice_attrs.ufrag.empty() or rem_ice_attrs.pwd.empty()) {
        RING_ERR("[call:%s] ICE empty attributes", getCallId().c_str());
        return false;
    }
    return iceTransport_->start(rem_ice_attrs, getAllRemoteCandidates());
}
예제 #3
0
void
SIPCall::sendSIPInfo(const char *const body, const char *const subtype)
{
    if (not inv or not inv->dlg)
        throw VoipLinkException("Couldn't get invite dialog");

    pj_str_t methodName = CONST_PJ_STR("INFO");
    pjsip_method method;
    pjsip_method_init_np(&method, &methodName);

    /* Create request message. */
    pjsip_tx_data *tdata;

    if (pjsip_dlg_create_request(inv->dlg, &method, -1, &tdata) != PJ_SUCCESS) {
        RING_ERR("[call:%s] Could not create dialog", getCallId().c_str());
        return;
    }

    /* Create "application/<subtype>" message body. */
    pj_str_t content;
    pj_cstr(&content, body);
    const pj_str_t type = CONST_PJ_STR("application");
    pj_str_t pj_subtype;
    pj_cstr(&pj_subtype, subtype);
    tdata->msg->body = pjsip_msg_body_create(tdata->pool, &type, &pj_subtype, &content);

    if (tdata->msg->body == NULL)
        pjsip_tx_data_dec_ref(tdata);
    else
        pjsip_dlg_send_request(inv->dlg, tdata, getSIPVoIPLink()->getModId(), NULL);
}
예제 #4
0
파일: Connection.cpp 프로젝트: ciuc/sipxecs
void Connection::fireSipXEvent(SIPX_CALLSTATE_EVENT eventCode, SIPX_CALLSTATE_CAUSE causeCode, void* pEventData)
{
    UtlString callId ;
    UtlString remoteAddress ;
    SipSession session ;
    UtlBoolean bDuplicateAudio =
            (   eventCode == CALLSTATE_AUDIO_EVENT
             && causeCode == m_eLastAudioMinor) ? TRUE : FALSE;

    // Avoid sending duplicate events
    if ((   (eventCode != m_eLastMajor)
         || (causeCode != m_eLastMinor))
        && validStateTransition(m_eLastMajor, eventCode)
        && !bDuplicateAudio)
    {
        if (eventCode != CALLSTATE_AUDIO_EVENT)
        {
            m_eLastMajor = eventCode;
            m_eLastMinor = causeCode;
        }
        else
        {
            m_eLastAudioMajor = eventCode;
            m_eLastAudioMinor = causeCode;
        }

        getCallId(&callId) ;
        getRemoteAddress(&remoteAddress);
        getSession(session) ;

        TapiMgr::getInstance().fireCallEvent(mpCallManager, callId.data(), &session, remoteAddress.data(), eventCode, causeCode, pEventData) ;
    }
}
예제 #5
0
void SIPTest::testSimpleIncomingIpCall()
{
    pthread_t thethread;

    // command to be executed by the thread, user agent client which initiate a call and hangup
    std::string command("sipp -sn uac 127.0.0.1 -i 127.0.0.1 -p 5062 -m 1i -bg");

    int rc = pthread_create(&thethread, NULL, sippThread, &command);

    if (rc)
        std::cout << "SIPTest: RING_ERR; return code from pthread_create()" << std::endl;

    // sleep a while to make sure that sipp insdtance is initialized and dring received
    // the incoming invite.
    sleep(2);

    CPPUNIT_ASSERT(Manager::instance().callFactory.callCount<SIPCall>() == 1);

    // Answer this call
    const auto& calls = Manager::instance().callFactory.getAllCalls<SIPCall>();
    const auto call = *calls.cbegin();
    CPPUNIT_ASSERT(Manager::instance().answerCall(call->getCallId()));

    sleep(1);

    rc = pthread_join(thethread, NULL);

    if (rc)
        std::cout << "SIPTest: RING_ERR; return code from pthread_join(): " << rc << std::endl;
    else
        std::cout << "SIPTest: completed join with thread" << std::endl;
}
 /*
  * Messages are in JSON, formatted like:
  * {
  *   "id": 1,
  *   "method": "Debugger.removeBreakpoint",
  *   "params": { "removeBreakpoint": "xyz" }
  * }
  */
 void route(std::string message) {
   try {
     auto json = parseJson(message);
     auto callId = getCallId(json);
     receive(callId, std::move(message), std::move(json));
   } catch (const InspectorException& e) {
     channel_->sendMessage(e.error());
   }
 }
예제 #7
0
void
SIPCall::answer()
{
    auto& account = getSIPAccount();

    if (not inv)
        throw VoipLinkException("No invite session for this call");

    if (!inv->neg) {
        RING_WARN("[call:%s] Negotiator is NULL, we've received an INVITE without an SDP",
                  getCallId().c_str());
        pjmedia_sdp_session *dummy = 0;
        getSIPVoIPLink()->createSDPOffer(inv.get(), &dummy);

        if (account.isStunEnabled())
            updateSDPFromSTUN();
    }

    pj_str_t contact(account.getContactHeader(transport_ ? transport_->get() : nullptr));
    setContactHeader(&contact);

    pjsip_tx_data *tdata;
    if (!inv->last_answer)
        throw std::runtime_error("Should only be called for initial answer");

    // answer with SDP if no SDP was given in initial invite (i.e. inv->neg is NULL)
    if (pjsip_inv_answer(inv.get(), PJSIP_SC_OK, NULL, !inv->neg ? sdp_->getLocalSdpSession() : NULL, &tdata) != PJ_SUCCESS)
        throw std::runtime_error("Could not init invite request answer (200 OK)");

    // contactStr must stay in scope as long as tdata
    if (contactHeader_.slen) {
        RING_DBG("[call:%s] Answering with contact header: %.*s",
                 getCallId().c_str(), (int)contactHeader_.slen, contactHeader_.ptr);
        sip_utils::addContactHeader(&contactHeader_, tdata);
    }

    if (pjsip_inv_send_msg(inv.get(), tdata) != PJ_SUCCESS) {
        inv.reset();
        throw std::runtime_error("Could not send invite request answer (200 OK)");
    }

    setState(CallState::ACTIVE, ConnectionState::CONNECTED);
}
예제 #8
0
int
SIPCall::SIPSessionReinvite()
{
    // Do nothing if no invitation processed yet
    if (not inv or inv->invite_tsx)
        return PJ_SUCCESS;

    RING_DBG("[call:%s] Processing reINVITE (state=%s)", getCallId().c_str(),
             pjsip_inv_state_name(inv->state));

    // Generate new ports to receive the new media stream
    // LibAV doesn't discriminate SSRCs and will be confused about Seq changes on a given port
    generateMediaPorts();
    sdp_->clearIce();
    auto& acc = getSIPAccount();
    if (not sdp_->createOffer(acc.getActiveAccountCodecInfoList(MEDIA_AUDIO),
                              acc.getActiveAccountCodecInfoList(acc.isVideoEnabled() ? MEDIA_VIDEO : MEDIA_NONE),
                              acc.getSrtpKeyExchange(),
                              getState() == CallState::HOLD))
        return !PJ_SUCCESS;

    if (initIceTransport(true))
        setupLocalSDPFromIce();

    pjsip_tx_data* tdata;
    auto local_sdp = sdp_->getLocalSdpSession();
    auto result = pjsip_inv_reinvite(inv.get(), nullptr, local_sdp, &tdata);
    if (result == PJ_SUCCESS) {
        if (!tdata)
            return PJ_SUCCESS;
        result = pjsip_inv_send_msg(inv.get(), tdata);
        if (result == PJ_SUCCESS)
            return PJ_SUCCESS;
        RING_ERR("[call:%s] Failed to send REINVITE msg (pjsip: %s)", getCallId().c_str(),
                 sip_utils::sip_strerror(result).c_str());
        // Canceling internals without sending (anyways the send has just failed!)
        pjsip_inv_cancel_reinvite(inv.get(), &tdata);
    } else
        RING_ERR("[call:%s] Failed to create REINVITE msg (pjsip: %s)", getCallId().c_str(),
                 sip_utils::sip_strerror(result).c_str());

    return !PJ_SUCCESS;
}
void DialingSipConnectionState::handleStateEntry(StateEnum previousState, const StateTransitionMemory* pTransitionMemory)
{
   StateTransitionEventDispatcher eventDispatcher(m_rSipConnectionEventSink, pTransitionMemory);
   eventDispatcher.dispatchEvent(getCurrentState());

   notifyConnectionStateObservers();

   OsSysLog::add(FAC_CP, PRI_DEBUG, "Entry dialing connection state from state: %d, sip call-id: %s\r\n",
      (int)previousState, getCallId().data());
}
예제 #10
0
void
SIPCall::setupLocalSDPFromIce()
{
    if (not iceTransport_) {
        RING_WARN("[call:%s] null icetransport, no attributes added to SDP", getCallId().c_str());
        return;
    }

    if (waitForIceInitialization(DEFAULT_ICE_INIT_TIMEOUT) <= 0) {
        RING_ERR("[call:%s] Local ICE init failed", getCallId().c_str());
        return;
    }

    sdp_->addIceAttributes(iceTransport_->getLocalAttributes());

    // Add video and audio channels
    sdp_->addIceCandidates(SDP_AUDIO_MEDIA_ID, iceTransport_->getLocalCandidates(ICE_AUDIO_RTP_COMPID));
    sdp_->addIceCandidates(SDP_AUDIO_MEDIA_ID, iceTransport_->getLocalCandidates(ICE_AUDIO_RTCP_COMPID));
#ifdef RING_VIDEO
    sdp_->addIceCandidates(SDP_VIDEO_MEDIA_ID, iceTransport_->getLocalCandidates(ICE_VIDEO_RTP_COMPID));
    sdp_->addIceCandidates(SDP_VIDEO_MEDIA_ID, iceTransport_->getLocalCandidates(ICE_VIDEO_RTCP_COMPID));
#endif
}
예제 #11
0
void
SIPCall::terminateSipSession(int status)
{
    if (inv and inv->state != PJSIP_INV_STATE_DISCONNECTED) {
        RING_DBG("[call:%s] Terminate SIP session", getCallId().c_str());

        pjsip_tx_data* tdata = nullptr;
        auto ret = pjsip_inv_end_session(inv.get(), status, nullptr, &tdata);
        if (ret == PJ_SUCCESS) {
            if (tdata) {
                auto contact = getSIPAccount().getContactHeader(transport_ ? transport_->get() : nullptr);
                sip_utils::addContactHeader(&contact, tdata);
                ret = pjsip_inv_send_msg(inv.get(), tdata);
                if (ret != PJ_SUCCESS)
                    RING_ERR("[call:%s] failed to send terminate msg, SIP error (%s)",
                             getCallId().c_str(), sip_utils::sip_strerror(ret).c_str());
            }
        } else
            RING_ERR("[call:%s] failed to terminate INVITE@%p, SIP error (%s)",
                     getCallId().c_str(), inv.get(), sip_utils::sip_strerror(ret).c_str());
    }

    inv.reset();
}
예제 #12
0
bool
SIPCall::onhold()
{
    if (not setState(CallState::HOLD))
        return false;

    stopAllMedia();

    if (getConnectionState() == ConnectionState::CONNECTED) {
        if (SIPSessionReinvite() != PJ_SUCCESS)
            RING_WARN("[call:%s] Reinvite failed", getCallId().c_str());
    }

    return true;
}
예제 #13
0
	SipDialog::~SipDialog() {
		DR_LOG(log_debug) << "SipDialog::~SipDialog - destroying sip dialog with call-id " << getCallId() ;
		if( NULL != m_timerSessionRefresh ) {
			cancelSessionTimer() ;
			assert( m_ppSelf ) ;
		}
		if( m_ppSelf ) {
			delete m_ppSelf ;
		}

		nta_leg_t *leg = nta_leg_by_call_id( theOneAndOnlyController->getAgent(), getCallId().c_str() );
		assert( leg ) ;
		if( leg ) {
			nta_leg_destroy( leg ) ;
		}
	}
예제 #14
0
void
SIPCall::transfer(const std::string& to)
{
    auto& account = getSIPAccount();

    stopRecording();

    std::string toUri;
    pj_str_t dst = { 0, 0 };

    toUri = account.getToUri(to);
    pj_cstr(&dst, toUri.c_str());
    RING_DBG("[call:%s] Transferring to %.*s", getCallId().c_str(), (int)dst.slen, dst.ptr);

    if (!transferCommon(&dst))
        throw VoipLinkException("Couldn't transfer");
}
예제 #15
0
bool
SIPCall::internalOffHold(const std::function<void()>& sdp_cb)
{
    if (not setState(CallState::ACTIVE))
        return false;

    sdp_cb();

    if (getConnectionState() == ConnectionState::CONNECTED) {
        if (SIPSessionReinvite() != PJ_SUCCESS) {
            RING_WARN("[call:%s] resuming hold", getCallId().c_str());
            onhold();
            return false;
        }
    }

    return true;
}
예제 #16
0
bool
SIPCall::offhold()
{
    bool success = false;
    auto& account = getSIPAccount();

    try {
        if (account.isStunEnabled())
            success = internalOffHold([&] { updateSDPFromSTUN(); });
        else
            success = internalOffHold([] {});

    } catch (const SdpException &e) {
        RING_ERR("[call:%s] %s", getCallId().c_str(), e.what());
        throw VoipLinkException("SDP issue in offhold");
    }

    return success;
}
예제 #17
0
std::vector<IceCandidate>
SIPCall::getAllRemoteCandidates()
{
    std::vector<IceCandidate> rem_candidates;

    auto addSDPCandidates = [this](unsigned sdpMediaId,
                                   std::vector<IceCandidate>& out) {
        IceCandidate cand;
        for (auto& line : sdp_->getIceCandidates(sdpMediaId)) {
            if (iceTransport_->getCandidateFromSDP(line, cand)) {
                RING_DBG("[call:%s] add remote ICE candidate: %s", getCallId().c_str(), line.c_str());
                out.emplace_back(cand);
            }
        }
    };

    addSDPCandidates(SDP_AUDIO_MEDIA_ID, rem_candidates);
#ifdef RING_VIDEO
    addSDPCandidates(SDP_VIDEO_MEDIA_ID, rem_candidates);
#endif

    return rem_candidates;
}
예제 #18
0
static int
EndMediaSession(struct sip_msg* msg, char* str1, char* str2)
{
    char *command, *result;
    str callId;

    if (!getCallId(msg, &callId)) {
        LOG(L_ERR, "error: end_media_session(): can't get Call-Id\n");
        return -1;
    }

    command = pkg_malloc(callId.len + 20);
    if (command == NULL) {
        LOG(L_ERR, "error: end_media_session(): out of memory\n");
        return -1;
    }

    sprintf(command, "delete %.*s info=\n", callId.len, callId.s);
    result = sendMediaproxyCommand(command);

    pkg_free(command);

    return result==NULL ? -1 : 1;
}
예제 #19
0
static int
UseMediaProxy(struct sip_msg* msg, char* str1, char* str2)
{
    str sdp, sessionIP, signalingIP, callId, userAgent, tokens[64];
    str fromDomain, toDomain, fromAddr, toAddr, fromTag, toTag, domain;
    char *ptr, *command, *result, *agent, *fromType, *toType, *info;
    int streamCount, i, port, count, portCount, cmdlen, infolen, status;
    StreamInfo streams[64], stream;
    Bool request;

    if (msg->first_line.type == SIP_REQUEST) {
        request = True;
    } else if (msg->first_line.type == SIP_REPLY) {
        request = False;
    } else {
        return -1;
    }

    if (!getCallId(msg, &callId)) {
        LM_ERR("can't get Call-Id\n");
        return -1;
    }

    status = getSDPMessage(msg, &sdp);
    // status = -1 is error, -2 is missing SDP body
    if (status < 0)
        return status;

    if (!getSessionLevelMediaIP(&sdp, &sessionIP)) {
        LM_ERR("failed to parse the SDP message\n");
        return -1;
    }

    streamCount = getMediaStreams(&sdp, &sessionIP, streams, 64);
    if (streamCount == -1) {
        LM_ERR("can't extract media streams from the SDP message\n");
        return -1;
    }

    if (streamCount == 0)
        return 1; // there are no media streams. we have nothing to do.

    fromDomain = getFromDomain(msg);
    fromType   = (isFromLocal(msg, NULL, NULL)>0) ? "local" : "remote";
    fromAddr   = getFromAddress(msg);
    toAddr     = getToAddress(msg);
    fromTag    = getFromTag(msg);
    toTag      = getToTag(msg);
    userAgent  = getUserAgent(msg);
    if (request) {
        toDomain = getDestinationDomain(msg); // call only for requests
        toType = (isDestinationLocal(msg, NULL, NULL)>0) ? "local" : "remote";
    } else {
        toDomain.s = "unknown";
        toDomain.len = 7;
        toType = "unknown";
    }

    signalingIP = getSignalingIP(msg);
    domain = getMediaproxyDomain(msg);

    infolen = fromAddr.len + toAddr.len + fromTag.len + toTag.len +
        domain.len + 64;

    cmdlen = callId.len + signalingIP.len + fromDomain.len + toDomain.len +
        userAgent.len*3 + infolen + 128;

    for (i=0; i<streamCount; i++) {
        stream = streams[i];
        cmdlen += stream.ip.len + stream.port.len + stream.type.len + 4;
    }

    command = pkg_malloc(cmdlen);
    if (!command) {
        LM_ERR("out of memory\n");
        return -1;
    }

    if (request)
        count = sprintf(command, "request %.*s", callId.len, callId.s);
    else
        count = sprintf(command, "lookup %.*s", callId.len, callId.s);

    for (i=0, ptr=command+count; i<streamCount; i++) {
        char c = (i==0 ? ' ' : ',');
        count = sprintf(ptr, "%c%.*s:%.*s:%.*s", c,
                        streams[i].ip.len, streams[i].ip.s,
                        streams[i].port.len, streams[i].port.s,
                        streams[i].type.len, streams[i].type.s);
        ptr += count;
    }

    agent = encodeQuopri(userAgent);
    if (!agent) {
        LM_ERR("out of memory\n");
        pkg_free(command);
        return -1;
    }

    info = pkg_malloc(infolen);
    if (!info) {
        LM_ERR("out of memory\n");
        pkg_free(command);
        pkg_free(agent);
        return -1;
    }

    sprintf(info, "from:%.*s,to:%.*s,fromtag:%.*s,totag:%.*s",
            fromAddr.len, fromAddr.s, toAddr.len, toAddr.s,
            fromTag.len, fromTag.s, toTag.len, toTag.s);

    if (domain.len) {
        strcat(info, ",domain:");
        strncat(info, domain.s, domain.len);
    }
    if (isRTPAsymmetric(userAgent)) {
        strcat(info, ",asymmetric");
    }

    snprintf(ptr, command + cmdlen - ptr, " %.*s %.*s %s %.*s %s %s info=%s\n",
             signalingIP.len, signalingIP.s, fromDomain.len, fromDomain.s,
             fromType, toDomain.len, toDomain.s, toType, agent, info);

    pkg_free(info);
    pkg_free(agent);

    result = sendMediaproxyCommand(command);

    pkg_free(command);

    if (result == NULL)
        return -1;

    count = getTokens(result, tokens, sizeof(tokens)/sizeof(str));

    if (count == 0) {
        LM_ERR("empty response from mediaproxy\n");
        return -1;
    } else if (count<streamCount+1) {
        if (request) {
            LM_ERR("insufficient ports returned from mediaproxy: got %d, "
                   "expected %d\n", count-1, streamCount);
            return -1;
        } else {
            LM_WARN("broken client. Called UA added extra media stream(s) "
                    "in the OK reply\n");
        }
    }

    if (sessionIP.s && !isAnyAddress(sessionIP)) {
        if (!replaceElement(msg, &sessionIP, &tokens[0])) {
            LM_ERR("failed to replace session-level media IP in the SDP body\n");
            return -1;
        }
    }

    portCount = min(count-1, streamCount);

    for (i=0; i<portCount; i++) {
        // check. is this really necessary?
        port = strtoint(&tokens[i+1]);
        if (port <= 0 || port > 65535) {
            LM_ERR("invalid port returned by mediaproxy: %.*s\n",
                   tokens[i+1].len, tokens[i+1].s);
            //return -1;
            continue;
        }

        if (streams[i].port.len!=1 || streams[i].port.s[0]!='0') {
            if (!replaceElement(msg, &(streams[i].port), &tokens[i+1])) {
                LM_ERR("failed to replace port in media stream number %d\n", i+1);
                return -1;
            }
        }

        if (streams[i].localIP && !isAnyAddress(streams[i].ip)) {
            if (!replaceElement(msg, &(streams[i].ip), &tokens[0])) {
                LM_ERR("failed to replace IP address in media stream number %d\n", i+1);
                return -1;
            }
        }
    }

    return 1;
}
예제 #20
0
	void SipDialog::doSessionTimerHandling() {
		bool bWeAreRefresher = areWeRefresher()  ;
		
		if( bWeAreRefresher ) {
			//TODO: send a refreshing reINVITE, and notify the client
			DR_LOG(log_debug) << "SipDialog::doSessionTimerHandling - sending refreshing re-INVITE with call-id " << getCallId()  ; 
			theOneAndOnlyController->getDialogController()->notifyRefreshDialog( shared_from_this() ) ;
		}
		else {
			//TODO: tear down the leg, and notify the client
			DR_LOG(log_debug) << "SipDialog::doSessionTimerHandling - tearing down sip dialog with call-id " << getCallId() 
				<< " because remote peer did not refresh the session within the specified interval"  ; 
			theOneAndOnlyController->getDialogController()->notifyTerminateStaleDialog( shared_from_this() ) ;
		}

		assert( m_ppSelf ) ;
		delete m_ppSelf ; m_ppSelf = NULL ; m_timerSessionRefresh = NULL ; m_refresher = no_refresher ; m_nSessionExpiresSecs = 0 ;

	}
예제 #21
0
static int
UseMediaProxy(struct sip_msg* msg, char* str1, char* str2)
{
    str sdp, sessionIP, callId, fromDomain, toDomain, userAgent, tokens[64];
    str fromAddr, toAddr, fromTag, toTag;
    char *clientIP, *ptr, *command, *result, *agent, *fromType, *toType, *info;
    int streamCount, i, port, count, portCount, cmdlen, infolen, success, type;
    StreamInfo streams[64], stream;
    Bool request;

    if (msg->first_line.type == SIP_REQUEST) {
        if (msg->first_line.u.request.method_value == METHOD_INVITE)
            type = MSG_INVITE;
        else if (msg->first_line.u.request.method_value == METHOD_ACK)
            type = MSG_ACK;
        else
            type = MSG_UNKNOWN;
    } else if (msg->first_line.type == SIP_REPLY) {
        type = MSG_REPLY;
    } else {
        type = MSG_UNKNOWN;
    }

    if (type==MSG_INVITE || type==MSG_ACK) {
        request = True;
    } else if (type==MSG_REPLY) {
        request = False;
    } else {
        return -1;
    }

    if (!getCallId(msg, &callId)) {
        LOG(L_ERR, "error: use_media_proxy(): can't get Call-Id\n");
        return -1;
    }

    success = getSDPMessage(msg, &sdp);
    if (success==0 && type==MSG_ACK) {
        return 1; // nothing to do. it's ok for ACK to not have a SDP body
    } else if (success <= 0) {
        LOG(L_ERR, "error: use_media_proxy(): failed to get the SDP message\n");
        return -1;
    }

    if (!getSessionLevelMediaIP(&sdp, &sessionIP)) {
        LOG(L_ERR, "error: use_media_proxy(): error parsing the SDP message\n");
        return -1;
    }

    streamCount = getMediaStreams(&sdp, &sessionIP, streams, 64);
    if (streamCount == -1) {
        LOG(L_ERR, "error: use_media_proxy(): can't extract media streams "
            "from the SDP message\n");
        return -1;
    }

    if (streamCount == 0) {
        // there are no media streams. we have nothing to do.
        return 1;
    }

    fromDomain = getFromDomain(&fromType, msg);
    fromAddr   = getFromAddress(msg);
    toAddr     = getToAddress(msg);
    fromTag    = getFromTag(msg);
    toTag      = getToTag(msg);
    userAgent  = getUserAgent(msg);
    if (request) {
        toDomain = getDestinationDomain(&toType, msg); // call only for requests
    } else {
        toDomain = getToDomain(&toType, msg);
    }

    clientIP = ip_addr2a(&msg->rcv.src_ip);

    infolen = fromAddr.len + toAddr.len + fromTag.len + toTag.len + 64;

    cmdlen = callId.len + strlen(clientIP) + fromDomain.len + toDomain.len +
        userAgent.len*3 + infolen + 128;

    for (i=0; i<streamCount; i++) {
        stream = streams[i];
        cmdlen += stream.ip.len + stream.port.len + stream.type.len + 4;
    }

    command = pkg_malloc(cmdlen);
    if (!command) {
        LOG(L_ERR, "error: use_media_proxy(): out of memory\n");
        return -1;
    }

    if (request)
        count = sprintf(command, "request %.*s", callId.len, callId.s);
    else
        count = sprintf(command, "lookup %.*s", callId.len, callId.s);

    for (i=0, ptr=command+count; i<streamCount; i++) {
        char c = (i==0 ? ' ' : ',');
        count = sprintf(ptr, "%c%.*s:%.*s:%.*s", c,
                        streams[i].ip.len, streams[i].ip.s,
                        streams[i].port.len, streams[i].port.s,
                        streams[i].type.len, streams[i].type.s);
        ptr += count;
    }

    agent = encodeQuopri(userAgent);
    if (!agent) {
        LOG(L_ERR, "error: use_media_proxy(): out of memory\n");
        pkg_free(command);
        return -1;
    }

    info = pkg_malloc(infolen);
    if (!info) {
        LOG(L_ERR, "error: use_media_proxy(): out of memory\n");
        pkg_free(command);
        pkg_free(agent);
        return -1;
    }

    sprintf(info, "from:%.*s,to:%.*s,fromtag:%.*s,totag:%.*s",
            fromAddr.len, fromAddr.s, toAddr.len, toAddr.s,
            fromTag.len, fromTag.s, toTag.len, toTag.s);
    if (isRTPAsymmetric(userAgent)) {
        strcat(info, ",asymmetric");
    }

    snprintf(ptr, command + cmdlen - ptr, " %s %.*s %s %.*s %s %s info=%s\n",
             clientIP, fromDomain.len, fromDomain.s, fromType,
             toDomain.len, toDomain.s, toType, agent, info);

    pkg_free(info);
    pkg_free(agent);

    result = sendMediaproxyCommand(command);

    pkg_free(command);

    if (result == NULL)
        return -1;

    count = getTokens(result, tokens, sizeof(tokens)/sizeof(str));

    if (count == 0) {
        LOG(L_ERR, "error: use_media_proxy(): empty response from mediaproxy\n");
        return -1;
    } else if (count<streamCount+1) {
        if (request) {
            LOG(L_ERR, "error: use_media_proxy(): insufficient ports returned "
                "from mediaproxy: got %d, expected %d\n", count-1, streamCount);
            return -1;
        } else {
            LOG(L_WARN, "warning: use_media_proxy(): broken client. Called UA "
                "added extra media stream(s) in the OK reply\n");
        }
    }

    if (sessionIP.s && !isAnyAddress(sessionIP)) {
        success = replaceElement(msg, &sessionIP, &tokens[0]);
        if (!success) {
            LOG(L_ERR, "error: use_media_proxy(): failed to replace "
                "session-level media IP in SDP body\n");
            return -1;
        }
    }

    portCount = min(count-1, streamCount);

    for (i=0; i<portCount; i++) {
        // check. is this really necessary?
        port = strtoint(&tokens[i+1]);
        if (port <= 0 || port > 65535) {
            LOG(L_ERR, "error: use_media_proxy(): invalid port returned "
                "by mediaproxy: %.*s\n", tokens[i+1].len, tokens[i+1].s);
            //return -1;
            continue;
        }

        if (streams[i].port.len!=1 || streams[i].port.s[0]!='0') {
            success = replaceElement(msg, &(streams[i].port), &tokens[i+1]);
            if (!success) {
                LOG(L_ERR, "error: use_media_proxy(): failed to replace "
                    "port in media stream nr. %d\n", i+1);
                return -1;
            }
        }

        if (streams[i].localIP && !isAnyAddress(streams[i].ip)) {
            success = replaceElement(msg, &(streams[i].ip), &tokens[0]);
            if (!success) {
                LOG(L_ERR, "error: use_media_proxy(): failed to replace "
                    "IP address in media stream nr. %d\n", i+1);
                return -1;
            }
        }
    }

    return 1;
}
예제 #22
0
파일: Connection.cpp 프로젝트: ciuc/sipxecs
/* //////////////////////////// PROTECTED ///////////////////////////////// */
void Connection::postTaoListenerMessage(int state, int newCause, int isLocal)
{
    int eventId = PtEvent::EVENT_INVALID;
    int termEventId = PtEvent::EVENT_INVALID;
    UtlString causeStr;
    causeStr.remove(0);

#ifdef TEST_PRINT
    Os::Logger::instance().log(FAC_CP, PRI_DEBUG, "Connection::postTaoListenerMessage: "
                  "Enter- %s state %d cause %d "
                  "eventid-  %d termeventid %d",
                  (isLocal?"LOCAL":"REMOTE"),
                  state, newCause,
                  eventId, termEventId);
#endif

    switch(state)
    {
    case CONNECTION_IDLE:
        eventId = PtEvent::CONNECTION_CREATED;
        termEventId = PtEvent::TERMINAL_CONNECTION_IDLE;
        break;

    case CONNECTION_INITIATED:
        eventId = PtEvent::CONNECTION_INITIATED;
        termEventId = PtEvent::TERMINAL_CONNECTION_CREATED;
        break;

    case CONNECTION_QUEUED:
        eventId = PtEvent::CONNECTION_QUEUED;
        termEventId = PtEvent::CONNECTION_CREATED;
        break;

    case CONNECTION_OFFERING:
        eventId = PtEvent::CONNECTION_OFFERED;
        break;

    case CONNECTION_DIALING:
        eventId = PtEvent::CONNECTION_DIALING ;
        break;

    case CONNECTION_ALERTING:
        eventId = PtEvent::CONNECTION_ALERTING;
        termEventId = PtEvent::TERMINAL_CONNECTION_RINGING;
        break;

    case CONNECTION_ESTABLISHED:
        eventId = PtEvent::CONNECTION_ESTABLISHED;
        termEventId = PtEvent::TERMINAL_CONNECTION_TALKING;
        break;

    case CONNECTION_FAILED:
        eventId = PtEvent::CONNECTION_FAILED;
        termEventId = PtEvent::TERMINAL_CONNECTION_DROPPED;
        break;

    case CONNECTION_DISCONNECTED:
        eventId = PtEvent::CONNECTION_DISCONNECTED;
        termEventId = PtEvent::TERMINAL_CONNECTION_DROPPED;
        break;

    case PtEvent::TERMINAL_CONNECTION_HELD:
        termEventId = PtEvent::TERMINAL_CONNECTION_HELD;
        break;

    default:
        eventId = PtEvent::CONNECTION_UNKNOWN;
        termEventId = PtEvent::TERMINAL_CONNECTION_UNKNOWN;
        break;

    }

    int cause;
    switch(newCause)
    {
     case CONNECTION_CAUSE_UNKNOWN:
        cause = PtEvent::CAUSE_UNKNOWN;
        causeStr.append("CAUSE_UNKNOWN");
        break;
    case CONNECTION_CAUSE_REDIRECTED:
        cause = PtEvent::CAUSE_REDIRECTED;
        causeStr.append("CAUSE_REDIRECTED");
        break ;

     case CONNECTION_CAUSE_NETWORK_CONGESTION:
        cause = PtEvent::CAUSE_NETWORK_CONGESTION;
        causeStr.append("CAUSE_NETWORK_CONGESTION");
        break;

     case CONNECTION_CAUSE_NETWORK_NOT_OBTAINABLE:
        cause = PtEvent::CAUSE_NETWORK_NOT_OBTAINABLE;
        causeStr.append("CAUSE_NETWORK_NOT_OBTAINABLE");
        break;

     case CONNECTION_CAUSE_DEST_NOT_OBTAINABLE:
        cause = PtEvent::CAUSE_DESTINATION_NOT_OBTAINABLE;
        causeStr.append("CAUSE_DESTINATION_NOT_OBTAINABLE");
        break;

     case CONNECTION_CAUSE_INCOMPATIBLE_DESTINATION:
        cause = PtEvent::CAUSE_INCOMPATIBLE_DESTINATION;
        causeStr.append("CAUSE_INCOMPATIBLE_DESTINATION");
        break;

     case CONNECTION_CAUSE_NOT_ALLOWED:
        cause = PtEvent::CAUSE_NOT_ALLOWED;
        causeStr.append("CAUSE_NOT_ALLOWED");
        break;

     case CONNECTION_CAUSE_NETWORK_NOT_ALLOWED:
        cause = PtEvent::CAUSE_NETWORK_NOT_ALLOWED;
        causeStr.append("CAUSE_NETWORK_NOT_ALLOWED");
        break;

    case CONNECTION_CAUSE_BUSY:
    case CONNECTION_CAUSE_SERVICE_UNAVAILABLE:
        cause = PtEvent::CAUSE_BUSY;
        causeStr.append("CAUSE_BUSY");
        break ;

    case CONNECTION_CAUSE_CANCELLED:
        cause = PtEvent::CAUSE_CALL_CANCELLED;
        causeStr.append("CAUSE_CALL_CANCELLED");
        break ;

    case CONNECTION_CAUSE_TRANSFER:
        cause = PtEvent::CAUSE_TRANSFER;
        causeStr.append("CAUSE_TRANSFER");
        break;

    default:
    case CONNECTION_CAUSE_NORMAL:
        cause = PtEvent::CAUSE_NORMAL;
        causeStr.append("CAUSE_NORMAL");
        break;
    }

    int cnt = 0;
    if (mpListenerCnt)
        cnt = mpListenerCnt->getRef();

    if (cnt > 0)
    {
        TaoObjHandle* pListeners;
        pListeners = new TaoObjHandle[cnt];
        mpListeners->getActiveObjects(pListeners, cnt);

        UtlString callId;

        // Use the connection call id first -- followed by call if
        // unavailable
        getCallId(&callId);                          // arg[0], callId
        if (callId.isNull())
        {
            mpCall->getCallId(callId);
#ifdef TEST_PRINT
            Os::Logger::instance().log(FAC_CP, PRI_DEBUG, "Connection::postTaoListenerMessage: "
                          "Connection call id not found, "
                          "Using CpCall Id = %s ",
                          callId.data());
#endif
        }

        callId += TAOMESSAGE_DELIMITER + mLocalAddress;        // arg[1], localAddress

        UtlString remoteAddress;
        getRemoteAddress(&remoteAddress, TRUE);

        if (remoteAddress.isNull())                            // arg[2], remote address
        {
            callId += TAOMESSAGE_DELIMITER + (UtlString)"UNKNOWN";    // not available yet
        }
        else
        {
            callId += TAOMESSAGE_DELIMITER + remoteAddress;
        }

        char buff[128];
        sprintf(buff, "%d", (int)mRemoteIsCallee);
        callId += TAOMESSAGE_DELIMITER + UtlString(buff);    // arg[3], remoteIsCallee

        sprintf(buff, "%d", cause);
        callId += TAOMESSAGE_DELIMITER + UtlString(buff);    // arg[4], cause

        if (mRemoteIsCallee)
        {
            remoteAddress.insert(0, "foreign-terminal-");
            callId += TAOMESSAGE_DELIMITER + remoteAddress;    // arg[5], remote terminal name
        }
        else
        {
            mpCall->getLocalTerminalId(buff, 127);
            callId += TAOMESSAGE_DELIMITER + UtlString(buff);    // arg[5], local terminal name
        }

        if (isLocal)                                        // TAO_OFFER_PARAM_LOCAL_CONNECTION
        {
            callId += TAOMESSAGE_DELIMITER + "1";            // arg[6], isLocal
        }
        else
        {
            callId += TAOMESSAGE_DELIMITER + "0";            // isLocal
        }

        sprintf(buff, "%d", mResponseCode);
        callId += TAOMESSAGE_DELIMITER + UtlString(buff);    // arg[7], SIP response code

        callId += TAOMESSAGE_DELIMITER + mResponseText;        // arg[8], SIP response text

        int argCnt = 9;
        if(mpCall)
        {
            int metaEventId = 0;
            int metaEventType = PtEvent::META_EVENT_NONE;
            int numCalls = 0;
            const UtlString* metaEventCallIds = NULL;
            mpCall->getMetaEvent(metaEventId, metaEventType, numCalls,
                &metaEventCallIds);
            if (metaEventId != PtEvent::META_EVENT_NONE)
            {
                sprintf(buff, "%d", metaEventId);
                callId += TAOMESSAGE_DELIMITER + UtlString(buff);    // arg[9], meta event id
                sprintf(buff, "%d", metaEventType);
                callId += TAOMESSAGE_DELIMITER + UtlString(buff);    // arg[10], meta code
                argCnt += 2;
                for (int i = 0; i < numCalls; i++)
                {
                    if (metaEventCallIds && metaEventCallIds[i])
                    {
                        callId += TAOMESSAGE_DELIMITER + metaEventCallIds[i];    // meta call ids
                        argCnt++;
                    }
                }
            }
        }

        TaoMessage msg(TaoMessage::EVENT,
                       0,
                       0,
                       eventId,
                       0,
                       argCnt,
                       callId);

        UtlString eventIdStr;
        if (eventId != PtEvent::EVENT_INVALID)
        {
            for (int i = 0; i < cnt; i++) // post connection events
            {
                ((OsServerTask*) pListeners[i])->postMessage((OsMsg&)msg);
            }
            mpCall->getStateString(eventId, &eventIdStr);
            mpCallManager->logCallState(callId.data(), eventIdStr.data(), causeStr);
        }

        if (termEventId != PtEvent::EVENT_INVALID)    // post terminal connection events
        {
            msg.setObjHandle(termEventId);
            for (int i = 0; i < cnt; i++)
            {
                ((OsServerTask*) pListeners[i])->postMessage((OsMsg&)msg);
            }

            mpCall->getStateString(termEventId, &eventIdStr);
            mpCallManager->logCallState(callId.data(), eventIdStr.data(), causeStr);

        }

        delete[] pListeners;
        callId.remove(0);
        eventIdStr.remove(0);
        remoteAddress.remove(0);
    }
#ifdef TEST_PRINT
    Os::Logger::instance().log(FAC_CP, PRI_DEBUG, "Connection::postTaoListenerMessage: "
                  "Leave- %s state %d cause %d "
                  "eventid-  %d termeventid %d",
                  (isLocal?"LOCAL":"REMOTE"),
                  state, newCause,
                  eventId, termEventId);
#endif

    causeStr.remove(0);
}
예제 #23
0
void
SIPCall::updateSDPFromSTUN()
{
    RING_WARN("[call:%s] SIPCall::updateSDPFromSTUN() not implemented", getCallId().c_str());
}
예제 #24
0
void
SIPCall::startAllMedia()
{
    if (isSecure() && not transport_->isSecure()) {
        RING_ERR("[call:%s] Can't perform secure call over insecure SIP transport",
                 getCallId().c_str());
        onFailure(EPROTONOSUPPORT);
        return;
    }
    auto slots = sdp_->getMediaSlots();
    unsigned ice_comp_id = 0;
    bool peer_holding {true};
    int slotN = -1;

    for (const auto& slot : slots) {
        ++slotN;
        const auto& local = slot.first;
        const auto& remote = slot.second;

        if (local.type != remote.type) {
            RING_ERR("[call:%s] [SDP:slot#%u] Inconsistent media types between local and remote",
                     getCallId().c_str(), slotN);
            continue;
        }

        RtpSession* rtp = local.type == MEDIA_AUDIO
            ? static_cast<RtpSession*>(avformatrtp_.get())
#ifdef RING_VIDEO
            : static_cast<RtpSession*>(&videortp_);
#else
            : nullptr;
#endif

        if (not rtp)
            continue;

        if (!local.codec) {
            RING_WARN("[call:%s] [SDP:slot#%u] Missing local codec", getCallId().c_str(),
                      slotN);
            continue;
        }
        if (!remote.codec) {
            RING_WARN("[call:%s] [SDP:slot#%u] Missing remote codec", getCallId().c_str(),
                      slotN);
            continue;
        }

        peer_holding &= remote.holding;

        if (isSecure() && (not local.crypto || not remote.crypto)) {
            RING_ERR("[call:%s] [SDP:slot#%u] Can't perform secure call over insecure RTP transport",
                     getCallId().c_str(), slotN);
            continue;
        }

#ifdef RING_VIDEO
        if (local.type == MEDIA_VIDEO)
            videortp_.switchInput(videoInput_);
#endif

        rtp->updateMedia(remote, local);
        if (isIceRunning()) {
            rtp->start(newIceSocket(ice_comp_id + 0),
                       newIceSocket(ice_comp_id + 1));
            ice_comp_id += 2;
        } else
            rtp->start();

        switch (local.type) {
#ifdef RING_VIDEO
            case MEDIA_VIDEO:
                isVideoMuted_ = videoInput_.empty();
                break;
#endif
            case MEDIA_AUDIO:
                isAudioMuted_ = not rtp->isSending();
                break;
            default: break;
        }
    }
예제 #25
0
static void
transfer_client_cb(pjsip_evsub *sub, pjsip_event *event)
{
    auto link = getSIPVoIPLink();
    if (not link) {
        RING_ERR("no more VoIP link");
        return;
    }

    auto mod_ua_id = link->getModId();

    switch (pjsip_evsub_get_state(sub)) {
        case PJSIP_EVSUB_STATE_ACCEPTED:
            if (!event)
                return;

            pj_assert(event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
            break;

        case PJSIP_EVSUB_STATE_TERMINATED:
            pjsip_evsub_set_mod_data(sub, mod_ua_id, NULL);
            break;

        case PJSIP_EVSUB_STATE_ACTIVE: {
            if (!event)
                return;

            pjsip_rx_data* r_data = event->body.rx_msg.rdata;

            if (!r_data)
                return;

            std::string request(pjsip_rx_data_get_info(r_data));

            pjsip_status_line status_line = { 500, *pjsip_get_status_text(500) };

            if (!r_data->msg_info.msg)
                return;

            if (r_data->msg_info.msg->line.req.method.id == PJSIP_OTHER_METHOD and
                    request.find("NOTIFY") != std::string::npos) {
                pjsip_msg_body *body = r_data->msg_info.msg->body;

                if (!body)
                    return;

                if (pj_stricmp2(&body->content_type.type, "message") or
                        pj_stricmp2(&body->content_type.subtype, "sipfrag"))
                    return;

                if (pjsip_parse_status_line((char*) body->data, body->len, &status_line) != PJ_SUCCESS)
                    return;
            }

            if (!r_data->msg_info.cid)
                return;

            auto call = static_cast<SIPCall *>(pjsip_evsub_get_mod_data(sub, mod_ua_id));
            if (!call)
                return;

            if (status_line.code / 100 == 2) {
                if (call->inv)
                    call->terminateSipSession(PJSIP_SC_GONE);
                Manager::instance().hangupCall(call->getCallId());
                pjsip_evsub_set_mod_data(sub, mod_ua_id, NULL);
            }

            break;
        }

        case PJSIP_EVSUB_STATE_NULL:
        case PJSIP_EVSUB_STATE_SENT:
        case PJSIP_EVSUB_STATE_PENDING:
        case PJSIP_EVSUB_STATE_UNKNOWN:
        default:
            break;
    }
}