/******************************************************************************* * Boap.cc Boap RPC protocol * T.Barnaby, BEAM Ltd, 8/5/03 * * History: * 4/2/05: Updated addressing scheme ******************************************************************************* */ #include #include #include #include #include #include // Boap NS #include #include #define DEBUG 0 #if DEBUG #define dprintf(fmt, a...) printf(fmt, ##a); #else #define dprintf(fmt, a...) #endif const int roundSize = 256; BoapPacket::BoapPacket(){ opos = 0; osize = roundSize; odata = (char*)malloc(osize); } BoapPacket::~BoapPacket(){ delete odata; } int BoapPacket::resize(int size){ if(size > osize){ osize = roundSize * ((size + roundSize - 1) / roundSize); odata = (char*)realloc(odata, osize); } return 0; } BError BoapPacket::setData(void* data, int nbytes){ BError err; resize(nbytes); memcpy(odata, data, nbytes); return err; } int BoapPacket::nbytes(){ return ((BoapPacketHead*)odata)->length; } char* BoapPacket::data(){ return odata; } void BoapPacket::updateLen(){ ((BoapPacketHead*)odata)->length = opos; } int BoapPacket::pushHead(BoapPacketHead& head){ opos = 0; resize(opos + sizeof(head)); memcpy(&odata[opos], &head, sizeof(head)); opos += sizeof(head); updateLen(); return 0; } int BoapPacket::push(Int8 v){ resize(opos + sizeof(v)); memcpy(&odata[opos], &v, sizeof(v)); opos += sizeof(v); updateLen(); return 0; } int BoapPacket::push(UInt8 v){ resize(opos + sizeof(v)); memcpy(&odata[opos], &v, sizeof(v)); opos += sizeof(v); updateLen(); return 0; } int BoapPacket::push(Int16 v){ resize(opos + sizeof(v)); memcpy(&odata[opos], &v, sizeof(v)); opos += sizeof(v); updateLen(); return 0; } int BoapPacket::push(UInt16 v){ resize(opos + sizeof(v)); memcpy(&odata[opos], &v, sizeof(v)); opos += sizeof(v); updateLen(); return 0; } int BoapPacket::push(Int32 v){ resize(opos + sizeof(v)); memcpy(&odata[opos], &v, sizeof(v)); opos += sizeof(v); updateLen(); return 0; } int BoapPacket::push(UInt32 v){ resize(opos + sizeof(v)); memcpy(&odata[opos], &v, sizeof(v)); opos += sizeof(v); updateLen(); return 0; } int BoapPacket::push(BString& v){ Int32 l = v.len() + 1; resize(opos + sizeof(l) + l); memcpy(&odata[opos], &l, sizeof(l)); opos += sizeof(l); memcpy(&odata[opos], v.retStr(), l); opos += l; updateLen(); return 0; } int BoapPacket::push(Double v){ resize(opos + sizeof(v)); memcpy(&odata[opos], &v, sizeof(v)); opos += sizeof(v); updateLen(); return 0; } int BoapPacket::push(BError& v){ Int32 n = v.getErrorNo(); BString s = v.getString(); push(n); push(s); return 0; } int BoapPacket::push(UInt32 nBytes, const void* data){ } int BoapPacket::popHead(BoapPacketHead& head){ opos = 0; memcpy(&head, &odata[opos], sizeof(head)); opos += sizeof(head); return 0; } int BoapPacket::pop(Int8& v){ memcpy(&v, &odata[opos], sizeof(v)); opos += sizeof(v); return 0; } int BoapPacket::pop(UInt8& v){ memcpy(&v, &odata[opos], sizeof(v)); opos += sizeof(v); return 0; } int BoapPacket::pop(Int16& v){ memcpy(&v, &odata[opos], sizeof(v)); opos += sizeof(v); return 0; } int BoapPacket::pop(UInt16& v){ memcpy(&v, &odata[opos], sizeof(v)); opos += sizeof(v); return 0; } int BoapPacket::pop(Int32& v){ memcpy(&v, &odata[opos], sizeof(v)); opos += sizeof(v); return 0; } int BoapPacket::pop(UInt32& v){ memcpy(&v, &odata[opos], sizeof(v)); opos += sizeof(v); return 0; } int BoapPacket::pop(BString& v){ Int32 l; memcpy(&l, &odata[opos], sizeof(l)); opos += sizeof(l); v = (char*)&odata[opos]; opos += l; return 0; } int BoapPacket::pop(Double& v){ memcpy(&v, &odata[opos], sizeof(v)); opos += sizeof(v); return 0; } int BoapPacket::pop(BError& v){ Int32 n; BString s; pop(n); pop(s); v.set(n, s); return 0; } int BoapPacket::pop(UInt32 nBytes, void* data){ return 0; } /******************************************************************************* * Boap Client communications object ******************************************************************************* */ /******************************************************************************* * Base for all Client Classes ******************************************************************************* */ BoapClientObject::BoapClientObject(BString name): BSocket(STREAM), oname(name){ oconnected = 0; oservice = 0; } BError BoapClientObject::connectService(BString name){ BError err; Boapns::Boapns boapns("boapns"); Boapns::BoapEntry entry; BString host = "localhost"; BString boapnsName; BSocketAddressINET add; if(oconnected) return err; oname = name; // Parse name if(name.subString(0, 2) == "//"){ name.pullSeparators("/"); host = name.pullToken("/"); } if(name == "boapns"){ if(! (err = add.set(host, "boapns", "tcp"))){ if(! (err = connect(add))){ oservice = 0; oconnected = 1; } } } else { // Lookup name boapnsName = BString("//") + host + "/boapns"; if(! (err = boapns.connectService(boapnsName))){ if(! (err = boapns.getEntry(name, entry))){ if(! (err = add.set(entry.ipAddress, entry.port))){ if(! (err = connect(add))){ oservice = entry.service; oconnected = 1; } } } } } return err; } BError BoapClientObject::performSend(BoapPacket& tx){ BError err; BSize nb = tx.nbytes(); char* data = tx.data(); BSize n = 0; BSize nd = 0; // Connect if required if(err = connectService(oname)) return err; // Send packet while(n < nb){ if(err = send(&data[n], nb - n, nd, MSG_NOSIGNAL)) return err; n = n + nd; } return err; } BError BoapClientObject::performRecv(BoapPacket& rx){ BError err; BSize nb = 0; char* data = 0; BSize n = 0; BSize nd = 0; BoapPacketHead head; // Connect if required if(err = connectService(oname)) return err; // Recieve Packet // Read Head first rx.resize(sizeof(BoapPacketHead)); nb = sizeof(BoapPacketHead); data = rx.data(); n = 0; while(n < nb){ if(err = recv(&data[n], nb - n, nd)) return err; n = n + nd; } // Read rest of packet rx.popHead(head); rx.resize(head.length); nb = head.length - sizeof(BoapPacketHead); data = &rx.data()[sizeof(BoapPacketHead)]; n = 0; while(n < nb){ if(err = recv(&data[n], nb - n, nd)) return err; n = n + nd; } return err; } BError BoapClientObject::performCall(BoapPacket& tx, BoapPacket& rx){ BError err; if(! (err = performSend(tx))){ err = performRecv(rx); } return err; } BoapSignalObject::BoapSignalObject(): BSocket(DGRAM){ setBroadCast(1); } BError BoapSignalObject::performSend(BoapPacket& tx){ BError err; BSize nb = tx.nbytes(); char* data = tx.data(); BSize n = 0; BSize nd = 0; BSocketAddressINET nadd; nadd.set(INADDR_BROADCAST, 14000); // Send packet while(n < nb){ if(err = sendTo(nadd, &data[n], nb - n, nd, MSG_NOSIGNAL)) return err; n = n + nd; } return err; } /******************************************************************************* * Boap Server communications object ******************************************************************************* */ BoapServer::BoapServer() : onet(BSocket::STREAM), onetEvent(BSocket::DGRAM) { oboapNs = 0; onet.setReuseAddress(1); } BError BoapServer::init(int boapNs){ BError err; Boapns::Boapns boapns("boapns"); BIter i; BoapService s; BList l; uint32_t ipAddress; BSocketAddressINET nadd; oboapNs = boapNs; ohostName = BSocketAddressINET::getHostName(); l = BSocketAddressINET::getIpAddresses(); if(l.number()) ipAddress = l[0]; else ipAddress = 0; if(boapNs) nadd.set("", "boapns", "tcp"); else nadd.set("", 0); // Create service socket if(err = onet.bind(nadd)) return err; // Create event socket if(err = onet.getAddress(nadd)) return err; if(err = onetEvent.bind(nadd)) return err; // BOAP event broadcast address onetEventAddress.set("", "boapns", "udp"); onetEventAddress.set(INADDR_BROADCAST, onetEventAddress.port()); onetEvent.setBroadCast(1); if(!boapNs){ for(oservices.start(i), s = 0; !oservices.isEnd(i); oservices.next(i), s++){ if(err = boapns.addEntry(Boapns::BoapEntry(oservices[i].oobject->name(), ipAddress, nadd.port(), s))) break; } } return err; } BError BoapServer::run(){ BError err; BSocketAddressINET nadd; int fd; opoll.append(onet.getFd()); opoll.append(onetEvent.getFd()); onet.listen(); while(1){ opoll.doPoll(fd); if(fd == onet.getFd()){ onet.accept(fd, nadd); dprintf("Accept Connection: Fd: %d Add: %s\n", fd, nadd.getString().retStr()); opoll.append(fd); } else if(fd == onetEvent.getFd()){ processEvent(fd); } else if(fd >= 0){ if(process(fd)){ opoll.delFd(fd); close(fd); } } } return err; } BError BoapServer::addObject(BoapServiceObject* object){ BError err; oservices.append(BoapServiceEntry(oservices.number(), object)); return err; } BError BoapServer::process(int fd){ BError err; int nb = 0; char* data = 0; int n = 0; int nd = 0; BoapPacketHead head; BIter i; // Recieve Packet // Read Head first orx.resize(sizeof(BoapPacketHead)); nb = sizeof(BoapPacketHead); data = orx.data(); n = 0; while(n < nb){ nd = recv(fd, &data[n], nb - n, 0); if(nd <= 0) return BError(1, strerror(errno)); n = n + nd; } // Read rest of packet orx.popHead(head); orx.resize(head.length); nb = head.length - sizeof(BoapPacketHead); data = &orx.data()[sizeof(BoapPacketHead)]; n = 0; while(n < nb){ nd = recv(fd, &data[n], nb - n, 0); if(nd <= 0) return BError(1, strerror(errno)); n = n + nd; } dprintf("Command received: Len(%d) Type(%d) Service(%d) Cmd(%d)\n", head.length, head.type, head.service, head.cmd); for(oservices.start(i); !oservices.isEnd(i); oservices.next(i)){ if(oservices[i].oservice == head.service){ oservices[i].oobject->process(orx, otx); break; } } // Send packet nb = otx.nbytes(); data = otx.data(); n = 0; while(n < nb){ nd = send(fd, &data[n], nb - n, MSG_NOSIGNAL); if(nd <= 0) return BError(1, strerror(errno)); n = n + nd; } return err; } BError BoapServer::processEvent(BoapPacket& rx){ BError err; BIter i; int s; dprintf("BoapServer::processEvent\n"); for(oservices.start(i), s = 0; !oservices.isEnd(i); oservices.next(i), s++){ oservices[i].oobject->processEvent(rx); } return err; } BError BoapServer::processEvent(int fd){ BError err; int nb = 0; BoapPacketHead head; BoapPacket rx; // Recieve Packet rx.resize(1500); if((nb = recv(fd, rx.data(), 1500, 0)) < 0) return BError(errno, strerror(errno)); orx.popHead(head); dprintf("Event received: Len(%d) Service(%d) Cmd(%d)\n", head.length, head.service, head.cmd); return processEvent(rx); } BError BoapServer::sendEvent(BoapPacket& tx){ BError err; int nb = 0; char* data = 0; int n = 0; uint32_t nsent; // Send packet nb = tx.nbytes(); data = tx.data(); n = 0; while(n < nb){ dprintf("BoapServer::sendEvent: Address: %s\n", onetEventAddress.getString().retStr()); err = onetEvent.sendTo(onetEventAddress, &data[n], nb - n, nsent); dprintf("BoapServer::sendEvent: result: %d:%s\n", err.getErrorNo(), err.getString().retStr()); if(err) return err; n = n + nsent; } return err; } BSocket& BoapServer::getSocket(){ return onet; } BSocket& BoapServer::getEventSocket(){ return onetEvent; } BString BoapServer::getHostName(){ return ohostName; } /******************************************************************************* * Base for all Server Objects ******************************************************************************* */ BoapFuncEntry::BoapFuncEntry(int cmd, BoapFunc func) : ocmd(cmd), ofunc(func){ } BoapServiceObject::BoapServiceObject(BoapServer& server, BString name) : oserver(server), oname(name){ oserver.addObject(this); } BoapServiceObject::~BoapServiceObject(){ } BString BoapServiceObject::name(){ return oname; } BError BoapServiceObject::process(BoapPacket& rx, BoapPacket& tx){ BError err; BoapPacketHead head; BIter i; rx.popHead(head); for(ofuncList.start(i); !ofuncList.isEnd(i); ofuncList.next(i)){ if(ofuncList[i].ocmd == head.cmd){ err = (this->*ofuncList[i].ofunc)(rx, tx); break; } } return err; } BError BoapServiceObject::sendEvent(BString name, Int32 arg){ BError err; BoapPacketHead txhead; BoapPacket tx; BString fullName = BString("//") + oserver.getHostName() + "/" + oname; txhead.type = BoapTypeSignal; txhead.service = 0; txhead.cmd = 0; tx.pushHead(txhead); tx.push(fullName); tx.push(name); tx.push(arg); if(err = sendEvent(tx)) return err; return err; } BError BoapServiceObject::processEvent(BString objectName, BString signalName, Int32 arg){ BError err; dprintf("BoapServiceObject::processEvent(BString objectName, BString signalName, Int32 arg)\n"); return err; } BError BoapServiceObject::sendEvent(BoapPacket& tx){ return oserver.sendEvent(tx); } BError BoapServiceObject::processEvent(BoapPacket& rx){ BError err; BoapPacketHead rxhead; BError ret; BString objectName; BString signalName; Int32 arg; dprintf("BoapServiceObject::processEvent\n"); rx.popHead(rxhead); rx.pop(objectName); rx.pop(signalName); rx.pop(arg); ret = processEvent(objectName, signalName, arg); return err; }