NamedList& NamedList::copySubParams(const NamedList& original, const String& prefix, bool skipPrefix, bool replace) { XDebug(DebugInfo,"NamedList::copySubParams(%p,\"%s\",%s,%s) [%p]", &original,prefix.c_str(),String::boolText(skipPrefix), String::boolText(replace),this); if (prefix) { unsigned int offs = skipPrefix ? prefix.length() : 0; ObjList* dest = &m_params; for (const ObjList* l = original.m_params.skipNull(); l; l = l->skipNext()) { const NamedString* s = static_cast<const NamedString*>(l->get()); if (s->name().startsWith(prefix)) { const char* name = s->name().c_str() + offs; if (!*name) continue; if (!replace) dest = dest->append(new NamedString(name,*s)); else if (offs) setParam(name,*s); else setParam(s->name(),*s); } } } return *this; }
// Insert a record into a list in the proper location // Order records ascending by their order // Look at ascPref for records with the same order bool DnsRecord::insert(ObjList& list, DnsRecord* rec, bool ascPref) { if (!rec || list.find(rec)) return false; XDebug(DebugAll,"DnsRecord::insert(%p) order=%d pref=%d",rec,rec->order(),rec->pref()); ObjList* o = list.skipNull(); for (; o; o = o->skipNext()) { DnsRecord* crt = static_cast<DnsRecord*>(o->get()); if (rec->order() > crt->order()) continue; if (rec->order() == crt->order()) { for (; o; o = o->skipNext()) { DnsRecord* crt = static_cast<DnsRecord*>(o->get()); if (crt->order() != rec->order()) break; if (crt->pref() == rec->pref()) continue; if (ascPref == (rec->pref() < crt->pref())) break; } } break; } if (o) o->insert(rec); else list.append(rec); return true; }
// Copy a SrvRecord list into another one void SrvRecord::copy(ObjList& dest, const ObjList& src) { dest.clear(); for (ObjList* o = src.skipNull(); o; o = o->skipNext()) { SrvRecord* rec = static_cast<SrvRecord*>(o->get()); dest.append(new SrvRecord(rec->order(),rec->pref(),rec->address(),rec->port())); } }
// Append a parameter to a buffer from a list or dictionary void appendParam(ObjList& msg, NamedList& params, unsigned char value, TokenDict* dict, unsigned char defValue) { unsigned char a[3] = {value,1}; const char* name = lookup(value,ETSIModem::s_msgParams); a[2] = lookup(params.getValue(name),dict,defValue); msg.append(new DataBlock(a,sizeof(a))); }
NamedList::NamedList(const NamedList& original) : String(original) { ObjList* dest = &m_params; for (const ObjList* l = original.m_params.skipNull(); l; l = l->skipNext()) { const NamedString* p = static_cast<const NamedString*>(l->get()); dest = dest->append(new NamedString(p->name(),*p)); } }
ThreadPrivate::ThreadPrivate(Thread* t,const char* name) : m_thread(t), m_counter(0), m_running(false), m_started(false), m_updest(true), m_cancel(false), m_name(name) { #ifdef DEBUG Debugger debug("ThreadPrivate::ThreadPrivate","(%p,\"%s\") [%p]",t,name,this); #endif // Inherit object counter of creating thread m_counter = Thread::getCurrentObjCounter(true); Lock lock(s_tmutex); s_threads.append(this); }
bool ExpEvaluator::runFunction(ObjList& stack, const ExpOperation& oper) const { DDebug(DebugAll,"runFunction(%p,'%s' %ld) ext=%p", &stack,oper.name().c_str(),oper.number(),(void*)m_extender); if (oper.name() == YSTRING("chr")) { String res; for (long int i = oper.number(); i; i--) { ExpOperation* o = popOne(stack); if (!o) return gotError("ExpEvaluator stack underflow"); res = String((char)o->number()) + res; TelEngine::destruct(o); } stack.append(new ExpOperation(res)); return true; } if (oper.name() == YSTRING("now")) { if (oper.number()) return gotError("Function expects no arguments"); stack.append(new ExpOperation(Time::secNow())); return true; } return m_extender && m_extender->runFunction(this,stack,oper); }
NamedList& NamedList::copyParam(const NamedList& original, const String& name, char childSep) { XDebug(DebugInfo,"NamedList::copyParam(%p,\"%s\",'%.1s')", &original,name.c_str(),&childSep); if (!childSep) { // faster and simpler - used in most cases const NamedString* s = original.getParam(name); return s ? setParam(name,*s) : clearParam(name); } clearParam(name,childSep); String tmp; tmp << name << childSep; ObjList* dest = &m_params; for (const ObjList* l = original.m_params.skipNull(); l; l = l->skipNext()) { const NamedString* s = static_cast<const NamedString*>(l->get()); if ((s->name() == name) || s->name().startsWith(tmp)) dest = dest->append(new NamedString(s->name(),*s)); } return *this; }
bool MrcpConnection::init(Message& msg, const char* target) { if (!target) return false; s_mutex.lock(); if (!s_conns.find(this)) s_conns.append(this); s_mutex.unlock(); Message m("call.execute"); m.addParam("id",id()); m.addParam("callto",target); m.copyParam(msg,"caller"); m.copyParam(msg,"called"); m.addParam("media",String::boolText(true)); m.addParam("media_application",String::boolText(true)); m.addParam("transport_application","TCP/MRCPv2"); m.addParam("formats_application","1"); // defined by the standard m.userData(this); return Engine::dispatch(m); }
// Append a parameter to a buffer // Truncate it or set error if fail is true and parameter length exceeds maxLen // Return: 0 if the parameter is missing // -1 if the parameter is too long // 1 on success int appendParam(ObjList& msg, NamedList& params, unsigned char value, unsigned char maxLen, bool fail) { NamedString* ns = params.getParam(lookup(value,ETSIModem::s_msgParams)); if (!ns) return 0; unsigned char len = ns->length(); if (len > maxLen) { if (fail) { params.setParam("error",ns->name() + "-too-long"); return -1; } len = maxLen; } DataBlock* data = new DataBlock; unsigned char a[2] = {value,len}; FSKModem::addRaw(*data,a,sizeof(a)); FSKModem::addRaw(*data,(void*)ns->c_str(),len); msg.append(data); return 1; }
NamedList& NamedList::setParam(const String& name, const char* value) { XDebug(DebugInfo,"NamedList::setParam(\"%s\",\"%s\")",name.c_str(),value); ObjList *p = m_params.skipNull(); while (p) { NamedString *s = static_cast<NamedString*>(p->get()); if (s->name() == name) { *s = value; return *this; } ObjList* next = p->skipNext(); if (next) p = next; else break; } if (p) p->append(new NamedString(name,value)); else m_params.append(new NamedString(name,value)); return *this; }
// Create a buffer containing the byte representation of a message to be sent // and another one with the header bool ETSIModem::createMsg(NamedList& params, DataBlock& data) { int type = lookup(params,s_msg); switch (type) { case MsgCallSetup: break; case MsgMWI: case MsgCharge: case MsgSMS: Debug(this,DebugStub,"Create message '%s' not implemented [%p]", params.c_str(),this); return false; default: Debug(this,DebugNote,"Can't create unknown message '%s' [%p]", params.c_str(),this); return false; } ObjList msg; bool fail = !params.getBoolValue("force-send",true); // DateTime - ETSI EN 300 659-3 - 5.4.1 String datetime = params.getValue("datetime"); unsigned char dt[4]; bool ok = false; if (datetime.isBoolean()) if (datetime.toBoolean()) ok = getDateTime(dt); else ; else ok = getDateTime(dt,&datetime); if (ok) { DataBlock* dtParam = new DataBlock(0,10); unsigned char* d = (unsigned char*)dtParam->data(); d[0] = DateTime; d[1] = 8; // Set date and time: %.2d%.2d%.2d%.2d month:day:hour:minute for (int i = 0, j = 2; i < 4; i++, j += 2) { d[j] = '0' + dt[i] / 10; d[j+1] = '0' + dt[i] % 10; } msg.append(dtParam); } else DDebug(this,DebugInfo,"Can't set datetime parameter from '%s' [%p]", datetime.c_str(),this); // CallerId/CallerIdReason - ETSI EN 300 659-3 - 5.4.2: Max caller id 20 // Parameter is missing: append reason (default caller absence: 0x4f: unavailable) int res = appendParam(msg,params,CallerId,20,fail); if (res == -1) return false; if (!res) appendParam(msg,params,CallerIdReason,s_dict_callerAbsence,0x4f); // CallerName/CallerNameReason - ETSI EN 300 659-3 - 5.4.5: Max caller name 50 // Parameter is missing: append reason (default callername absence: 0x4f: unavailable) res = appendParam(msg,params,CallerName,50,fail); if (res == -1) return false; if (!res) appendParam(msg,params,CallerNameReason,s_dict_callerAbsence,0x4f); // Build message unsigned char len = 0; unsigned char hdr[2] = {type}; data.assign(&hdr,sizeof(hdr)); for (ObjList* o = msg.skipNull(); o; o = o->skipNext()) { DataBlock* msgParam = static_cast<DataBlock*>(o->get()); if (len + msgParam->length() > 255) { if (!fail) { Debug(this,DebugNote,"Trucating %s message length to %u bytes [%p]", params.c_str(),data.length(),this); break; } params.setParam("error","message-too-long"); return false; } len += msgParam->length(); data += *msgParam; } if (!len) { params.setParam("error","empty-message"); return false; } unsigned char* buf = ((unsigned char*)(data.data())); buf[1] = len; m_chksum = 0; for (unsigned int i = 0; i < data.length(); i++) m_chksum += buf[i]; unsigned char crcVal = 256 - (m_chksum & 0xff); FSKModem::addRaw(data,&crcVal,1); return true; }
bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper) const { DDebug(DebugAll,"runOperation(%p,%u) %s",&stack,oper.opcode(),getOperator(oper.opcode())); switch (oper.opcode()) { case OpcPush: stack.append(new ExpOperation(oper)); break; case OpcAnd: case OpcOr: case OpcXor: case OpcShl: case OpcShr: case OpcAdd: case OpcSub: case OpcMul: case OpcDiv: case OpcMod: case OpcEq: case OpcNe: case OpcLt: case OpcGt: case OpcLe: case OpcGe: { ExpOperation* op2 = popOne(stack); ExpOperation* op1 = popOne(stack); if (!op1 || !op2) { TelEngine::destruct(op1); TelEngine::destruct(op2); return gotError("ExpEvaluator stack underflow"); } switch (oper.opcode()) { case OpcDiv: case OpcMod: if (!op2->number()) return gotError("Division by zero"); default: break; } long int val = 0; switch (oper.opcode()) { case OpcAnd: val = op1->number() & op2->number(); break; case OpcOr: val = op1->number() | op2->number(); break; case OpcXor: val = op1->number() ^ op2->number(); break; case OpcShl: val = op1->number() << op2->number(); break; case OpcShr: val = op1->number() >> op2->number(); break; case OpcAdd: val = op1->number() + op2->number(); break; case OpcSub: val = op1->number() - op2->number(); break; case OpcMul: val = op1->number() * op2->number(); break; case OpcDiv: val = op1->number() / op2->number(); break; case OpcMod: val = op1->number() % op2->number(); break; case OpcLt: val = (op1->number() < op2->number()) ? 1 : 0; break; case OpcGt: val = (op1->number() > op2->number()) ? 1 : 0; break; case OpcLe: val = (op1->number() <= op2->number()) ? 1 : 0; break; case OpcGe: val = (op1->number() >= op2->number()) ? 1 : 0; break; case OpcEq: val = (*op1 == *op2) ? 1 : 0; break; case OpcNe: val = (*op1 != *op2) ? 1 : 0; break; default: break; } TelEngine::destruct(op1); TelEngine::destruct(op2); DDebug(DebugAll,"Numeric result: %lu",val); stack.append(new ExpOperation(val)); } break; case OpcLAnd: case OpcLOr: { ExpOperation* op2 = popOne(stack); ExpOperation* op1 = popOne(stack); if (!op1 || !op2) { TelEngine::destruct(op1); TelEngine::destruct(op2); return gotError("ExpEvaluator stack underflow"); } bool val = false; switch (oper.opcode()) { case OpcLAnd: val = op1->number() && op2->number(); break; case OpcLOr: val = op1->number() || op2->number(); break; default: break; } TelEngine::destruct(op1); TelEngine::destruct(op2); DDebug(DebugAll,"Bool result: '%s'",String::boolText(val)); stack.append(new ExpOperation(val ? 1 : 0)); } break; case OpcCat: { ExpOperation* op2 = popOne(stack); ExpOperation* op1 = popOne(stack); if (!op1 || !op2) { TelEngine::destruct(op1); TelEngine::destruct(op2); return gotError("ExpEvaluator stack underflow"); } String val = *op1 + *op2; TelEngine::destruct(op1); TelEngine::destruct(op2); DDebug(DebugAll,"String result: '%s'",val.c_str()); stack.append(new ExpOperation(val)); } break; case OpcAs: { ExpOperation* op2 = popOne(stack); ExpOperation* op1 = popOne(stack); if (!op1 || !op2) { TelEngine::destruct(op1); TelEngine::destruct(op2); return gotError("ExpEvaluator stack underflow"); } stack.append(new ExpOperation(*op1,*op2)); TelEngine::destruct(op1); TelEngine::destruct(op2); } break; case OpcFunc: return runFunction(stack,oper); case OpcField: return runField(stack,oper); default: Debug(DebugStub,"Please implement operation %u",oper.opcode()); return false; } return true; }
bool ExpEvaluator::trySimplify() { DDebug(DebugInfo,"trySimplify"); bool done = false; for (unsigned int i = 0; i < m_opcodes.length(); i++) { ExpOperation* o = static_cast<ExpOperation*>(m_opcodes[i]); if (!o) continue; switch (o->opcode()) { case OpcLAnd: case OpcLOr: case OpcLXor: case OpcAnd: case OpcOr: case OpcXor: case OpcShl: case OpcShr: case OpcAdd: case OpcSub: case OpcMul: case OpcDiv: case OpcMod: case OpcCat: case OpcEq: case OpcNe: case OpcLt: case OpcGt: case OpcLe: case OpcGe: if (i >= 2) { ExpOperation* op2 = static_cast<ExpOperation*>(m_opcodes[i-1]); ExpOperation* op1 = static_cast<ExpOperation*>(m_opcodes[i-2]); if (!op1 || !op2) continue; if (o->opcode() == OpcLAnd || o->opcode() == OpcAnd || o->opcode() == OpcMul) { if ((op1->opcode() == OpcPush && !op1->number() && op2->opcode() == OpcField) || (op2->opcode() == OpcPush && !op2->number() && op1->opcode() == OpcField)) { (m_opcodes+i)->set(new ExpOperation(0)); m_opcodes.remove(op1); m_opcodes.remove(op2); i -= 2; done = true; continue; } } if (o->opcode() == OpcLOr) { if ((op1->opcode() == OpcPush && op1->number() && op2->opcode() == OpcField) || (op2->opcode() == OpcPush && op2->number() && op1->opcode() == OpcField)) { (m_opcodes+i)->set(new ExpOperation(1)); m_opcodes.remove(op1); m_opcodes.remove(op2); i -= 2; done = true; continue; } } if ((op1->opcode() == OpcPush) && (op2->opcode() == OpcPush)) { ObjList stack; stack.append(new ExpOperation(*op1)); stack.append(new ExpOperation(*op2)); if (runOperation(stack,*o)) { // replace operators and operation with computed constant (m_opcodes+i)->set(popOne(stack)); m_opcodes.remove(op1); m_opcodes.remove(op2); i -= 2; done = true; } } } default: break; } } return done; }
// Creates a SDP body from transport address and list of media descriptors // Use own list if given media list is 0 MimeSdpBody* SDPSession::createSDP(const char* addr, ObjList* mediaList) { DDebug(m_parser,DebugAll,"SDPSession::createSDP('%s',%p) [%p]",addr,mediaList,this); if (!mediaList) mediaList = m_rtpMedia; // if we got no media descriptors we simply create no SDP if (!mediaList) return 0; if (m_sdpSession) ++m_sdpVersion; else m_sdpVersion = m_sdpSession = Time::secNow(); // no address means on hold or muted String origin; origin << "yate " << m_sdpSession << " " << m_sdpVersion; origin << " IN IP4 " << (addr ? addr : m_host.safe()); String conn; conn << "IN IP4 " << (addr ? addr : "0.0.0.0"); MimeSdpBody* sdp = new MimeSdpBody; sdp->addLine("v","0"); sdp->addLine("o",origin); sdp->addLine("s",m_parser->m_sessionName); sdp->addLine("c",conn); sdp->addLine("t","0 0"); Lock lock(m_parser); bool defcodecs = m_parser->m_codecs.getBoolValue("default",true); for (ObjList* ml = mediaList->skipNull(); ml; ml = ml->skipNext()) { SDPMedia* m = static_cast<SDPMedia*>(ml->get()); String mline(m->fmtList()); ObjList* l = mline.split(',',false); mline = *m; mline << " " << (m->localPort() ? m->localPort().c_str() : "0") << " " << m->transport(); ObjList* map = m->mappings().split(',',false); ObjList rtpmap; String frm; int ptime = 0; ObjList* f = l; for (; f; f = f->next()) { String* s = static_cast<String*>(f->get()); if (s) { int mode = 0; if (*s == "ilbc20") ptime = mode = 20; else if (*s == "ilbc30") ptime = mode = 30; else if (*s == "g729b") continue; int payload = s->toInteger(SDPParser::s_payloads,-1); int defcode = payload; String tmp = *s; tmp << "="; for (ObjList* pl = map; pl; pl = pl->next()) { String* mapping = static_cast<String*>(pl->get()); if (!mapping) continue; if (mapping->startsWith(tmp)) { payload = -1; tmp = *mapping; tmp >> "=" >> payload; XDebug(m_parser,DebugAll,"RTP mapped payload %d for '%s' [%p]", payload,s->c_str(),this); break; } } if (payload >= 0) { if (defcode < 0) defcode = payload; const char* map = lookup(defcode,SDPParser::s_rtpmap); if (map && m_parser->m_codecs.getBoolValue(*s,defcodecs && DataTranslator::canConvert(*s))) { frm << " " << payload; String* temp = new String("rtpmap:"); *temp << payload << " " << map; rtpmap.append(temp); if (mode) { temp = new String("fmtp:"); *temp << payload << " mode=" << mode; rtpmap.append(temp); } if (*s == "g729") { temp = new String("fmtp:"); *temp << payload << " annexb=" << ((0 != l->find("g729b")) ? "yes" : "no"); rtpmap.append(temp); } else if (*s == "amr") { temp = new String("fmtp:"); *temp << payload << " octet-align=0"; rtpmap.append(temp); } else if (*s == "amr-o") { temp = new String("fmtp:"); *temp << payload << " octet-align=1"; rtpmap.append(temp); } if(s->length()) { String key("fmtp-"); key << *s; for(unsigned int i = 0; i < m->length(); ++i) { const NamedString *ns = m->getParam(i); if(ns && ns->name() == key) { temp = new String("fmtp:"); *temp << payload << " " << *ns; rtpmap.append(temp); } } } } } } } TelEngine::destruct(l); TelEngine::destruct(map); if ((m_rfc2833 >= 0) && frm && m->isAudio()) { int rfc2833 = m->rfc2833().toInteger(m_rfc2833); if (rfc2833 < 96 || rfc2833 > 127) rfc2833 = 101; // claim to support telephone events frm << " " << rfc2833; String* s = new String; *s << "rtpmap:" << rfc2833 << " telephone-event/8000"; rtpmap.append(s); } if (frm.null()) { if (m->isAudio() || !m->fmtList()) { Debug(m_parser,DebugMild,"No formats for '%s', excluding from SDP [%p]", m->c_str(),this); continue; } Debug(m_parser,DebugInfo,"Assuming formats '%s' for media '%s' [%p]", m->fmtList(),m->c_str(),this); frm << " " << m->fmtList(); // brutal but effective for (char* p = const_cast<char*>(frm.c_str()); *p; p++) { if (*p == ',') *p = ' '; } } if (ptime) { String* temp = new String("ptime:"); *temp << ptime; rtpmap.append(temp); } sdp->addLine("m",mline + frm); bool enc = false; if (m->isModified()) { unsigned int n = m->length(); for (unsigned int i = 0; i < n; i++) { const NamedString* param = m->getParam(i); if (param) { String tmp = param->name(); if (tmp.startsWith("fmtp-")) continue; if (*param) tmp << ":" << *param; sdp->addLine("a",tmp); enc = enc || (param->name() == "encryption"); } } } for (f = rtpmap.skipNull(); f; f = f->skipNext()) { String* s = static_cast<String*>(f->get()); if (s) sdp->addLine("a",*s); } if (addr && m->localCrypto()) { sdp->addLine("a","crypto:" + m->localCrypto()); if (!enc) sdp->addLine("a","encryption:optional"); } }
// Update from parameters. Build a default SDP if no media is found in params bool SDPSession::updateSDP(const NamedList& params) { DDebug(m_parser,DebugAll,"SDPSession::updateSdp('%s') [%p]",params.c_str(),this); bool defaults = true; const char* sdpPrefix = params.getValue("osdp-prefix","osdp"); ObjList* lst = 0; unsigned int n = params.length(); String defFormats; m_parser->getAudioFormats(defFormats); for (unsigned int i = 0; i < n; i++) { const NamedString* p = params.getParam(i); if (!p) continue; // search for rtp_port or rtp_port_MEDIANAME parameters String tmp(p->name()); if (!tmp.startSkip("media",false)) continue; if (tmp && (tmp[0] != '_')) continue; // since we found at least one media declaration disable defaults defaults = false; // now tmp holds the suffix for the media, null for audio bool audio = tmp.null(); // check if media is supported, default only for audio if (!p->toBoolean(audio)) continue; String fmts = params.getValue("formats" + tmp); if (audio && fmts.null()) fmts = defFormats; if (fmts.null()) continue; String trans = params.getValue("transport" + tmp,"RTP/AVP"); String crypto; if (m_secure) crypto = params.getValue("crypto" + tmp); if (audio) tmp = "audio"; else tmp >> "_"; SDPMedia* rtp = 0; // try to take the media descriptor from the old list if (m_rtpMedia) { ObjList* om = m_rtpMedia->find(tmp); if (om) rtp = static_cast<SDPMedia*>(om->remove(false)); } bool append = false; if (rtp) rtp->update(fmts); else { rtp = new SDPMedia(tmp,trans,fmts); append = true; } rtp->crypto(crypto,false); if (sdpPrefix) { for (unsigned int j = 0; j < n; j++) { const NamedString* param = params.getParam(j); if (!param) continue; tmp = param->name(); if (tmp.startSkip(sdpPrefix + rtp->suffix() + "_",false) && (tmp.find('_') < 0)) rtp->parameter(tmp,*param,append); } } if (!lst) lst = new ObjList; lst->append(rtp); } if (defaults && !lst) { lst = new ObjList; lst->append(new SDPMedia("audio","RTP/AVP",params.getValue("formats",defFormats))); } return setMedia(lst); }
// Creates a SDP body from transport address and list of media descriptors // Use own list if given media list is 0 MimeSdpBody* SDPSession::createSDP(const char* addr, ObjList* mediaList) { DDebug(m_enabler,DebugAll,"SDPSession::createSDP('%s',%p) [%p]",addr,mediaList,m_ptr); if (!mediaList) mediaList = m_rtpMedia; // if we got no media descriptors we simply create no SDP if (!mediaList) return 0; if (m_sdpSession) ++m_sdpVersion; else m_sdpVersion = m_sdpSession = Time::secNow(); // override the address with the externally advertised if needed if (addr && m_rtpNatAddr) addr = m_rtpNatAddr; if (!m_originAddr) m_originAddr = addr ? addr : m_host.safe(); // no address means on hold or muted String origin; origin << "yate " << m_sdpSession << " " << m_sdpVersion; origin << " "; int f = addIP(origin,m_originAddr); String conn; addIP(conn,addr,f); MimeSdpBody* sdp = new MimeSdpBody; sdp->addLine("v","0"); sdp->addLine("o",origin); sdp->addLine("s",m_parser->m_sessionName); sdp->addLine("c",conn); sdp->addLine("t","0 0"); Lock lock(m_parser); bool defcodecs = m_parser->m_codecs.getBoolValue("default",true); for (ObjList* ml = mediaList->skipNull(); ml; ml = ml->skipNext()) { SDPMedia* m = static_cast<SDPMedia*>(ml->get()); int rfc2833 = 0; if ((m_rfc2833 >= 0) && m->isAudio()) { if (!m_rtpForward) { rfc2833 = m->rfc2833().toInteger(m_rfc2833); if (rfc2833 < 96 || rfc2833 > 127) rfc2833 = 101; } else if (m->rfc2833().toBoolean(true)) { rfc2833 = m->rfc2833().toInteger(); if (rfc2833 < 96 || rfc2833 > 127) rfc2833 = 0; } } String mline(m->fmtList()); ObjList* l = mline.split(',',false); mline = *m; mline << " " << (m->localPort() ? m->localPort().c_str() : "0") << " " << m->transport(); ObjList* map = m->mappings().split(',',false); ObjList rtpmap; ObjList* dest = &rtpmap; String frm; int ptime = 0; ObjList* f = l; for (; f; f = f->next()) { const String* s = static_cast<const String*>(f->get()); if (s) { int mode = 0; if (*s == "g729b") continue; int payload = s->toInteger(SDPParser::s_payloads,-1); int defcode = payload; String tmp = *s; tmp << "="; bool found = false; for (ObjList* pl = map; pl; pl = pl->next()) { const String* mapping = static_cast<const String*>(pl->get()); if (!mapping) continue; if (mapping->startsWith(tmp)) { payload = -1; tmp = *mapping; tmp >> "=" >> payload; found = true; XDebug(m_enabler,DebugAll,"RTP mapped payload %d for '%s' [%p]", payload,s->c_str(),m_ptr); break; } String tmp2 = *mapping; int pload; tmp2 >> "=" >> pload; if (payload == pload) { XDebug(m_enabler,DebugAll,"RTP conflict for payload %d, allocating new [%p]", payload,m_ptr); payload = -1; u_int32_t bmap = 0; for (ObjList* sl = map; sl; sl = sl->next()) { mapping = static_cast<const String*>(sl->get()); if (!mapping) continue; tmp2 = *mapping; pload = 0; tmp2 >> "=" >> pload; if (pload >= 96 && pload < 127) bmap |= 1 << (pload - 96); } // allocate free and non-standard is possible for (pload = 96; pload < 127; pload++) { if (pload == rfc2833) continue; if (lookup(pload,SDPParser::s_rtpmap)) continue; if ((bmap & (1 << (pload - 96))) == 0) { payload = pload; break; } } if (payload >= 0) break; // none free, allocate from "standard" ones too for (pload = 96; pload < 127; pload++) { if (pload == rfc2833) continue; if ((bmap & (1 << (pload - 96))) == 0) { payload = pload; break; } } break; } } if (payload >= 0) { if (!found) { tmp = *s; tmp << "=" << payload; map->append(new String(tmp)); } if (defcode < 0) defcode = payload; const char* map = lookup(defcode,SDPParser::s_rtpmap); if (map && m_parser->m_codecs.getBoolValue(*s,defcodecs && DataTranslator::canConvert(*s))) { if (*s == "ilbc20") ptime = mode = 20; else if (*s == "ilbc30") ptime = mode = 30; frm << " " << payload; String* temp = new String("rtpmap:"); *temp << payload << " " << map; dest = dest->append(temp); if (mode) { temp = new String("fmtp:"); *temp << payload << " mode=" << mode; dest = dest->append(temp); } if (*s == "g729") { temp = new String("fmtp:"); *temp << payload << " annexb=" << ((0 != l->find("g729b")) ? "yes" : "no"); dest = dest->append(temp); } else if (*s == "amr") { temp = new String("fmtp:"); *temp << payload << " octet-align=0"; dest = dest->append(temp); } else if (*s == "amr-o") { temp = new String("fmtp:"); *temp << payload << " octet-align=1"; dest = dest->append(temp); } } } } }
// Parse a received buffer according to RFC 3435 // See Appendix A for the grammar bool MGCPMessage::parse(MGCPEngine* engine, ObjList& dest, const unsigned char* buffer, unsigned int len, const char* sdpType) { if (!buffer) return false; #ifdef PARSER_DEBUG String t((const char*)buffer,len); Debug(engine,DebugAll,"Parse received buffer\r\n%s",t.c_str()); #endif int errorCode = 510; // Protocol error unsigned int trans = 0; String error; unsigned int crt = 0; while (crt < len && !error) { unsigned int count = 0; const char* line = 0; // Skip empty lines before a message line and skip trailing blanks on the message line while (crt < len) { line = getLine(buffer,len,crt,count); if (!line) { error = "Invalid end-of-line"; break; } // Exit loop if the line is not empty if (count) break; } if (!count || error) break; // *** Decode the message line MGCPMessage* msg = decodeMessage(line,count,trans,error,engine); if (!msg) break; dest.append(msg); #ifdef PARSER_DEBUG String m((const char*)line,count); Debug(engine,DebugAll,"Decoded message: %s",m.c_str()); #endif // *** Decode parameters if (decodeParams(buffer,len,crt,msg,error,engine)) continue; if (error) { if (msg->isCommand()) trans = msg->transactionId(); break; } if (crt >= len) break; // *** Decode SDP // Decode SDPs until the end of buffer or // a line containing a dot (message separator in a piggybacked block) // SDPs are separated by an empty line int empty = 0; while (empty < 2) { // Skip until an empty line, a line containing a dot or end of buffer unsigned int start = crt; unsigned int sdpLen = 0; while (true) { line = getLine(buffer,len,crt,count); if (!line) { error = "Invalid end-of-line"; break; } if (!count || (count == 1 && (*line == '.' || !*line))) { if (!count) empty++; else empty = 3; break; } empty = 0; sdpLen = crt - start; } if (error) break; if (sdpLen) msg->sdp.append(new MimeSdpBody(sdpType,(const char*)buffer+start,sdpLen)); } // Found 2 empty lines: skip until end of buffer or line containing '.' or non empty line if (empty == 2) { unsigned int start = crt; while (true) { line = getLine(buffer,len,crt,count); if (!line) { error = "Invalid end-of-line"; break; } if (!count) { if (crt == len) break; continue; } // Fallback with current index if found non empty line which doesn't start with '.' if (*line && *line != '.') crt = start; break; } } } if (!error) return true; dest.clear(); if (trans && trans <= 999999999) dest.append(new MGCPMessage(engine,0,errorCode,trans,0,0)); Debug(engine,DebugNote,"Parser error: %s",error.c_str()); return false; }