1537ff140SPatrick Venture #include "config.h" 2537ff140SPatrick Venture 3537ff140SPatrick Venture #include "endian.hpp" 407c462acSRatan Gupta #include "slp.hpp" 5537ff140SPatrick Venture #include "slp_meta.hpp" 607c462acSRatan Gupta 707c462acSRatan Gupta #include <arpa/inet.h> 8ead7a3caSRatan Gupta #include <dirent.h> 907c462acSRatan Gupta #include <ifaddrs.h> 1007c462acSRatan Gupta #include <net/if.h> 1107c462acSRatan Gupta #include <string.h> 1207c462acSRatan Gupta 1307c462acSRatan Gupta #include <algorithm> 1407c462acSRatan Gupta 1507c462acSRatan Gupta namespace slp 1607c462acSRatan Gupta { 1707c462acSRatan Gupta namespace handler 1807c462acSRatan Gupta { 1907c462acSRatan Gupta 2007c462acSRatan Gupta namespace internal 2107c462acSRatan Gupta { 2207c462acSRatan Gupta 2307c462acSRatan Gupta buffer prepareHeader(const Message& req) 2407c462acSRatan Gupta { 25537ff140SPatrick Venture uint8_t length = 26537ff140SPatrick Venture slp::header::MIN_LEN + /* 14 bytes for header */ 2707c462acSRatan Gupta req.header.langtag.length() + /* Actual length of lang tag */ 2807c462acSRatan Gupta slp::response::SIZE_ERROR; /* 2 bytes for error code */ 2907c462acSRatan Gupta 3007c462acSRatan Gupta buffer buff(length, 0); 3107c462acSRatan Gupta 3207c462acSRatan Gupta buff[slp::header::OFFSET_VERSION] = req.header.version; 3307c462acSRatan Gupta 3407c462acSRatan Gupta // will increment the function id from 1 as reply 3507c462acSRatan Gupta buff[slp::header::OFFSET_FUNCTION] = req.header.functionID + 1; 3607c462acSRatan Gupta 3707c462acSRatan Gupta std::copy_n(&length, slp::header::SIZE_LENGTH, 38537ff140SPatrick Venture buff.data() + slp::header::OFFSET_LENGTH); 3907c462acSRatan Gupta 4007c462acSRatan Gupta auto flags = endian::to_network(req.header.flags); 4107c462acSRatan Gupta 4207c462acSRatan Gupta std::copy_n((uint8_t*)&flags, slp::header::SIZE_FLAGS, 43537ff140SPatrick Venture buff.data() + slp::header::OFFSET_FLAGS); 4407c462acSRatan Gupta 4507c462acSRatan Gupta std::copy_n(req.header.extOffset.data(), slp::header::SIZE_EXT, 46537ff140SPatrick Venture buff.data() + slp::header::OFFSET_EXT); 4707c462acSRatan Gupta 4807c462acSRatan Gupta auto xid = endian::to_network(req.header.xid); 4907c462acSRatan Gupta 5007c462acSRatan Gupta std::copy_n((uint8_t*)&xid, slp::header::SIZE_XID, 51537ff140SPatrick Venture buff.data() + slp::header::OFFSET_XID); 5207c462acSRatan Gupta 5307c462acSRatan Gupta uint16_t langtagLen = req.header.langtag.length(); 5407c462acSRatan Gupta langtagLen = endian::to_network(langtagLen); 5507c462acSRatan Gupta std::copy_n((uint8_t*)&langtagLen, slp::header::SIZE_LANG, 56537ff140SPatrick Venture buff.data() + slp::header::OFFSET_LANG_LEN); 5707c462acSRatan Gupta 58537ff140SPatrick Venture std::copy_n((uint8_t*)req.header.langtag.c_str(), 59537ff140SPatrick Venture req.header.langtag.length(), 60537ff140SPatrick Venture buff.data() + slp::header::OFFSET_LANG); 6107c462acSRatan Gupta return buff; 6207c462acSRatan Gupta } 6307c462acSRatan Gupta 64537ff140SPatrick Venture std::tuple<int, buffer> processSrvTypeRequest(const Message& req) 6507c462acSRatan Gupta { 6607c462acSRatan Gupta /* 6707c462acSRatan Gupta 0 1 2 3 6807c462acSRatan Gupta 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 6907c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 7007c462acSRatan Gupta | Service Location header (function = SrvTypeRply = 10) | 7107c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 7207c462acSRatan Gupta | Error Code | length of <srvType-list> | 7307c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 7407c462acSRatan Gupta | <srvtype--list> \ 7507c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 7607c462acSRatan Gupta */ 7707c462acSRatan Gupta 7807c462acSRatan Gupta buffer buff; 7907c462acSRatan Gupta 8007c462acSRatan Gupta // read the slp service info from conf and create the service type string 8107c462acSRatan Gupta slp::handler::internal::ServiceList svcList = 82ead7a3caSRatan Gupta slp::handler::internal::readSLPServiceInfo(); 8307c462acSRatan Gupta if (svcList.size() <= 0) 8407c462acSRatan Gupta { 8507c462acSRatan Gupta buff.resize(0); 860d3e9e33SRatan Gupta std::cerr << "SLP unable to read the service info\n"; 8707c462acSRatan Gupta return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff); 8807c462acSRatan Gupta } 8907c462acSRatan Gupta 9007c462acSRatan Gupta std::string service; 9107c462acSRatan Gupta bool firstIteration = true; 9207c462acSRatan Gupta for_each(svcList.cbegin(), svcList.cend(), 93537ff140SPatrick Venture [&service, &firstIteration](const auto& svc) { 9407c462acSRatan Gupta if (firstIteration == true) 9507c462acSRatan Gupta { 9607c462acSRatan Gupta service = svc.first; 9707c462acSRatan Gupta firstIteration = false; 9807c462acSRatan Gupta } 9907c462acSRatan Gupta else 10007c462acSRatan Gupta { 10107c462acSRatan Gupta service += ","; 10207c462acSRatan Gupta service += svc.first; 10307c462acSRatan Gupta } 10407c462acSRatan Gupta }); 10507c462acSRatan Gupta 10607c462acSRatan Gupta buff = prepareHeader(req); 10707c462acSRatan Gupta 10807c462acSRatan Gupta /* Need to modify the length and the function type field of the header 10907c462acSRatan Gupta * as it is dependent on the handler of the service */ 11007c462acSRatan Gupta 11107c462acSRatan Gupta std::cout << "service=" << service.c_str() << "\n"; 11207c462acSRatan Gupta 11307c462acSRatan Gupta uint8_t length = buff.size() + /* 14 bytes header + length of langtag */ 11407c462acSRatan Gupta slp::response::SIZE_ERROR + /* 2 byte err code */ 11507c462acSRatan Gupta slp::response::SIZE_SERVICE + /* 2 byte srvtype len */ 11607c462acSRatan Gupta service.length(); 11707c462acSRatan Gupta 11807c462acSRatan Gupta buff.resize(length); 11907c462acSRatan Gupta 12007c462acSRatan Gupta std::copy_n(&length, slp::header::SIZE_LENGTH, 121537ff140SPatrick Venture buff.data() + slp::header::OFFSET_LENGTH); 12207c462acSRatan Gupta 12307c462acSRatan Gupta /* error code is already set to 0 moving to service type len */ 12407c462acSRatan Gupta 12507c462acSRatan Gupta uint16_t serviceTypeLen = service.length(); 12607c462acSRatan Gupta serviceTypeLen = endian::to_network(serviceTypeLen); 12707c462acSRatan Gupta 12807c462acSRatan Gupta std::copy_n((uint8_t*)&serviceTypeLen, slp::response::SIZE_SERVICE, 129537ff140SPatrick Venture buff.data() + slp::response::OFFSET_SERVICE_LEN); 13007c462acSRatan Gupta 13107c462acSRatan Gupta /* service type data */ 13207c462acSRatan Gupta std::copy_n((uint8_t*)service.c_str(), service.length(), 133537ff140SPatrick Venture (buff.data() + slp::response::OFFSET_SERVICE)); 13407c462acSRatan Gupta 13507c462acSRatan Gupta return std::make_tuple(slp::SUCCESS, buff); 13607c462acSRatan Gupta } 13707c462acSRatan Gupta 138537ff140SPatrick Venture std::tuple<int, buffer> processSrvRequest(const Message& req) 13907c462acSRatan Gupta { 14007c462acSRatan Gupta /* 14107c462acSRatan Gupta Service Reply 14207c462acSRatan Gupta 0 1 2 3 14307c462acSRatan Gupta 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 14407c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 14507c462acSRatan Gupta | Service Location header (function = SrvRply = 2) | 14607c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 14707c462acSRatan Gupta | Error Code | URL Entry count | 14807c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 14907c462acSRatan Gupta | <URL Entry 1> ... <URL Entry N> \ 15007c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 15107c462acSRatan Gupta 15207c462acSRatan Gupta URL Entry 15307c462acSRatan Gupta 0 1 2 3 15407c462acSRatan Gupta 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 15507c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 15607c462acSRatan Gupta | Reserved | Lifetime | URL Length | 15707c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 15807c462acSRatan Gupta |URL len, contd.| URL (variable length) \ 15907c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 16007c462acSRatan Gupta |# of URL auths | Auth. blocks (if any) \ 16107c462acSRatan Gupta +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 16207c462acSRatan Gupta */ 16307c462acSRatan Gupta 16407c462acSRatan Gupta buffer buff; 16507c462acSRatan Gupta // Get all the services which are registered 16607c462acSRatan Gupta slp::handler::internal::ServiceList svcList = 167ead7a3caSRatan Gupta slp::handler::internal::readSLPServiceInfo(); 16807c462acSRatan Gupta if (svcList.size() <= 0) 16907c462acSRatan Gupta { 17007c462acSRatan Gupta buff.resize(0); 1710d3e9e33SRatan Gupta std::cerr << "SLP unable to read the service info\n"; 17207c462acSRatan Gupta return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff); 17307c462acSRatan Gupta } 17407c462acSRatan Gupta 17507c462acSRatan Gupta // return error if serice type doesn't match 17607c462acSRatan Gupta auto& svcName = req.body.srvrqst.srvType; 17707c462acSRatan Gupta auto svcIt = svcList.find(svcName); 17807c462acSRatan Gupta if (svcIt == svcList.end()) 17907c462acSRatan Gupta { 18007c462acSRatan Gupta buff.resize(0); 1810d3e9e33SRatan Gupta std::cerr << "SLP unable to find the service=" << svcName << "\n"; 18207c462acSRatan Gupta return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff); 18307c462acSRatan Gupta } 18407c462acSRatan Gupta // Get all the interface address 18507c462acSRatan Gupta auto ifaddrList = slp::handler::internal::getIntfAddrs(); 18607c462acSRatan Gupta if (ifaddrList.size() <= 0) 18707c462acSRatan Gupta { 18807c462acSRatan Gupta buff.resize(0); 1890d3e9e33SRatan Gupta std::cerr << "SLP unable to read the interface address\n"; 19007c462acSRatan Gupta return std::make_tuple((int)slp::Error::INTERNAL_ERROR, buff); 19107c462acSRatan Gupta } 19207c462acSRatan Gupta 19307c462acSRatan Gupta buff = prepareHeader(req); 19407c462acSRatan Gupta // Calculate the length and resize the buffer 19507c462acSRatan Gupta uint8_t length = buff.size() + /* 14 bytes header + length of langtag */ 19607c462acSRatan Gupta slp::response::SIZE_ERROR + /* 2 bytes error code */ 19707c462acSRatan Gupta slp::response::SIZE_URL_COUNT; /* 2 bytes srvtype len */ 19807c462acSRatan Gupta 19907c462acSRatan Gupta buff.resize(length); 20007c462acSRatan Gupta 20107c462acSRatan Gupta // Populate the url count 20207c462acSRatan Gupta uint16_t urlCount = ifaddrList.size(); 20307c462acSRatan Gupta urlCount = endian::to_network(urlCount); 20407c462acSRatan Gupta 20507c462acSRatan Gupta std::copy_n((uint8_t*)&urlCount, slp::response::SIZE_URL_COUNT, 206537ff140SPatrick Venture buff.data() + slp::response::OFFSET_URL_ENTRY); 20707c462acSRatan Gupta 20807c462acSRatan Gupta // Find the service 20907c462acSRatan Gupta const slp::ConfigData& svc = svcIt->second; 2101f12e380SGunnar Mills // Populate the URL Entries 21107c462acSRatan Gupta auto pos = slp::response::OFFSET_URL_ENTRY + slp::response::SIZE_URL_COUNT; 21207c462acSRatan Gupta for (const auto& addr : ifaddrList) 21307c462acSRatan Gupta { 214*aa902c6eSPatrick Williams std::string url = svc.name + ':' + svc.type + "//" + addr + ',' + 215*aa902c6eSPatrick Williams svc.port; 21607c462acSRatan Gupta 217537ff140SPatrick Venture buff.resize(buff.size() + slp::response::SIZE_URL_ENTRY + url.length()); 21807c462acSRatan Gupta 21907c462acSRatan Gupta uint8_t reserved = 0; 22007c462acSRatan Gupta uint16_t auth = 0; 22107c462acSRatan Gupta uint16_t lifetime = endian::to_network<uint16_t>(slp::LIFETIME); 22207c462acSRatan Gupta uint16_t urlLength = url.length(); 22307c462acSRatan Gupta 22407c462acSRatan Gupta std::copy_n((uint8_t*)&reserved, slp::response::SIZE_RESERVED, 22507c462acSRatan Gupta buff.data() + pos); 22607c462acSRatan Gupta 22707c462acSRatan Gupta pos += slp::response::SIZE_RESERVED; 22807c462acSRatan Gupta 22907c462acSRatan Gupta std::copy_n((uint8_t*)&lifetime, slp::response::SIZE_LIFETIME, 23007c462acSRatan Gupta buff.data() + pos); 23107c462acSRatan Gupta 23207c462acSRatan Gupta pos += slp::response::SIZE_LIFETIME; 23307c462acSRatan Gupta 23407c462acSRatan Gupta urlLength = endian::to_network(urlLength); 23507c462acSRatan Gupta std::copy_n((uint8_t*)&urlLength, slp::response::SIZE_URLLENGTH, 23607c462acSRatan Gupta buff.data() + pos); 23707c462acSRatan Gupta pos += slp::response::SIZE_URLLENGTH; 23807c462acSRatan Gupta 239537ff140SPatrick Venture std::copy_n((uint8_t*)url.c_str(), url.length(), buff.data() + pos); 24007c462acSRatan Gupta pos += url.length(); 24107c462acSRatan Gupta 24207c462acSRatan Gupta std::copy_n((uint8_t*)&auth, slp::response::SIZE_AUTH, 24307c462acSRatan Gupta buff.data() + pos); 24407c462acSRatan Gupta pos += slp::response::SIZE_AUTH; 24507c462acSRatan Gupta } 24607c462acSRatan Gupta uint8_t packetLength = buff.size(); 24707c462acSRatan Gupta std::copy_n((uint8_t*)&packetLength, slp::header::SIZE_VERSION, 248537ff140SPatrick Venture buff.data() + slp::header::OFFSET_LENGTH); 24907c462acSRatan Gupta 25007c462acSRatan Gupta return std::make_tuple((int)slp::SUCCESS, buff); 25107c462acSRatan Gupta } 25207c462acSRatan Gupta 25307c462acSRatan Gupta std::list<std::string> getIntfAddrs() 25407c462acSRatan Gupta { 25507c462acSRatan Gupta std::list<std::string> addrList; 25607c462acSRatan Gupta 25707c462acSRatan Gupta struct ifaddrs* ifaddr; 25807c462acSRatan Gupta // attempt to fill struct with ifaddrs 25907c462acSRatan Gupta if (getifaddrs(&ifaddr) == -1) 26007c462acSRatan Gupta { 26107c462acSRatan Gupta return addrList; 26207c462acSRatan Gupta } 26307c462acSRatan Gupta 264537ff140SPatrick Venture slp::deleted_unique_ptr<ifaddrs> ifaddrPtr( 265537ff140SPatrick Venture ifaddr, [](ifaddrs* addr) { freeifaddrs(addr); }); 26607c462acSRatan Gupta 26707c462acSRatan Gupta ifaddr = nullptr; 26807c462acSRatan Gupta 26907c462acSRatan Gupta for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next) 27007c462acSRatan Gupta { 27107c462acSRatan Gupta // walk interfaces 27207c462acSRatan Gupta if (ifa->ifa_addr == nullptr) 27307c462acSRatan Gupta { 27407c462acSRatan Gupta continue; 27507c462acSRatan Gupta } 27607c462acSRatan Gupta 27707c462acSRatan Gupta // get only INET interfaces not ipv6 27807c462acSRatan Gupta if (ifa->ifa_addr->sa_family == AF_INET) 27907c462acSRatan Gupta { 28007c462acSRatan Gupta // if loopback, or not running ignore 28107c462acSRatan Gupta if ((ifa->ifa_flags & IFF_LOOPBACK) || 28207c462acSRatan Gupta !(ifa->ifa_flags & IFF_RUNNING)) 28307c462acSRatan Gupta { 28407c462acSRatan Gupta continue; 28507c462acSRatan Gupta } 28607c462acSRatan Gupta 28707c462acSRatan Gupta char tmp[INET_ADDRSTRLEN] = {0}; 28807c462acSRatan Gupta 28907c462acSRatan Gupta inet_ntop(AF_INET, 290537ff140SPatrick Venture &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr), tmp, 29107c462acSRatan Gupta sizeof(tmp)); 29207c462acSRatan Gupta addrList.emplace_back(tmp); 29307c462acSRatan Gupta } 29407c462acSRatan Gupta } 29507c462acSRatan Gupta 29607c462acSRatan Gupta return addrList; 29707c462acSRatan Gupta } 29807c462acSRatan Gupta 299ead7a3caSRatan Gupta slp::handler::internal::ServiceList readSLPServiceInfo() 30007c462acSRatan Gupta { 30107c462acSRatan Gupta using namespace std::string_literals; 30207c462acSRatan Gupta slp::handler::internal::ServiceList svcLst; 30307c462acSRatan Gupta slp::ConfigData service; 304ead7a3caSRatan Gupta struct dirent* dent = nullptr; 305ead7a3caSRatan Gupta 306ead7a3caSRatan Gupta // Open the services dir and get the service info 307ead7a3caSRatan Gupta // from service files. 308ead7a3caSRatan Gupta // Service File format would be "ServiceName serviceType Port" 309ead7a3caSRatan Gupta DIR* dir = opendir(SERVICE_DIR); 310ead7a3caSRatan Gupta // wrap the pointer into smart pointer. 311537ff140SPatrick Venture slp::deleted_unique_ptr<DIR> dirPtr(dir, [](DIR* dir) { 312ead7a3caSRatan Gupta if (!dir) 313ead7a3caSRatan Gupta { 314ead7a3caSRatan Gupta closedir(dir); 315ead7a3caSRatan Gupta } 316ead7a3caSRatan Gupta }); 317ead7a3caSRatan Gupta dir = nullptr; 318ead7a3caSRatan Gupta 319ead7a3caSRatan Gupta if (dirPtr.get()) 320ead7a3caSRatan Gupta { 321ead7a3caSRatan Gupta while ((dent = readdir(dirPtr.get())) != NULL) 322ead7a3caSRatan Gupta { 323ead7a3caSRatan Gupta if (dent->d_type == DT_REG) // regular file 324ead7a3caSRatan Gupta { 325ead7a3caSRatan Gupta auto absFileName = std::string(SERVICE_DIR) + dent->d_name; 326ead7a3caSRatan Gupta std::ifstream readFile(absFileName); 327ead7a3caSRatan Gupta readFile >> service; 328ead7a3caSRatan Gupta service.name = "service:"s + service.name; 32907c462acSRatan Gupta svcLst.emplace(service.name, service); 33007c462acSRatan Gupta } 331ead7a3caSRatan Gupta } 332ead7a3caSRatan Gupta } 33307c462acSRatan Gupta return svcLst; 33407c462acSRatan Gupta } 33507c462acSRatan Gupta } // namespace internal 33607c462acSRatan Gupta 337537ff140SPatrick Venture std::tuple<int, buffer> processRequest(const Message& msg) 33807c462acSRatan Gupta { 33907c462acSRatan Gupta int rc = slp::SUCCESS; 34007c462acSRatan Gupta buffer resp(0); 341537ff140SPatrick Venture std::cout << "SLP Processing Request=" << msg.header.functionID << "\n"; 3420d3e9e33SRatan Gupta 343b5e632a1SBrad Bishop switch (msg.header.functionID) 344b5e632a1SBrad Bishop { 34507c462acSRatan Gupta case (uint8_t)slp::FunctionType::SRVTYPERQST: 346*aa902c6eSPatrick Williams std::tie(rc, 347*aa902c6eSPatrick Williams resp) = slp::handler::internal::processSrvTypeRequest(msg); 34807c462acSRatan Gupta break; 34907c462acSRatan Gupta case (uint8_t)slp::FunctionType::SRVRQST: 35007c462acSRatan Gupta std::tie(rc, resp) = slp::handler::internal::processSrvRequest(msg); 35107c462acSRatan Gupta break; 35207c462acSRatan Gupta default: 35307c462acSRatan Gupta rc = (uint8_t)slp::Error::MSG_NOT_SUPPORTED; 35407c462acSRatan Gupta } 35507c462acSRatan Gupta return std::make_tuple(rc, resp); 35607c462acSRatan Gupta } 35707c462acSRatan Gupta 358537ff140SPatrick Venture buffer processError(const Message& req, uint8_t err) 35907c462acSRatan Gupta { 36007c462acSRatan Gupta buffer buff; 36107c462acSRatan Gupta buff = slp::handler::internal::prepareHeader(req); 36207c462acSRatan Gupta 36307c462acSRatan Gupta std::copy_n(&err, slp::response::SIZE_ERROR, 364537ff140SPatrick Venture buff.data() + slp::response::OFFSET_ERROR); 36507c462acSRatan Gupta return buff; 36607c462acSRatan Gupta } 36707c462acSRatan Gupta } // namespace handler 36807c462acSRatan Gupta } // namespace slp 369