本文整理汇总了C++中Exception::error方法的典型用法代码示例。如果您正苦于以下问题:C++ Exception::error方法的具体用法?C++ Exception::error怎么用?C++ Exception::error使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类Exception
的用法示例。
在下文中一共展示了Exception::error方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: init
bool Application::init(int argc, const char* argv[]) {
// set main thread name
Util::SetCurrentThreadName("Main");
initApplicationPaths(argv[0]);
// configurations
string name("configs");
getString("application.baseName", name);
string configPath(_path.parent());
configPath.append(name);
configPath.append(".ini");
if (loadConfigurations(configPath)) {
setString("application.configPath", configPath);
vector<string> values;
FileSystem::Unpack(configPath, values);
if (!values.empty())
values.resize(values.size() - 1);
FileSystem::Pack(values, configPath);
setString("application.configDir", configPath);
}
// logs
Logs::SetLogger(*this);
string logDir(_path.parent());
logDir.append("logs");
string logFileName("log");
if (loadLogFiles(logDir, logFileName, _logSizeByFile, _logRotation)) {
FileSystem::CreateDirectory(logDir);
_logPath = logDir + "/" + logFileName;
if (_logRotation > 0) {
_logPath.append(".");
_logStream.open(_logPath + "0", ios::out | ios::binary | ios::app);
} else
_logStream.open(_logPath, ios::out | ios::binary | ios::app);
}
// options
Exception ex;
defineOptions(ex, _options);
if (ex)
FATAL_ERROR(ex.error());
if (!_options.process(ex, argc, argv, [this](const string& name, const string& value) { setString("arguments." + name, value); }))
FATAL_ERROR("Arguments, ",ex.error()," use 'help'")
else if (ex)
WARN("Arguments, ",ex.error()," use 'help'")
if (hasArgument("help")) {
displayHelp();
return false;
}
return true;
}
示例2: messageHandler
void FlashStream::messageHandler(const string& name,AMFReader& message,FlashWriter& writer) {
if(name=="play") {
disengage(&writer);
string publication;
message.readString(publication);
// TODO implements completly NetStream.play method, with possible NetStream.play.failed too!
Exception ex;
_pListener = invoker.subscribe(ex,peer,publication,writer);
if (ex) {
writer.writeAMFStatus("NetStream.Play.Failed",ex.error());
return;
}
if(message.available())
_pListener->setNumber("unbuffered",message.readNumber()==-3000);
if(_bufferTime>0) {
// To do working the buffertime on receiver side
BinaryWriter& raw = writer.writeRaw();
raw.write16(0);
raw.write32(id);
_pListener->setNumber("bufferTime",_bufferTime);
}
writer.writeAMFStatus("NetStream.Play.Reset","Playing and resetting " + publication); // for entiere playlist
writer.writeAMFStatus("NetStream.Play.Start","Started playing " + publication); // for item
} else if(name == "closeStream") {
disengage(&writer);
} else if(name=="publish") {
disengage(&writer);
string type,publication;
message.readString(publication);
size_t query = publication.find('?');
if (query != string::npos)
publication = publication.substr(0, query); // TODO use query in Util::UnpackQuery for publication options?
if(message.available())
message.readString(type); // TODO support "append" and "appendWithGap"
Exception ex;
_pPublication = invoker.publish(ex, peer, publication, type == "record" ? Publication::RECORD : Publication::LIVE);
if (ex)
writer.writeAMFStatus("NetStream.Publish.BadName",ex.error());
else
writer.writeAMFStatus("NetStream.Publish.Start",publication +" is now published");
} else if(_pListener && name=="receiveAudio") {
_pListener->receiveAudio = message.readBoolean();
} else if(_pListener && name=="receiveVideo") {
_pListener->receiveVideo = message.readBoolean();
} else
ERROR("RTMFPMessage '",name,"' unknown on stream ",id);
}
示例3: init
bool Application::init(int argc, const char* argv[]) {
// set main thread name
Util::SetCurrentThreadName("Main");
initApplicationPaths(argv[0]);
// configurations
string configPath;
if (loadConfigurations(String::Format(configPath,_file.parent(),_file.baseName(),".ini"))) {
setString("application.configPath", configPath);
setString("application.configDir", FileSystem::GetParent(configPath));
}
// logs
Logs::SetLogger(*this);
string logDir(_file.parent());
logDir.append("logs");
string logFileName("log");
Exception ex;
if (loadLogFiles(logDir, logFileName, _logSizeByFile, _logRotation)) {
bool success;
EXCEPTION_TO_LOG(success=FileSystem::CreateDirectory(ex, logDir),file().baseName()," log system")
if (success) {
_logPath.assign(FileSystem::MakeFolder(logDir)).append(logFileName);
if (_logRotation > 0) {
_logPath += '.';
_logStream.open(_logPath += '0', ios::out | ios::binary | ios::app);
} else
_logStream.open(_logPath, ios::out | ios::binary | ios::app);
}
}
// options
defineOptions(ex, _options);
if (ex)
FATAL_ERROR(ex.error());
if (!_options.process(ex, argc, argv, [this](const string& name, const string& value) { setString("arguments." + name, value); }))
FATAL_ERROR("Arguments, ",ex.error()," use 'help'")
else if (ex)
WARN("Arguments, ",ex.error()," use 'help'")
if (hasArgument("help")) {
displayHelp();
return false;
}
return true;
}
示例4: onConnection
void Peer::onConnection(Exception& ex, Writer& writer,DataReader& parameters,DataWriter& response) {
if(!connected) {
_pWriter = &writer;
// reset default protocol parameters
_parameters.clear();
Parameters::ForEach forEach([this](const string& key,const string& value) {
_parameters.setString(key,value);
});
string buffer;
_handler.iterate(String::Format(buffer,protocol,"."), forEach);
ParameterWriter parameterWriter(_parameters);
SplitWriter parameterAndResponse(parameterWriter,response);
_handler.onConnection(ex, *this,parameters,parameterAndResponse);
if (!ex) {
(bool&)connected = ((Entities<Client>&)_handler.clients).add(*this);
if (!connected) {
ex.set(Exception::PROTOCOL, "Client ", Util::FormatHex(id, ID_SIZE, buffer), " exists already");
ERROR(ex.error());
_handler.onDisconnection(*this);
}
}
if (!connected) {
writer.abort();
_pWriter = NULL;
} else {
OnInitParameters::raise(_parameters);
DEBUG("Client ",address.toString()," connection")
}
writer.open(); // open even if "ex" to send error messages!
} else
示例5: loadConfigurations
bool Application::loadConfigurations(string& path) {
Exception ex;
if (Util::ReadIniFile(ex, path, *this))
return true;
DEBUG("Impossible to load configuration file (", ex.error(), ")");
return false;
}
示例6: valueType
UInt8 QueryReader::valueType() {
if (String::ICompare(_value, "null") == 0)
return NIL;
if (String::ICompare(_value, "false") == 0) {
_number = 0;
return BOOLEAN;
}
if (String::ICompare(_value, "true") == 0) {
_number = 1;
return BOOLEAN;
}
Exception ex;
if (_date.update(ex, _value)) {
if (ex)
WARN("QueryReader date, ", ex.error());
return DATE;
}
if (String::ToNumber(_value, _number))
return NUMBER;
return STRING;
}
示例7: Parse
bool Parse(const char * stDate, Int32 year, UInt8 month, UInt8 day,UInt8 weekDay, UInt8 hour, UInt8 minute, UInt8 second, UInt16 millisecond,Int32 offset,const char* format=NULL) {
bool bIsParseOk = _Date.update(Ex,stDate,format);
if (!bIsParseOk) {
DEBUG("Error during parsing of ", stDate, ", ",Ex.error());
return false;
}
return Check(year, month, day, weekDay, hour, minute, second, millisecond, offset);
}
示例8: manage
void RTMFPWriter::manage(Exception& ex, Invoker& invoker) {
if(!consumed() && !_band.failed()) {
if(_trigger.raise(ex))
raiseMessage();
if (ex) {
fail("RTMFPWriter can't deliver its data, ",ex.error());
return;
}
}
if(critical && state()==CLOSED) {
ex.set(Exception::NETWORK, "Main flow writer closed, session is closing");
return;
}
flush(false);
}
示例9: manage
void RTMFPSession::manage() {
if(died)
return;
Session::manage();
if (_failed) {
failSignal();
return;
}
// After 6 mn we considerate than the session has failed
if(_recvTimestamp.isElapsed(360000000)) {
fail("Timeout no client message");
return;
}
// To accelerate the deletion of peer ghost (mainly for netgroup efficient), starts a keepalive server after 2 mn
if(_recvTimestamp.isElapsed(120000000) && !keepAlive()) // TODO check it!
return;
// Raise RTMFPWriter
auto it=_flowWriters.begin();
while (it != _flowWriters.end()) {
Exception ex;
it->second->manage(ex, invoker);
if (ex) {
if (it->second->critical) {
fail(ex.error());
break;
}
continue;
}
if (it->second->consumed()) {
_flowWriters.erase(it++);
continue;
}
++it;
}
flush();
}
示例10: flush
void RTMFPSession::flush(UInt8 marker,bool echoTime,RTMFPEngine::Type type) {
_pLastWriter=NULL;
if(!_pSender)
return;
if (!died && _pSender->available()) {
PacketWriter& packet(_pSender->packet);
// After 30 sec, send packet without echo time
if(_recvTimestamp.isElapsed(30000000))
echoTime = false;
if(echoTime)
marker+=4;
else
packet.clip(2);
BinaryWriter writer(packet, 6);
writer.write8(marker).write16(RTMFP::TimeNow());
if(echoTime)
writer.write16(_timeSent+RTMFP::Time(_recvTimestamp.elapsed()));
_pSender->farId = farId;
_pSender->encoder.type = type;
_pSender->address.set(peer.address);
if (packet.size() > RTMFP_MAX_PACKET_SIZE)
ERROR("Message exceeds max RTMFP packet size");
dumpResponse(packet.data() + 6, packet.size() - 6);
Exception ex;
_pThread = _socket.send<RTMFPSender>(ex, _pSender,_pThread);
if (ex)
ERROR("RTMFP flush, ", ex.error());
}
_pSender.reset();
}
示例11: flush
void RTMFPSession::flush(bool echoTime,UInt8 marker) {
_pLastWriter=NULL;
if(!_pSender)
return;
if (!died && _pSender->available()) {
BinaryWriter& packet(_pSender->packet);
// After 30 sec, send packet without echo time
if(peer.lastReceptionTime.isElapsed(30000))
echoTime = false;
if(echoTime)
marker+=4;
else
packet.clip(2);
BinaryWriter writer(packet.data()+6, 5);
writer.write8(marker).write16(RTMFP::TimeNow());
if (echoTime)
writer.write16(_timeSent+RTMFP::Time(peer.lastReceptionTime.elapsed()));
_pSender->farId = farId;
_pSender->address.set(peer.address);
if (packet.size() > RTMFP_MAX_PACKET_SIZE)
ERROR("Message exceeds max RTMFP packet size on session ",name()," (",packet.size(),">",RTMFP_MAX_PACKET_SIZE,")");
dumpResponse(packet.data() + 6, packet.size() - 6);
Exception ex;
_pThread = Session::send<RTMFProtocol,RTMFPSender>(ex, _pSender,_pThread);
if (ex)
ERROR("RTMFP flush, ", ex.error());
}
_pSender.reset();
}
示例12: messageHandler
void FlashStream::messageHandler(const string& name, AMFReader& message, FlashWriter& writer) {
if (name == "play") {
disengage(&writer);
string publication;
message.readString(publication);
// TODO implements completly NetStream.play method, with possible NetStream.play.failed too!
Exception ex;
_pListener = invoker.subscribe(ex, peer, publication, writer); // ex already log displayed
if (!_pListener) {
writer.writeAMFStatus("NetStream.Play.Failed", ex.error());
return;
}
OnStart::raise(id, writer); // stream begin
writer.writeAMFStatus("NetStream.Play.Reset", "Playing and resetting " + publication); // for entiere playlist
writer.writeAMFStatus("NetStream.Play.Start", "Started playing "+publication); // for item
AMFWriter& amf(writer.writeInfos("|RtmpSampleAccess"));
amf.writeBoolean(true); // audioSampleAccess
amf.writeBoolean(true); // videoSampleAccess
if (_bufferTime > 0)
_pListener->setNumber("bufferTime", _bufferTime);
} else if (name == "closeStream") {
disengage(&writer);
} else if (name == "publish") {
disengage(&writer);
string type, publication;
message.readString(publication);
size_t query = publication.find('?');
if (query != string::npos)
publication = publication.substr(0, query); // TODO use query in Util::UnpackQuery for publication options?
if (message.available())
message.readString(type); // TODO support "append" and "appendWithGap"
Exception ex;
_pPublication = invoker.publish(ex, peer, publication, type == "record" ? Publication::RECORD : Publication::LIVE);
if (ex) {
writer.writeAMFStatus("NetStream.Publish.BadName", ex.error());
_pPublication = NULL;
} else
writer.writeAMFStatus("NetStream.Publish.Start", publication + " is now published");
} else if (_pListener && name == "receiveAudio") {
message.readBoolean(_pListener->receiveAudio);
} else if (_pListener && name == "receiveVideo") {
message.readBoolean(_pListener->receiveVideo);
} else if (_pListener && name == "pause") {
bool paused(true);
message.readBoolean(paused);
// TODO support pause for VOD
if (paused) {
// useless, client knows it when it calls NetStream::pause method
// writer.writeAMFStatus("NetStream.Pause.Notify", _pListener->publication.name() + " paused");
} else {
double position;
if (message.readNumber(position))
_pListener->seek((UInt32)position);
OnStart::raise(id, writer); // stream begin
// useless, client knows it when it calls NetStream::resume method
// writer.writeAMFStatus("NetStream.Unpause.Notify", _pListener->publication.name() + " resumed");
}
} else if (_pListener && name == "seek") {
double position;
if (message.readNumber(position)) {
_pListener->seek((UInt32)position);
// TODO support seek for VOD
OnStart::raise(id, writer); // stream begin
// useless, client knows it when it calls NetStream::seek method, and wait "NetStream.Seek.Complete" rather (raised by client side)
// writer.writeAMFStatus("NetStream.Seek.Notify", _pListener->publication.name() + " seek operation");
} else
writer.writeAMFStatus("NetStream.Seek.InvalidTime", _pListener->publication.name() + " seek operation must pass in argument a milliseconds position time");
} else if (_pPublication && name == "@setDataFrame") {
// metadata
_pPublication->writeProperties(message);
} else if (_pPublication && name == "@clearDataFrame") {
_pPublication->clearProperties();
} else
ERROR("Message '",name,"' unknown on stream ",id);
}
示例13: packetHandler
void WSSession::packetHandler(PacketReader& packet) {
UInt8 type = 0;
Exception ex;
if(peer.connected) {
type = packet.read8();
switch(type) {
case WS::TYPE_BINARY: {
RawReader reader(packet);
peer.onMessage(ex, "onMessage",reader,WS::TYPE_BINARY);
break;
}
case WS::TYPE_TEXT: {
if(!JSONReader::IsValid(packet)) {
RawReader reader(packet);
peer.onMessage(ex, "onMessage",reader);
break;
}
JSONReader reader(packet);
if(reader.followingType()!=JSONReader::STRING) {
peer.onMessage(ex, "onMessage",reader);
break;
}
string name;
reader.readString(name);
if(name=="__publish") {
if(reader.followingType()!=JSONReader::STRING) {
ex.set(Exception::PROTOCOL, "__publish method takes a stream name in first parameter",WS::CODE_MALFORMED_PAYLOAD);
break;
}
reader.readString(name);
if(_pPublication)
invoker.unpublish(peer,_pPublication->name());
_pPublication = invoker.publish(ex, peer,name);
} else if(name=="__play") {
if(reader.followingType()!=JSONReader::STRING) {
ex.set(Exception::PROTOCOL, "__play method takes a stream name in first parameter",WS::CODE_MALFORMED_PAYLOAD);
break;
}
reader.readString(name);
closeSusbcription();
} else if(name=="__closePublish") {
closePublication();
} else if(name=="__closePlay") {
closeSusbcription();
} else if (name == "__close") {
closePublication();
closeSusbcription();
} else if(_pPublication) {
reader.reset();
_pPublication->pushData(reader);
} else
peer.onMessage(ex, name,reader);
break;
}
case WS::TYPE_CLOSE:
_writer.close(packet.available() ? packet.read16() : 0);
break;
case WS::TYPE_PING:
_writer.writePong(packet.current(),packet.available());
break;
case WS::TYPE_PONG:
peer.setPing(_writer.ping = (UInt16)(_time.elapsed()/1000));
break;
default:
ex.set(Exception::PROTOCOL, Format<UInt8>("Type %#x unknown", type), WS::CODE_MALFORMED_PAYLOAD);
break;
}
if (ex) {
ERROR(ex.error());
_writer.close((ex.code()==Exception::APPLICATION || ex.code() == Exception::SOFTWARE) ? WS::CODE_PROTOCOL_ERROR : ex.code());
}
}
if(!peer.connected || type==WS::TYPE_CLOSE)
kill();
else
_writer.flush();
}
示例14: handshakeHandler
//.........这里部分代码省略.........
// public address
RTMFP::WriteAddress(response,pSessionWanted->peer.address, RTMFP::ADDRESS_PUBLIC);
DEBUG("P2P address initiator exchange, ",pSessionWanted->peer.address.toString());
if (hasAnExteriorPeer && pSession->peer.serverAddress.host()!=pSessionWanted->peer.address.host()) {
// the both peer see the server in a different way (and serverAddress.host()!= public address host written above),
// Means an exterior peer, but we can't know which one is the exterior peer
// so add an interiorAddress build with how see eachone the server on the both side
SocketAddress interiorAddress(pSession->peer.serverAddress.host(), pSessionWanted->peer.address.port());
RTMFP::WriteAddress(response,interiorAddress, RTMFP::ADDRESS_PUBLIC);
DEBUG("P2P address initiator exchange, ",interiorAddress.toString());
}
// local address
for(const SocketAddress& address : pSessionWanted->peer.localAddresses) {
RTMFP::WriteAddress(response,address, RTMFP::ADDRESS_LOCAL);
DEBUG("P2P address initiator exchange, ",address.toString());
}
// add the turn address (RelayServer) if possible and required
if (pSession && times>0) {
UInt8 timesBeforeTurn(0);
if(pSession->peer.parameters().getNumber("timesBeforeTurn",timesBeforeTurn) && timesBeforeTurn>=times) {
UInt16 port = invoker.relayer.relay(pSession->peer.address,pSessionWanted->peer.address,20); // 20 sec de timeout is enough for RTMFP!
if (port > 0) {
SocketAddress address(pSession->peer.serverAddress.host(), port);
RTMFP::WriteAddress(response, address, RTMFP::ADDRESS_REDIRECTION);
} // else ERROR already display by RelayServer class
}
}
return 0x71;
}
DEBUG("UDP Hole punching, session ", Util::FormatHex(peerId, ID_SIZE, LOG_BUFFER), " wanted not found")
set<SocketAddress> addresses;
peer.onRendezVousUnknown(peerId,addresses);
set<SocketAddress>::const_iterator it;
for(it=addresses.begin();it!=addresses.end();++it) {
if(it->host().isWildcard())
continue;
if(address == *it)
WARN("A client tries to connect to himself (same ", address.toString()," address)");
RTMFP::WriteAddress(response,*it,RTMFP::ADDRESS_REDIRECTION);
DEBUG("P2P address initiator exchange, ",it->toString());
}
return addresses.empty() ? 0 : 0x71;
}
if(type == 0x0a){
/// RTMFPHandshake
HelloAttempt& attempt = AttemptCounter::attempt<HelloAttempt>(tag);
Peer& peer(*_pPeer);
// Fill peer infos
peer.properties().clear();
string serverAddress;
Util::UnpackUrl(epd, serverAddress, (string&)peer.path,(string&)peer.query);
peer.setServerAddress(serverAddress);
Util::UnpackQuery(peer.query, peer.properties());
Exception ex;
set<SocketAddress> addresses;
peer.onHandshake(attempt.count+1,addresses);
if(!addresses.empty()) {
set<SocketAddress>::iterator it;
for(it=addresses.begin();it!=addresses.end();++it) {
if (it->host().isWildcard())
RTMFP::WriteAddress(response, peer.serverAddress, RTMFP::ADDRESS_REDIRECTION);
else
RTMFP::WriteAddress(response, *it, RTMFP::ADDRESS_REDIRECTION);
}
return 0x71;
}
// New RTMFPCookie
RTMFPCookie* pCookie = attempt.pCookie;
if (!pCookie) {
pCookie = new RTMFPCookie(*this, invoker, tag, _pPeer);
if (!pCookie->run(ex)) {
delete pCookie;
ERROR("RTMFPCookie creation, ", ex.error())
return 0;
}
_pPeer.reset(new Peer((Handler&)invoker)); // reset peer
_cookies.emplace(pCookie->value(), pCookie);
attempt.pCookie = pCookie;
}
// response
response.write8(COOKIE_SIZE);
response.write(pCookie->value(),COOKIE_SIZE);
// instance id (certificat in the middle)
response.write(_certificat,sizeof(_certificat));
return 0x70;
} else
示例15: build
//.........这里部分代码省略.........
UInt16 val = String::ToNumber<UInt16>(ex, values[1]);
if (ex)
break;
pMedia = addMedia(values[0], val, values[2]);
for(const string& st : values) {
pMedia->formats.emplace_back(String::ToNumber<UInt8>(ex, st));
if (ex)
break;
}
break;
}
case 'a': { // a=* (zero or more session attribute lines)
vector<string>* pFields = NULL;
bool isMsId = false;
string fingerHash;
// TODO SDPSource* pSource = NULL;
// TODO list<UInt32>* pSourceGroupe = NULL;
vector<string> fields;
String::Split(line, " ", fields, String::SPLIT_IGNORE_EMPTY | String::SPLIT_TRIM);
for(const string& st : fields) {
size_t pos = st.find(':');
string key,value;
if(pos!=string::npos) {
key = st.substr(0,pos);
value = st.substr(pos+1);
} else
key = st;
// RFC 5576
if(pMedia) {
/* TODO
if(pSourceGroupe)
pSourceGroupe->push_back(NumberParser::parseUnsigned(field));
else if(pSource) {
if(isMsId)
pSource->msData = field;
else if(key=="cname") // cname:<value>
pSource->cname = value;
else if(key=="msid") {// draft-alvestrand-mmusic-msid-00
isMsId = true;
pSource->msId = value;
} else if(key=="mslabel") // draft-alvestrand-rtcweb-mid-01
pSource->msLabel = value;
else if(key=="label") // draft-alvestrand-rtcweb-mid-01
pSource->label = value;
else
WARN("Media source attribute ",key," unknown");
} else if(key=="ssrc") // a=ssrc:<ssrc-id>
pSource = &sources[NumberParser::parseUnsigned(key)];// a=ssrc:<ssrc-id> <attribute>
else if(key=="rtcp-mux")
pMedia->rtcpMux = true;
else if(key=="mid") // RFC 3388, a=mid:<token>
pMedia->mid = value;
else if(key=="ssrc-group") // a=ssrc-group:<semantics>
pSourceGroupe = &sourceGroupes[value];
else if(key="crypto") { // a=crypto:<tag> <crypto-suite> <key-params> [<session-params>]
StringTokenizer values(value," ",StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
poco_assert(values.size()>2)
pMedia->cryptoTag =
} else */
WARN("Media attribute ",key," unknown");
} else if(pFields)
pFields->emplace_back(st);
else if(!fingerHash.empty())
int i=0; // TODO finger = talk_base::SSLFingerprint::CreateFromRfc4572(fingerHash, field);
else if(key=="group") // RFC 5888 and draft-holmberg-mmusic-sdp-bundle-negotiation-00
pFields = &groups[value];
else if(key=="ice-ufrag")
iceUFrag = value;
else if(key=="ice-pwd")
icePwd = value;
else if(key=="ice-options") {
pFields = &iceOptions;
iceOptions.emplace_back(value);
} else if(key=="fingerprint") // fingerprint:<hash> <algo>
fingerHash = value; // fingerprint:<hash>
else if(key=="msid-semantic")
supportMsId = value=="VMS";
else if(key=="extmap") // RFC 5285 a=extmap:<value>["/"<direction>] <URI> <extensionattributes>
pFields = &extensions[value];
else
WARN("SDP attribute ",key," unknown");
}
} // case 'a':
break;
} // switch(type)
if (ex) {
ex.set(Exception::PROTOCOL, "SDP '",type,"' value ",line," malformed, ",ex.error());
return false;
}
} // for(string& line : lines)
return true;
}