bool SocketAddress::setIntern(Exception& ex,const string& hostAndPort,bool resolveHost) { ASSERT_RETURN(!hostAndPort.empty(),false); string host, port; auto it = hostAndPort.begin(); auto& end = hostAndPort.end(); if (*it == '[') { ++it; while (it != end && *it != ']') host += *it++; if (it == end) { ex.set(Exception::NETADDRESS,"Malformed IPv6 address ", hostAndPort); return false; } ++it; } else { while (it != end && *it != ':') host += *it++; } if (it != end && *it == ':') { ++it; while (it != end) port += *it++; } else { ex.set(Exception::NETADDRESS, "Missing port number in ", hostAndPort); return false; } return setIntern(ex,host, resolveService(ex,port),resolveHost); }
bool SocketAddress::setIntern(Exception& ex,const string& host, UInt16 port,bool resolveHost) { IPAddress ip; Exception ignore; if (ip.set(ignore, host)) { set(ip, port); return true; } HostEntry entry; if (!resolveHost) { if (ignore) ex.set(ignore); return false; } if (!DNS::HostByName(ex, host, entry)) return false; auto& addresses = entry.addresses(); if (addresses.size() > 0) { // if we get both IPv4 and IPv6 addresses, prefer IPv4 for (const IPAddress& address : addresses) { if (address.family() == IPAddress::IPv4) { set(address, port); return true; } } set(addresses.front(), port); return true; } ex.set(Exception::NETADDRESS, "No address found for the host ", host); return false; }
bool FileSystem::Remove(Exception& ex,const char* path,bool all) { bool isFolder(IsFolder(path)); if (all && isFolder) { FileSystem::ForEach forEach([&ex](const string& filePath){ Remove(ex, filePath, true); }); Exception ignore; Paths(ignore, path, forEach); // if exception it's a not existent folder } if (!Exists(path)) return !ex;; // already removed! #if defined(_WIN32) if (isFolder) { wchar_t wFile[_MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, path, -1, wFile, _MAX_PATH); if (RemoveDirectoryW(wFile)==0) ex.set(Exception::FILE, "Impossible to remove folder ", path); } else { wchar_t wFile[_MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, path, -1, wFile, _MAX_PATH); if(_wremove(wFile) != 0) ex.set(Exception::FILE, "Impossible to remove file ", path); } return !ex; #endif if (remove(path) == 0) return !ex; if (isFolder) ex.set(Exception::FILE, "Impossible to remove folder ", path); else ex.set(Exception::FILE, "Impossible to remove file ", path); return false; }
UInt32 FileSystem::Paths(Exception& ex, const char* path, const ForEach& forEach) { int err = 0; string directory(path); FileSystem::MakeDirectory(directory); UInt32 count(0); string pathFile; #if defined(_WIN32) directory.append("*"); wchar_t wDirectory[_MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, directory.c_str(), -1, wDirectory, _MAX_PATH); WIN32_FIND_DATAW fileData; HANDLE fileHandle = FindFirstFileW(wDirectory, &fileData); if (fileHandle == INVALID_HANDLE_VALUE) { if ((err = GetLastError()) != ERROR_NO_MORE_FILES) { ex.set(Exception::FILE, "The system cannot find the directory ", path); return count; } return count; } do { if (wcscmp(fileData.cFileName, L".") != 0 && wcscmp(fileData.cFileName, L"..") != 0) { ++count; String::Append(MakeDirectory(pathFile.assign(path)), fileData.cFileName); if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) pathFile.append("/"); forEach(pathFile); } } while (FindNextFileW(fileHandle, &fileData) != 0); FindClose(fileHandle); #else DIR* pDirectory = opendir(directory.c_str()); if (!pDirectory) { ex.set(Exception::FILE, "The system cannot find the directory ",directory); return count; } struct dirent* pEntry(NULL); while((pEntry = readdir(pDirectory))) { if (strcmp(pEntry->d_name, ".")!=0 && strcmp(pEntry->d_name, "..")!=0) { ++count; String::Append(pathFile.assign(directory), pEntry->d_name); // Cross-platform solution when DT_UNKNOWN or symbolic link if(pEntry->d_type==DT_DIR) pathFile.append("/"); else if(pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK) { Status status; Stat(pathFile, status); if ((status.st_mode&S_IFMT) == S_IFDIR) pathFile.append("/"); } forEach(pathFile); } } closedir(pDirectory); #endif return count; }
bool LUAXML::LUAToXML(Exception& ex, lua_State* pState, int index, const PoolBuffers& poolBuffers) { // index - LUA XML table if (!lua_istable(pState, index)) { ex.set(Exception::APPLICATION, "Just LUA table can be convert to XML"); return false; } PacketWriter writer(poolBuffers); const char* name(NULL); bool result(false); lua_pushnil(pState); // first key while (lua_next(pState, index) != 0) { // uses 'key' (at index -2) and 'value' (at index -1) if (lua_type(pState, -2) == LUA_TSTRING) { name = lua_tostring(pState, -2); if (lua_istable(pState, -1)) { // information fields { xml = {version = 1.0}, ... } writer.write("<?").write(name).write(" "); lua_pushnil(pState); // first key while (lua_next(pState, -2) != 0) { // uses 'key' (at index -2) and 'value' (at index -1) if (lua_type(pState, -2) == LUA_TSTRING && lua_isstring(pState, -1)) writer.write(lua_tostring(pState, -2)).write("=\"").write(lua_tostring(pState, -1)).write("\" "); else ex.set(Exception::APPLICATION, "Bad ", name, " XML attribute information, key must be string and value convertible to string"); lua_pop(pState, 1); } writer.write("?>"); } else ex.set(Exception::APPLICATION, "Bad ",name," XML information, value must be a table"); } else if (lua_isnumber(pState, -2)) { if(lua_istable(pState, -1)) result = LUAToXMLElement(ex, pState, writer); else ex.set(Exception::APPLICATION, "Impossible to write inner XML data on the top of XML level"); } else ex.set(Exception::APPLICATION, "Impossible to convert the key of type ",lua_typename(pState,lua_type(pState,-2)),"to a correct XML root element"); lua_pop(pState, 1); } if (result) lua_pushlstring(pState,STR writer.data(), writer.size()); return result; }
bool SocketSender::run(Exception& ex) { if (!_pSocket) { ex.set(Exception::SOCKET, "SocketSender ", name, " started in parallel without pointer of socket"); return false; } // send Exception exc; shared_ptr<SocketSender> pThis(_pThis); _pSocket->send(exc, pThis); if (exc.code() != Exception::ASSERT) ex.set(exc); return true; }
UInt32 FileSystem::GetSize(Exception& ex,const char* path) { Status status; status.st_size = 0; string file(path); size_t oldSize(file.size()); if (Stat(MakeFile(file).c_str(), status) != 0 || status.st_mode&S_IFDIR) { ex.set(Exception::FILE, "File ", path, " doesn't exist"); return 0; } if (oldSize>file.size()) { // if was a folder ex.set(Exception::FILE, "GetSize works just on file, and ", path, " is a folder"); return 0; } return (UInt32)status.st_size; }
WinRegistryKey::Type WinRegistryKey::type(Exception& ex,const string& name) { if (!open(ex)) return REGT_NONE; DWORD type = REG_NONE; DWORD size; if (RegQueryValueExA(_hKey, name.c_str(), NULL, &type, NULL, &size) != ERROR_SUCCESS) { ex.set(Exception::REGISTRY, "Key ", key(name), " not found"); return REGT_NONE; } if (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_DWORD) { ex.set(Exception::REGISTRY, key(name), ", type not supported"); return REGT_NONE; } return (Type)type; }
bool RTMFPCookieComputing::run(Exception& ex) { // First execution is for the DH computing if pDH == null, else it's to compute Diffie-Hellman keys if (!_diffieHellman.initialized()) return _diffieHellman.initialize(ex); // Compute Diffie-Hellman secret _diffieHellman.computeSecret(ex,initiatorKey.data(),initiatorKey.size(),_sharedSecret); if (ex) return false; if (packet.size() > 0) { ex.set(Exception::CRYPTO, "RTMFPCookieComputing already executed"); return false; } // string hex; // DEBUG("Shared Secret : ", Util::FormatHex(_sharedSecret.data(), _sharedSecret.size(), hex)); // It's our key public part int size = _diffieHellman.publicKeySize(ex); if (size<0) { if (!ex) ex.set(Exception::CRYPTO, "DH public key not initialized"); return false; } packet.write7BitLongValue(size+11); UInt32 noncePos = packet.size(); packet.writeRaw(EXPAND_DATA_SIZE("\x03\x1A\x00\x00\x02\x1E\x00")); UInt8 byte2 = DH_KEY_SIZE-size; if(byte2>2) { CRITIC("Generation DH key with less of 126 bytes!"); byte2=2; } packet.write8(0x81); packet.write8(2-byte2); packet.write8(0x0D); packet.write8(0x02); if (size>2000) ERROR("RTMFP diffie hellman public key with an error size key of ",size) // TODO remove this log one time fixed! _diffieHellman.readPublicKey(ex,packet.buffer(size)); packet.write8(0x58); // Compute Keys RTMFP::ComputeAsymetricKeys(_sharedSecret,initiatorNonce.data(),initiatorNonce.size(),packet.data()+noncePos,size+11,decryptKey,encryptKey); waitHandle(); return true; }
bool HTTPSender::run(Exception& ex) { if (!_pRequest && (!_pWriter || _sizePos>0)) { // accept just HTTPSender::writeRaw call, for media streaming ex.set(Exception::PROTOCOL, "No HTTP request to send the reply"); return false; } if (!_pWriter) { //// GET FILE Time time; // Not Modified => don't send the file if (_file.lastModified()>0 && _pRequest->ifModifiedSince >= _file.lastModified()) { write("304 Not Modified", HTTP::CONTENT_ABSENT); } else { if (_file.lastModified()==0) { // file doesn't exist, test directory string dir(_file.fullPath()); if (FileSystem::Exists(FileSystem::MakeDirectory(dir))) { // Redirect to the real path of directory DataWriter& response = write("301 Moved Permanently"); // TODO check that it happens sometimes or never! BinaryWriter& writer = response.packet; String::Format(_buffer, "http://", _pRequest->serverAddress, _file.path(), '/'); HTTP_BEGIN_HEADER(writer) HTTP_ADD_HEADER(writer, "Location", _buffer) HTTP_END_HEADER(writer) HTML_BEGIN_COMMON_RESPONSE(writer, "Moved Permanently") writer.writeRaw("The document has moved <a href=\"", _buffer, "\">here</a>."); HTML_END_COMMON_RESPONSE(writer, _buffer) } else writeError(404, String::Format(_buffer,"File ", _file.path(), " doesn't exist")); } else {
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
bool LUAIPAddress::Read(Exception& ex, lua_State *pState, int index, IPAddress& address,bool withDNS) { if (lua_type(pState, index)==LUA_TSTRING) // lua_type because can be encapsulated in a lua_next return withDNS ? address.setWithDNS(ex, lua_tostring(pState,index)) : address.set(ex, lua_tostring(pState,index)); if(lua_istable(pState,index)) { bool isConst; IPAddress* pOther = Script::ToObject<IPAddress>(pState, isConst, index); if (pOther) { address.set(*pOther); return true; } SocketAddress* pAddress = Script::ToObject<SocketAddress>(pState, isConst, index); if (pAddress) { address.set(pAddress->host()); return true; } ServerConnection* pServer = Script::ToObject<ServerConnection>(pState, isConst, index); if (pServer) { address.set(pServer->address.host()); return true; } } ex.set(Exception::NETADDRESS, "No valid IPAddress available to read"); return false; }
ADD_TEST(DateTest, ParseISO8601Frac) { CHECK(Parse("2005-01-08T12:30:00.1Z", 2005, 1, 8,6, 12, 30, 0, 100, Date::GMT)); CHECK(_Date.toString(Date::ISO8601_FRAC_FORMAT, _Out) == "2005-01-08T12:30:00.100Z"); CHECK(Parse("2005-01-08T12:30:00.123+01:00", 2005, 1, 8,6, 12, 30, 0, 123, 3600000)); CHECK(_Date.toString(Date::ISO8601_FRAC_FORMAT, _Out) == "2005-01-08T12:30:00.123+01:00"); CHECK(Parse("2005-01-08T12:30:00Z", 2005, 1, 8,6, 12, 30, 0, 0, Date::GMT)); CHECK(_Date.toString(Date::ISO8601_FRAC_FORMAT, _Out) == "2005-01-08T12:30:00.000Z"); CHECK(Parse("2005-01-08T12:30:00+01:00", 2005, 1, 8,6, 12, 30, 0, 0, 3600000)); CHECK(_Date.toString(Date::ISO8601_FRAC_FORMAT, _Out) == "2005-01-08T12:30:00.000+01:00"); CHECK(Parse("2014-04-22T06:00:00.000+02:00", 2014, 4, 22, 2, 6, 0, 0, 0, 7200000)); CHECK(_Date.toString(Date::ISO8601_FRAC_FORMAT, _Out) == "2014-04-22T06:00:00.000+02:00"); CHECK(!Ex); CHECK(Parse("2005-01-08T12:30:00.12345-01:00", 2005, 1, 8,6, 12, 30, 0, 123, -3600000)); CHECK(_Date.toString(Date::ISO8601_FRAC_FORMAT, _Out) == "2005-01-08T12:30:00.123-01:00"); CHECK(Parse("2010-09-23T16:17:01.2817002+02:00", 2010, 9, 23, 4, 16, 17, 1, 281, 7200000)); CHECK(_Date.toString(Date::ISO8601_FRAC_FORMAT, _Out) == "2010-09-23T16:17:01.281+02:00"); CHECK(Parse("2005-01-08T12:30:00.123456", 2005, 1, 8,6, 12, 30, 0, 123, Date::LOCAL)); CHECK(Parse("2005-01-08T12:30:00.012034", 2005, 1, 8,6, 12, 30, 0, 12, Date::LOCAL)); _Date.setOffset(4020000); CHECK(_Date.offset()==4020000); CHECK(_Date.toString(Date::ISO8601_FRAC_FORMAT, _Out) == "2005-01-08T12:30:00.012+01:07"); CHECK(Ex); // warning on microsecond lost information Ex.set(Exception::NIL); }
bool LUAXML::LUAToXMLElement(Exception& ex, lua_State* pState, PacketWriter& writer) { // -1 => table lua_pushstring(pState, "__name"); lua_rawget(pState, -2); const char* name(lua_tostring(pState, -1)); lua_pop(pState, 1); if (!name) { ex.set(Exception::APPLICATION, "Impossible to write a XML element without name (__name)"); return false; } // write attributes writer.write("<").write(name).write(" "); lua_pushnil(pState); // first key while (lua_next(pState, -2) != 0) { // uses 'key' (at index -2) and 'value' (at index -1) if (lua_type(pState, -2) == LUA_TSTRING && strcmp(lua_tostring(pState, -2),"__name")!=0 && lua_isstring(pState, -1)) writer.write(lua_tostring(pState, -2)).write("=\"").write(lua_tostring(pState, -1)).write("\" "); lua_pop(pState, 1); } if (lua_objlen(pState, -1) == 0) { writer.write("/>"); return true; } writer.write(">"); // write elements lua_pushnil(pState); // first key while (lua_next(pState, -2) != 0) { // uses 'key' (at index -2) and 'value' (at index -1) if (lua_isnumber(pState, -2)) { if (lua_istable(pState, -1)) LUAToXMLElement(ex, pState, writer); // table child else if (lua_isstring(pState, -1)) writer.write(lua_tostring(pState, -1), lua_objlen(pState, -1)); // __value else ex.set(Exception::APPLICATION, "Impossible to convert the value of type ", lua_typename(pState, lua_type(pState, -1)), "to a correct XML value of ",name); } else if (lua_type(pState, -2) != LUA_TSTRING) ex.set(Exception::APPLICATION, "Impossible to convert the key of type ",lua_typename(pState,lua_type(pState,-2)),"to a correct XML element of ",name); lua_pop(pState, 1); } writer.write("</").write(name).write(">"); return true; }
bool RTMFP::Decode(Exception& ex,RTMFPEngine& aesDecrypt,PacketReader& packet) { // Decrypt aesDecrypt.process(packet.current(),(UInt8*)packet.current(),packet.available()); bool result = ReadCRC(packet); if (!result) ex.set(Exception::CRYPTO, "Bad RTMFP CRC sum computing"); return result; }
bool WinRegistryKey::setString(Exception& ex, const string& name, const string& value) { if (!open(ex)) return false; if (RegSetValueExA(_hKey, name.c_str(), 0, REG_SZ, (CONST BYTE*) value.c_str(), (DWORD) value.size() + 1) == ERROR_SUCCESS) return true; ex.set(Exception::REGISTRY, "Failed to set registry value ", key(name)); return false; }
bool WinRegistryKey::setInt(Exception& ex,const string& name, int value) { if (!open(ex)) return false; DWORD data = value; if (RegSetValueExA(_hKey, name.c_str(), 0, REG_DWORD, (CONST BYTE*) &data, sizeof(data)) == ERROR_SUCCESS) return true; ex.set(Exception::REGISTRY, "Failed to set registry value ", key(name)); return false; }
void TCPClient::onReadable(Exception& ex,UInt32 available) { if (available == 0) { close(); // Graceful disconnection return; } lock_guard<recursive_mutex> lock(_mutex); if(available>(_pBuffer->size() - _rest)) _pBuffer->resize(_rest+available,true); Exception exRecv; int received = _socket.receiveBytes(exRecv,_pBuffer->data()+_rest, available); if (received <= 0) { if (exRecv) onError(exRecv); // to be before onDisconnection! close(); // Graceful disconnection return; } else if (exRecv) ex.set(exRecv); // received > 0, so WARN _rest += received; while (_rest > 0) { _pBuffer->resize(_rest,true); UInt32 rest = onReception(_pBuffer); // To prevent the case where the buffer has been manipulated during onReception call if(_pBuffer.empty()) rest = 0; else if (_pBuffer->size() < _rest) _rest = _pBuffer->size(); if (rest > _rest) rest = _rest; if (rest == 0) { // has consumed all _pBuffer.release(); _rest = 0; break; } if (_rest == rest) // no new bytes consumption, wait next reception break; // has consumed few bytes (but not all) // 0 < rest < _rest <= _pBuffer->size() memmove(_pBuffer->data(), _pBuffer->data() + (_rest - rest), rest); // move to the beginning _rest = rest; } }
int WinRegistryKey::getInt(Exception& ex,const string& name) { if (!open(ex)) return 0; int value(0); DWORD type; DWORD size = sizeof(value); if (RegQueryValueExA(_hKey, name.c_str(), NULL, &type, (BYTE*)&value, &size) == ERROR_SUCCESS && type == REG_DWORD) return value; ex.set(Exception::REGISTRY, "Key ", key(name), " not found"); return 0; }
bool TCPClient::connect(Exception& ex,const SocketAddress& address) { lock_guard<recursive_mutex> lock(_mutex); if (_disconnecting) { ex.set(Exception::SOCKET, "TCPClient is always connected to ", _peerAddress.toString(), ", call disconnect() before, and wait onDisconnection event"); return false; } _connected = _socket.connect(ex, address); if (!_connected) return false; _peerAddress.set(address); return true; }
bool DNS::HostName(Exception& ex,string& host) { if(!Net::InitializeNetwork(ex)) return false; char buffer[256]; int rc = gethostname(buffer, sizeof(buffer)); if (rc == 0) { host.assign(buffer); return true; } ex.set(Exception::NETADDRESS,"Cannot get host name"); return false; }
UInt16 SocketAddress::resolveService(Exception& ex,const string& service) { UInt16 port=0; if (String::ToNumber<UInt16>(service,port)) return port; if (!Net::InitializeNetwork(ex)) return 0; struct servent* se = getservbyname(service.c_str(), NULL); if (se) return ntohs(se->s_port); ex.set(Exception::NETADDRESS, "Service ", service, " unknown"); return 0; }
bool Net::InitializeNetwork(Exception& ex) { lock_guard<mutex> lock(Mutex); if (Initialized) return true; WORD version = MAKEWORD(2, 2); WSADATA data; if (WSAStartup(version, &data) != 0) { ex.set(Exception::NETWORK, "Failed to initialize network subsystem"); return false; } return Initialized = true; }
bool WinRegistryKey::open(Exception& ex) { if (_hKey) return true; if (_readOnly) { if (RegOpenKeyExA(_hRootKey, _subKey.c_str(), 0, KEY_READ | _extraSam, &_hKey) == ERROR_SUCCESS) return true; } else { if (RegCreateKeyExA(_hRootKey, _subKey.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE | _extraSam, NULL, &_hKey, NULL) == ERROR_SUCCESS) return true; } ex.set(Exception::REGISTRY,"Cannot open registry ", key()); return false; }
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); }
void FileSystem::CreateDirectories(Exception& ex,const string& path) { vector<string> directories; if (Unpack(path, directories).empty()) return; string dir; if (directories.front().size()==2 && directories.front().back() == ':') { // device dir.append(directories.front()); directories.erase(directories.begin()); } for (const string& directory : directories) { dir.append("/"); dir.append(directory); if (!CreateDirectory(dir)) { ex.set(Exception::FILE, "Impossible to create ", dir, " directory"); return; } } }
void TCPClient::receive(Exception& ex, UInt32 available) { if (available>0) onSending(0); // to update _idleTime if (available == 0) { close(); // Graceful disconnection return; } UInt32 size(_pBuffer->size()); _pBuffer->resize(size+available,true); Exception exRecv; int received = _socket.receiveBytes(exRecv,_pBuffer->data()+size, available); if (received <= 0) { if (exRecv) OnError::raise(exRecv); // to be before onDisconnection! close(); // Graceful disconnection return; } else if (exRecv) ex.set(exRecv); // received > 0, so WARN _pBuffer->resize(size+received,true); size = 0; while(size<_pBuffer->size()) { // while everything is not consumed if (size) _pBuffer->clip(size); size = OnData::raise<0xFFFFFFFF>(_pBuffer); // consumed if (!size) // if no consumption return; // no release here } _pBuffer.release(); }
bool SDP::build(Exception& ex, const char* text) { SDPMedia* pMedia = NULL; String::ForEach forEach([this,&pMedia,&ex](UInt32 index,const char* line){ if(strlen(line)==0 || line[1] != '=') { ex.set(Exception::FORMATTING, "SDP line ",line," malformed, second byte isn't an equal sign"); return false; } UInt8 type = line[0]; line = String::TrimLeft(line); // RFC 4566 switch(type) { case 'v': // v= (protocol version) version = String::ToNumber<UInt32>(ex, line); break; case 'o': { // o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address> String::ForEach forEach([&ex,this](UInt32 index, const char* value) { switch (index) { case 0: user.assign(value); break; case 1: sessionId = String::ToNumber<UInt32>(ex, value); break; case 2: sessionVersion = String::ToNumber<UInt32>(ex, value); break; case 4: unicastAddress.set(IPAddress::Wildcard(String::ICompare(value,"IP6")==0 ? IPAddress::IPv6 : IPAddress::IPv4)); break; case 5: unicastAddress.set(ex,value,unicastAddress.family()); break; } return !ex; }); if(String::Split(line, " ", forEach, String::SPLIT_IGNORE_EMPTY | String::SPLIT_TRIM)<6) ex.set(Exception::PROTOCOL, "SDP o line required 6 values (<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>)"); break; } case 's': // s= (session name) sessionName = line; break; /// Optional lines case 'i': // i=* (session information) sessionInfos = line; break; case 'u': // u=* (URI of description) uri = line; break; case 'e': // e=* (email address) email = line; break; case 'p': // p=* (phone number) phone = line; break; case 'c': { // c=* (connection information -- not required if included in all media) IPAddress defaultAddress; // TODO defaultAddress is useless for what? String::ForEach forEach([&ex,&defaultAddress, this](UInt32 index, const char* value) { switch (index) { case 1: defaultAddress.set(IPAddress::Wildcard(String::ICompare(value,"IP6")==0 ? IPAddress::IPv6 : IPAddress::IPv4)); break; case 2: defaultAddress.set(ex,value,defaultAddress.family()); break; } return !ex; }); if(String::Split(line, " ", forEach, String::SPLIT_IGNORE_EMPTY | String::SPLIT_TRIM)<3) ex.set(Exception::PROTOCOL, "SDP c line required 3 values"); break; } case 'b': // b=* (zero or more bandwidth information lines) // TODO useless? break; // One or more time descriptions ("t=" and "r=" lines; see below) // t= (time the session is active) // r=* (zero or more repeat times) case 't': // TODO useless? break; case 'r': // TODO useless? break; case 'z': // z=* (time zone adjustments) // TODO useless? break; case 'k': // k=* (encryption key) encryptKey = line; break; case 'm': { // m=<name> <port> <proto> <fmt> string name; UInt16 port; String::ForEach forEach([&ex, &pMedia, &name, &port, this](UInt32 index, const char* value) { switch (index) { case 0: name = value; break; case 1: port = String::ToNumber<UInt16>(ex, value); break; case 2: pMedia = addMedia(name, port, value); break; } return !ex; }); if(String::Split(line, " ", forEach, String::SPLIT_IGNORE_EMPTY | String::SPLIT_TRIM)<4) ex.set(Exception::PROTOCOL, "SDP m line required 4 values (<name> <port> <proto> <fmt>)"); 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; String::ForEach forEach([&ex, &pMedia, &pFields, &isMsId, &fingerHash, this](UInt32 index, const char* value) { // 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");*/ ERROR("TODO") } else if(pFields) pFields->emplace_back(value); else if(!fingerHash.empty()) int i=0; // TODO finger = talk_base::SSLFingerprint::CreateFromRfc4572(fingerHash, field); else { const char* key(value); const char* value(String::Empty.c_str()); const char* colon(strchr(value,':')); if (colon) { *(char*)colon = 0; value = colon + 1; } if (String::ICompare(key,"group")==0) // RFC 5888 and draft-holmberg-mmusic-sdp-bundle-negotiation-00 pFields = &groups[value]; else if (String::ICompare(key,"ice-ufrag")==0) iceUFrag = value; else if (String::ICompare(key,"ice-pwd")==0) icePwd = value; else if (String::ICompare(key,"ice-options")==0) { pFields = &iceOptions; iceOptions.emplace_back(value); } else if (String::ICompare(key,"fingerprint")==0) // fingerprint:<hash> <algo> fingerHash = value; // fingerprint:<hash> else if (String::ICompare(key,"msid-semantic")==0) supportMsId = String::ICompare(value ,"VMS")==0; else if (String::ICompare(key,"extmap")==0) // RFC 5285 a=extmap:<value>["/"<direction>] <URI> <extensionattributes> pFields = &extensions[value]; else WARN("SDP attribute ", key, " unknown"); } return true; }); String::Split(line, " ", forEach, String::SPLIT_IGNORE_EMPTY | String::SPLIT_TRIM); break; } // case 'a': } // switch(type)
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(); }
Type String::ToNumber(Exception& ex, Type failValue, const char* value, size_t size) { int digit = 1, comma = 0; bool beginning = true, negative = false; long double result(0); bool isSigned = numeric_limits<Type>::is_signed; Type max = numeric_limits<Type>::max(); const char* current(value); if (size == string::npos) size = strlen(value); while(current && size-->0) { if (iscntrl(*current) || *current==' ') { if (beginning) { ++current; continue; } ex.set(Exception::FORMATTING, value, " is not a correct number"); return failValue; } if (*current == '-') { if (isSigned && beginning && !negative) { negative = true; ++current; continue; } ex.set(Exception::FORMATTING, value, " is not a correct number"); return failValue; } if (*current == '.' || *current == ',') { if (comma == 0 && !beginning) { comma = 1; ++current; continue; } ex.set(Exception::FORMATTING, value, " is not a correct number"); return failValue; } if (beginning) beginning = false; if (isdigit(*current) == 0) { ex.set(Exception::FORMATTING, value, " is not a correct number"); return failValue; } result = result * 10 + (*current - '0'); comma *= 10; ++current; } if (beginning) { ex.set(Exception::FORMATTING, "Empty string is not a number"); return failValue; } if (comma > 0) result /= comma; if (result > max) { ex.set(Exception::FORMATTING, value, " exceeds maximum number capacity"); return failValue; } if (negative) result *= -1; return (Type)result; }