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(); }
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()); }
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); }
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) ; } }
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()); } }
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); }
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()); }
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 }
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(); }
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; }
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 ) ; } }
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"); }
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; }
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; }
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; }
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; }
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; }
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 ; }
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; }
/* //////////////////////////// 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); }
void SIPCall::updateSDPFromSTUN() { RING_WARN("[call:%s] SIPCall::updateSDPFromSTUN() not implemented", getCallId().c_str()); }
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; } }
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; } }