<commit_before>// @(#)root/tree:$Id$
// Author: Rene Brun   12/01/96

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// A TLeaf for an 8 bit Integer data type.                              //
//////////////////////////////////////////////////////////////////////////

#include "TLeafB.h"
#include "TBranch.h"
#include "TClonesArray.h"
#include "Riostream.h"

ClassImp(TLeafB)

//______________________________________________________________________________
TLeafB::TLeafB()
: TLeaf()
, fMinimum(0)
, fMaximum(0)
, fValue(0)
, fPointer(0)
{
   // -- Default constructor.
   fLenType = 1;
}

//______________________________________________________________________________
TLeafB::TLeafB(TBranch *parent, const char* name, const char* type)
   : TLeaf(parent, name, type)
   , fMinimum(0)
   , fMaximum(0)
   , fValue(0)
   , fPointer(0)
{
   // -- Create a LeafB.
   fLenType = 1;
}

//______________________________________________________________________________
TLeafB::~TLeafB()
{
   // -- Destructor.
   if (ResetAddress(0, kTRUE)) {
      delete[] fValue;
      fValue = 0;
   }
   // Note: We do not own this, the user's object does.
   fPointer = 0;
}

//______________________________________________________________________________
void TLeafB::Export(TClonesArray* list, Int_t n)
{
   // -- Export element from local leaf buffer to a ClonesArray.

   for (Int_t i = 0, j = 0; i < n; i++, j += fLen) {
      memcpy(((char*) list->UncheckedAt(i)) + fOffset, &fValue[j], fLen);
   }
}

//______________________________________________________________________________
void TLeafB::FillBasket(TBuffer& b)
{
   // -- Pack leaf elements into Basket output buffer.

   Int_t len = GetLen();
   if (fPointer) {
      fValue = *fPointer;
   }
   if (IsRange()) {
      if (fValue[0] > fMaximum) {
         fMaximum = fValue[0];
      }
   }
   if (IsUnsigned()) {
      for (Int_t i = 0; i < len; i++) {
         b << (UChar_t) fValue[i];
      }
   } else {
      b.WriteFastArray(fValue, len);
   }
}

//______________________________________________________________________________
const char *TLeafB::GetTypeName() const
{
   // -- Returns name of leaf type.

   if (fIsUnsigned) {
      return "UChar_t";
   }
   return "Char_t";
}

//______________________________________________________________________________
void TLeafB::Import(TClonesArray *list, Int_t n)
{
   // -- Import element from ClonesArray into local leaf buffer.

   for (Int_t i = 0, j = 0; i < n; i++, j+= fLen) {
      memcpy(&fValue[j], ((char*) list->UncheckedAt(i)) + fOffset, fLen);
   }
}

//______________________________________________________________________________
void TLeafB::PrintValue(Int_t l) const
{
   // -- Prints leaf value.

   if (fIsUnsigned) {
      UChar_t *uvalue = (UChar_t*) GetValuePointer();
      printf("%u", uvalue[l]);
   } else {
      Char_t *value = (Char_t*) GetValuePointer();
      printf("%d", value[l]);
   }
}

//______________________________________________________________________________
void TLeafB::ReadBasket(TBuffer &b)
{
   // -- Read leaf elements from Basket input buffer.

   if (!fLeafCount && (fNdata == 1)) {
      b.ReadChar(fValue[0]);
   } else {
      if (fLeafCount) {
         Long64_t entry = fBranch->GetReadEntry();
         if (fLeafCount->GetBranch()->GetReadEntry() != entry) {
            fLeafCount->GetBranch()->GetEntry(entry);
         }
         Int_t len = Int_t(fLeafCount->GetValue());
         if (len > fLeafCount->GetMaximum()) {
            Error("ReadBasket", "leaf: '%s' len: %d max: %d", GetName(), len, fLeafCount->GetMaximum());
            len = fLeafCount->GetMaximum();
         }
         fNdata = len * fLen;
         b.ReadFastArray(fValue, len*fLen);
      } else {
         b.ReadFastArray(fValue, fLen);
      }
   }
}

//______________________________________________________________________________
void TLeafB::ReadBasketExport(TBuffer& b, TClonesArray* list, Int_t n)
{
   // -- Read leaf elements from Basket input buffer and export buffer to TClonesArray objects.

   b.ReadFastArray(fValue, n*fLen);

   for (Int_t i = 0, j = 0; i < n; i++, j += fLen) {
      memcpy(((char*) list->UncheckedAt(i)) + fOffset, &fValue[j], fLen);
   }
}

//______________________________________________________________________________
void TLeafB::ReadValue(istream &s, Char_t /*delim = ' '*/)
{
   // -- Read a string from istream s and store it into the branch buffer.
   if (fIsUnsigned) {
      UChar_t *uvalue = (UChar_t*)GetValuePointer();
      for (Int_t i=0;i<fLen;i++) {
         UShort_t tmp;
         s >> tmp;
         uvalue[i] = tmp;
      }
   } else {
      Char_t *value = (Char_t*)GetValuePointer();
      for (Int_t i=0;i<fLen;i++) {
         Short_t tmp;
         s >> tmp;
         value[i] = tmp;
      }
   }
}

//______________________________________________________________________________
void TLeafB::SetAddress(void *addr)
{
   // -- Set value buffer address.

   // Check ownership of the value buffer and
   // calculate a new size for it.
   if (ResetAddress(addr)) {
      // -- We owned the old value buffer, delete it.
      delete[] fValue;
      fValue = 0;
   }
   if (addr) {
      // -- We have been provided a new value buffer.
      if (TestBit(kIndirectAddress)) {
         // -- The data member is a pointer to an array.
         fPointer = (Char_t**) addr;
         // Calculate the maximum size we have ever needed
         // for the value buffer.
         Int_t ncountmax = fLen;
         if (fLeafCount) {
            ncountmax = (fLeafCount->GetMaximum() + 1) * fLen;
         }
         // Reallocate the value buffer if needed.
         if ((fLeafCount && (Int_t(fLeafCount->GetValue()) < ncountmax)) ||
             (fNdata < ncountmax) ||
             (*fPointer == 0)) {
            // -- Reallocate.
            // Note:
            //      1) For a varying length array we do this based on
            //         an indirect estimator of the size of the value
            //         buffer since we have no record of how large it
            //         actually is.  If the current length of the
            //         varying length array is less than it has been
            //         in the past, then reallocate the value buffer
            //         to the larger of either the calculated new size
            //         or the maximum size it has ever been.
            //
            //      2) The second condition checks if the new value
            //         buffer size calculated by ResetAddress() is
            //         smaller than the most we have ever used, and
            //         if it is, then we increase the new size and
            //         reallocate.
            //
            //      3) The third condition is checking to see if we
            //         have been given a value buffer, if not then
            //         we must allocate one.
            //
            if (fNdata < ncountmax) {
               fNdata = ncountmax;
            }
            delete[] *fPointer;
            *fPointer = 0;
            *fPointer = new Char_t[fNdata];
         }
         fValue = *fPointer;
      } else {
         // -- The data member is fixed size.
         // FIXME: What about fPointer???
         fValue = (char*) addr;
      }
   } else {
      // -- We must create the value buffer ourselves.
      // Note: We are using the size calculated by ResetAddress().
      fValue = new char[fNdata];
      // FIXME: Why initialize at all?
      fValue[0] = 0;
   }
}

<commit_msg>Fix doc string<commit_after>// @(#)root/tree:$Id$
// Author: Rene Brun   12/01/96

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// A TLeaf for an 8 bit Integer data type.                              //
//////////////////////////////////////////////////////////////////////////

#include "TLeafB.h"
#include "TBranch.h"
#include "TClonesArray.h"
#include "Riostream.h"

ClassImp(TLeafB)

//______________________________________________________________________________
TLeafB::TLeafB()
: TLeaf()
, fMinimum(0)
, fMaximum(0)
, fValue(0)
, fPointer(0)
{
   // -- Default constructor.
   fLenType = 1;
}

//______________________________________________________________________________
TLeafB::TLeafB(TBranch *parent, const char* name, const char* type)
   : TLeaf(parent, name, type)
   , fMinimum(0)
   , fMaximum(0)
   , fValue(0)
   , fPointer(0)
{
   // -- Create a LeafB.
   fLenType = 1;
}

//______________________________________________________________________________
TLeafB::~TLeafB()
{
   // -- Destructor.
   if (ResetAddress(0, kTRUE)) {
      delete[] fValue;
      fValue = 0;
   }
   // Note: We do not own this, the user's object does.
   fPointer = 0;
}

//______________________________________________________________________________
void TLeafB::Export(TClonesArray* list, Int_t n)
{
   // -- Export element from local leaf buffer to a ClonesArray.

   for (Int_t i = 0, j = 0; i < n; i++, j += fLen) {
      memcpy(((char*) list->UncheckedAt(i)) + fOffset, &fValue[j], fLen);
   }
}

//______________________________________________________________________________
void TLeafB::FillBasket(TBuffer& b)
{
   // -- Pack leaf elements into Basket output buffer.

   Int_t len = GetLen();
   if (fPointer) {
      fValue = *fPointer;
   }
   if (IsRange()) {
      if (fValue[0] > fMaximum) {
         fMaximum = fValue[0];
      }
   }
   if (IsUnsigned()) {
      for (Int_t i = 0; i < len; i++) {
         b << (UChar_t) fValue[i];
      }
   } else {
      b.WriteFastArray(fValue, len);
   }
}

//______________________________________________________________________________
const char *TLeafB::GetTypeName() const
{
   // -- Returns name of leaf type.

   if (fIsUnsigned) {
      return "UChar_t";
   }
   return "Char_t";
}

//______________________________________________________________________________
void TLeafB::Import(TClonesArray *list, Int_t n)
{
   // -- Import element from ClonesArray into local leaf buffer.

   for (Int_t i = 0, j = 0; i < n; i++, j+= fLen) {
      memcpy(&fValue[j], ((char*) list->UncheckedAt(i)) + fOffset, fLen);
   }
}

//______________________________________________________________________________
void TLeafB::PrintValue(Int_t l) const
{
   // -- Prints leaf value.

   if (fIsUnsigned) {
      UChar_t *uvalue = (UChar_t*) GetValuePointer();
      printf("%u", uvalue[l]);
   } else {
      Char_t *value = (Char_t*) GetValuePointer();
      printf("%d", value[l]);
   }
}

//______________________________________________________________________________
void TLeafB::ReadBasket(TBuffer &b)
{
   // -- Read leaf elements from Basket input buffer.

   if (!fLeafCount && (fNdata == 1)) {
      b.ReadChar(fValue[0]);
   } else {
      if (fLeafCount) {
         Long64_t entry = fBranch->GetReadEntry();
         if (fLeafCount->GetBranch()->GetReadEntry() != entry) {
            fLeafCount->GetBranch()->GetEntry(entry);
         }
         Int_t len = Int_t(fLeafCount->GetValue());
         if (len > fLeafCount->GetMaximum()) {
            Error("ReadBasket", "leaf: '%s' len: %d max: %d", GetName(), len, fLeafCount->GetMaximum());
            len = fLeafCount->GetMaximum();
         }
         fNdata = len * fLen;
         b.ReadFastArray(fValue, len*fLen);
      } else {
         b.ReadFastArray(fValue, fLen);
      }
   }
}

//______________________________________________________________________________
void TLeafB::ReadBasketExport(TBuffer& b, TClonesArray* list, Int_t n)
{
   // -- Read leaf elements from Basket input buffer and export buffer to TClonesArray objects.

   b.ReadFastArray(fValue, n*fLen);

   for (Int_t i = 0, j = 0; i < n; i++, j += fLen) {
      memcpy(((char*) list->UncheckedAt(i)) + fOffset, &fValue[j], fLen);
   }
}

//______________________________________________________________________________
void TLeafB::ReadValue(istream &s, Char_t /*delim = ' '*/)
{
   // -- Read a 8 bit integer from istream s and store it into the branch buffer.
   if (fIsUnsigned) {
      UChar_t *uvalue = (UChar_t*)GetValuePointer();
      for (Int_t i=0;i<fLen;i++) {
         UShort_t tmp;
         s >> tmp;
         uvalue[i] = tmp;
      }
   } else {
      Char_t *value = (Char_t*)GetValuePointer();
      for (Int_t i=0;i<fLen;i++) {
         Short_t tmp;
         s >> tmp;
         value[i] = tmp;
      }
   }
}

//______________________________________________________________________________
void TLeafB::SetAddress(void *addr)
{
   // -- Set value buffer address.

   // Check ownership of the value buffer and
   // calculate a new size for it.
   if (ResetAddress(addr)) {
      // -- We owned the old value buffer, delete it.
      delete[] fValue;
      fValue = 0;
   }
   if (addr) {
      // -- We have been provided a new value buffer.
      if (TestBit(kIndirectAddress)) {
         // -- The data member is a pointer to an array.
         fPointer = (Char_t**) addr;
         // Calculate the maximum size we have ever needed
         // for the value buffer.
         Int_t ncountmax = fLen;
         if (fLeafCount) {
            ncountmax = (fLeafCount->GetMaximum() + 1) * fLen;
         }
         // Reallocate the value buffer if needed.
         if ((fLeafCount && (Int_t(fLeafCount->GetValue()) < ncountmax)) ||
             (fNdata < ncountmax) ||
             (*fPointer == 0)) {
            // -- Reallocate.
            // Note:
            //      1) For a varying length array we do this based on
            //         an indirect estimator of the size of the value
            //         buffer since we have no record of how large it
            //         actually is.  If the current length of the
            //         varying length array is less than it has been
            //         in the past, then reallocate the value buffer
            //         to the larger of either the calculated new size
            //         or the maximum size it has ever been.
            //
            //      2) The second condition checks if the new value
            //         buffer size calculated by ResetAddress() is
            //         smaller than the most we have ever used, and
            //         if it is, then we increase the new size and
            //         reallocate.
            //
            //      3) The third condition is checking to see if we
            //         have been given a value buffer, if not then
            //         we must allocate one.
            //
            if (fNdata < ncountmax) {
               fNdata = ncountmax;
            }
            delete[] *fPointer;
            *fPointer = 0;
            *fPointer = new Char_t[fNdata];
         }
         fValue = *fPointer;
      } else {
         // -- The data member is fixed size.
         // FIXME: What about fPointer???
         fValue = (char*) addr;
      }
   } else {
      // -- We must create the value buffer ourselves.
      // Note: We are using the size calculated by ResetAddress().
      fValue = new char[fNdata];
      // FIXME: Why initialize at all?
      fValue[0] = 0;
   }
}

<|endoftext|>


<commit_before>#include "BinarySearchTree.h"
using namespace std;

int main(){
   BST<int> bst;
   srand(0);
   //srand(time(NULL));

   bst.placeholder=100;
   int test_data[10];
   for (int i = 0; i < 10; i++){
        test_data[i] = (rand() % 100)+1;
        bst.root = bst.insert(bst.root, test_data[i]);
   }
   bst.print_t(bst.root);

   for (int i = 0; i < 10; i++){
        //cout << test_data[i] << (bst.search(bst.root, test_data[i])?" can":" cannot")<< " be found in the tree!" << endl;
        //cout << test_data[i]-1 << (bst.search(bst.root, test_data[i]-1)?" can":" cannot")<< " be found in the tree!" << endl;
   }
   return 0;
}
<commit_msg>Binary<commit_after>#include "BinarySearchTree.h"
using namespace std;

int main(){
   BST<int> bst;
   //srand(0);
   srand(time(NULL));

   bst.placeholder=100;
   int test_data[10];
   for (int i = 0; i < 10; i++){
        test_data[i] = (rand() % 100)+1;
        bst.root = bst.insert(bst.root, test_data[i]);
   }
   bst.print_t(bst.root);

   for (int i = 0; i < 10; i++){
        //cout << test_data[i] << (bst.search(bst.root, test_data[i])?" can":" cannot")<< " be found in the tree!" << endl;
        //cout << test_data[i]-1 << (bst.search(bst.root, test_data[i]-1)?" can":" cannot")<< " be found in the tree!" << endl;
   }
   return 0;
}
<|endoftext|>


<commit_before>#include "broker.h"
#include "frame.h"
#include <sstream>
#include <thread>
#include <sys/socket.h>

Broker::Broker() {
    topicRoot = new TopicNode("", "");
}

Broker::~Broker() {
    delete topicRoot;
}

MQTT_ERROR Broker::Start() {
    struct sockaddr_in addr;
    int listener = socket(AF_INET, SOCK_STREAM, 0);
    addr.sin_family = AF_INET;
    addr.sin_port = 8883;
    addr.sin_addr.s_addr = INADDR_ANY;
    bind(listener, (struct sockaddr *)&addr, sizeof(addr));
    listen(listener, 5);
    while (true) {
        struct sockaddr_in client;
        unsigned int len = sizeof(client);
        int sock = accept(listener, (struct sockaddr *)&client, &len);
        BrokerSideClient* bc = new BrokerSideClient(new Transport(sock, &client), this);
        //std::thread t(bc->readMessageLoop());
        //t.join();
    }

    return NO_ERROR;
}

MQTT_ERROR Broker::checkQoSAndPublish(BrokerSideClient* requestClient, uint8_t publisherQoS, uint8_t requestedQoS, bool retain, std::string topic, std::string message) {
    uint16_t id = 0;
    MQTT_ERROR err = NO_ERROR;
    uint8_t qos = publisherQoS;
    if (requestedQoS < publisherQoS) {
        // QoS downgrade
        qos = requestedQoS;
    }
    if (qos > 0) {
        err = requestClient->getUsablePacketID(&id);
        if (err != NO_ERROR) {
            return err;
        }
    }
    err = requestClient->sendMessage(new PublishMessage(false, qos, retain, id, topic, message));
    return err;
}

std::string Broker::ApplyDummyClientID() {
    std::stringstream ss;
    ss << "DummyClientID" << clients.size() + 1;
    return ss.str();
}

BrokerSideClient::BrokerSideClient(Transport* ct, Broker* b) : broker(b), Terminal("", NULL, 0, NULL) {
    this->ct = ct;
}

BrokerSideClient::~BrokerSideClient() {}

void BrokerSideClient::setPreviousSession(BrokerSideClient* ps) {
    subTopics = ps->subTopics;
    packetIDMap = ps->packetIDMap;
    cleanSession = ps->cleanSession;
    will = ps->will;
    user = ps->user;
    keepAlive = ps->keepAlive;
}

MQTT_ERROR BrokerSideClient::recvConnectMessage(ConnectMessage* m) {return NO_ERROR;}
MQTT_ERROR BrokerSideClient::recvConnackMessage(ConnackMessage* m) {return INVALID_MESSAGE_CAME;}
MQTT_ERROR BrokerSideClient::recvPublishMessage(PublishMessage* m) {
    if (m->fh->Dup) {
        // re-delivered
    } else {
        // first time delivery
    }

    MQTT_ERROR err = NO_ERROR;
    if (m->fh->Retain) {
        std::string data = m->payload;
        if (m->fh->QoS == 0 && data.size() > 0) {
            data = "";
        }
        broker->topicRoot->applyRetain(m->topicName, m->fh->QoS, data, err);
        if (err != NO_ERROR) {
            return err;
        }
    }
    broker->topicRoot->getTopicNode(m->topicName, true, err);
    if (err != NO_ERROR) {
        return err;
    }

    // TODO: downgrade and publish

    switch (m->fh->QoS) {
    case 0:
        if (m->fh->PacketID != 0){
            return PACKET_ID_SHOULD_BE_ZERO;
        }
    case 1:
        sendMessage(new PubackMessage(m->fh->PacketID));
    case 2:
        sendMessage(new PubrecMessage(m->fh->PacketID));
    }

    return err;
}

MQTT_ERROR BrokerSideClient::recvPubackMessage(PubackMessage* m) {
    if (m->fh->PacketID > 0) {
        return ackMessage(m->fh->PacketID);
    }
    return NO_ERROR;
}

MQTT_ERROR BrokerSideClient::recvPubrecMessage(PubrecMessage* m) {
    MQTT_ERROR err = ackMessage(m->fh->PacketID);
    if (err < 0) {
        return err;
    }
    err = sendMessage(new PubrelMessage(m->fh->PacketID));
    return err;
}

MQTT_ERROR BrokerSideClient::recvPubrelMessage(PubrelMessage* m) {
    MQTT_ERROR err = ackMessage(m->fh->PacketID);
    if (err < 0) {
        return err;
    }
    err = sendMessage(new PubcompMessage(m->fh->PacketID));
    return err;
}

MQTT_ERROR BrokerSideClient::recvPubcompMessage(PubcompMessage* m) {
    return ackMessage(m->fh->PacketID);
}

MQTT_ERROR BrokerSideClient::recvSubscribeMessage(SubscribeMessage* m) {
    std::vector<SubackCode> returnCodes;

    MQTT_ERROR err; // this sould be duplicate?
    for (std::vector<SubscribeTopic*>::iterator it = m->subTopics.begin(); it != m->subTopics.end(); it++) {
        std::vector<TopicNode*> nodes = broker->topicRoot->getTopicNode((*it)->topic, true, err);
        SubackCode code = (SubackCode)(*it)->qos;

        if (err != NO_ERROR) {
            code = FAILURE;
        } else {
            for (std::vector<TopicNode*>::iterator nIt = nodes.begin(); nIt != nodes.end(); nIt++) {
                (*nIt)->subscribers[ID] = (*it)->qos;
                subTopics[(*it)->topic] = (*it)->qos;
                if ((*nIt)->retainMessage.size() > 0) {
                    err = this->broker->checkQoSAndPublish(this, (*nIt)->retainQoS, (*it)->qos, true, (*nIt)->fullPath,(*nIt)->retainMessage);
                    if (err != NO_ERROR) {
                        return err;
                    }
                }
            }
        }
        returnCodes.push_back(code);
    }
    return sendMessage(new SubackMessage(m->fh->PacketID, returnCodes));
}

MQTT_ERROR BrokerSideClient::recvSubackMessage(SubackMessage* m) {return INVALID_MESSAGE_CAME;}

MQTT_ERROR BrokerSideClient::recvUnsubscribeMessage(UnsubscribeMessage* m) {
    if (m->topics.size() == 0) {
        return PROTOCOL_VIOLATION;
    }

    MQTT_ERROR err = NO_ERROR;
    for (std::vector<std::string>::iterator it = m->topics.begin(); it != m->topics.end(); it++) {
        this->broker->topicRoot->deleteSubscriber(this->ID, *it, err);
        this->subTopics.erase(*it);
    }

    this->sendMessage(new UnsubackMessage(m->fh->PacketID));
    return err;
}

MQTT_ERROR BrokerSideClient::recvUnsubackMessage(UnsubackMessage* m) {return INVALID_MESSAGE_CAME;}
MQTT_ERROR BrokerSideClient::recvPingreqMessage(PingreqMessage* m) {return NO_ERROR;}
MQTT_ERROR BrokerSideClient::recvPingrespMessage(PingrespMessage* m) {return INVALID_MESSAGE_CAME;}
MQTT_ERROR BrokerSideClient::recvDisconnectMessage(DisconnectMessage* m) {return NO_ERROR;}
<commit_msg>add downgrade loop<commit_after>#include "broker.h"
#include "frame.h"
#include <sstream>
#include <thread>
#include <sys/socket.h>

Broker::Broker() {
    topicRoot = new TopicNode("", "");
}

Broker::~Broker() {
    delete topicRoot;
}

MQTT_ERROR Broker::Start() {
    struct sockaddr_in addr;
    int listener = socket(AF_INET, SOCK_STREAM, 0);
    addr.sin_family = AF_INET;
    addr.sin_port = 8883;
    addr.sin_addr.s_addr = INADDR_ANY;
    bind(listener, (struct sockaddr *)&addr, sizeof(addr));
    listen(listener, 5);
    while (true) {
        struct sockaddr_in client;
        unsigned int len = sizeof(client);
        int sock = accept(listener, (struct sockaddr *)&client, &len);
        BrokerSideClient* bc = new BrokerSideClient(new Transport(sock, &client), this);
        //std::thread t(bc->readMessageLoop());
        //t.join();
    }

    return NO_ERROR;
}

MQTT_ERROR Broker::checkQoSAndPublish(BrokerSideClient* requestClient, uint8_t publisherQoS, uint8_t requestedQoS, bool retain, std::string topic, std::string message) {
    uint16_t id = 0;
    MQTT_ERROR err = NO_ERROR;
    uint8_t qos = publisherQoS;
    if (requestedQoS < publisherQoS) {
        // QoS downgrade
        qos = requestedQoS;
    }
    if (qos > 0) {
        err = requestClient->getUsablePacketID(&id);
        if (err != NO_ERROR) {
            return err;
        }
    }
    err = requestClient->sendMessage(new PublishMessage(false, qos, retain, id, topic, message));
    return err;
}

std::string Broker::ApplyDummyClientID() {
    std::stringstream ss;
    ss << "DummyClientID" << clients.size() + 1;
    return ss.str();
}

BrokerSideClient::BrokerSideClient(Transport* ct, Broker* b) : broker(b), Terminal("", NULL, 0, NULL) {
    this->ct = ct;
}

BrokerSideClient::~BrokerSideClient() {}

void BrokerSideClient::setPreviousSession(BrokerSideClient* ps) {
    subTopics = ps->subTopics;
    packetIDMap = ps->packetIDMap;
    cleanSession = ps->cleanSession;
    will = ps->will;
    user = ps->user;
    keepAlive = ps->keepAlive;
}

MQTT_ERROR BrokerSideClient::recvConnectMessage(ConnectMessage* m) {return NO_ERROR;}
MQTT_ERROR BrokerSideClient::recvConnackMessage(ConnackMessage* m) {return INVALID_MESSAGE_CAME;}
MQTT_ERROR BrokerSideClient::recvPublishMessage(PublishMessage* m) {
    if (m->fh->Dup) {
        // re-delivered
    } else {
        // first time delivery
    }

    MQTT_ERROR err = NO_ERROR;
    if (m->fh->Retain) {
        std::string data = m->payload;
        if (m->fh->QoS == 0 && data.size() > 0) {
            data = "";
        }
        broker->topicRoot->applyRetain(m->topicName, m->fh->QoS, data, err);
        if (err != NO_ERROR) {
            return err;
        }
    }

    std::vector<TopicNode*> nodes = broker->topicRoot->getTopicNode(m->topicName, true, err);
    if (err != NO_ERROR) {
        return err;
    }

    for (std::map<std::string, uint8_t>::iterator it = nodes[0]->subscribers.begin(); it != nodes[0]->subscribers.end(); it++) {
        if (nodes[0]->subscribers.find(it->first) == nodes[0]->subscribers.end()) {
            continue;
        }
        BrokerSideClient* subscriber = broker->clients[it->first];
        err = broker->checkQoSAndPublish(subscriber, m->fh->QoS, it->second, false, m->topicName, m->payload);
        }

    switch (m->fh->QoS) {
    case 0:
        if (m->fh->PacketID != 0){
            return PACKET_ID_SHOULD_BE_ZERO;
        }
    case 1:
        sendMessage(new PubackMessage(m->fh->PacketID));
    case 2:
        sendMessage(new PubrecMessage(m->fh->PacketID));
    }

    return err;
}

MQTT_ERROR BrokerSideClient::recvPubackMessage(PubackMessage* m) {
    if (m->fh->PacketID > 0) {
        return ackMessage(m->fh->PacketID);
    }
    return NO_ERROR;
}

MQTT_ERROR BrokerSideClient::recvPubrecMessage(PubrecMessage* m) {
    MQTT_ERROR err = ackMessage(m->fh->PacketID);
    if (err < 0) {
        return err;
    }
    err = sendMessage(new PubrelMessage(m->fh->PacketID));
    return err;
}

MQTT_ERROR BrokerSideClient::recvPubrelMessage(PubrelMessage* m) {
    MQTT_ERROR err = ackMessage(m->fh->PacketID);
    if (err < 0) {
        return err;
    }
    err = sendMessage(new PubcompMessage(m->fh->PacketID));
    return err;
}

MQTT_ERROR BrokerSideClient::recvPubcompMessage(PubcompMessage* m) {
    return ackMessage(m->fh->PacketID);
}

MQTT_ERROR BrokerSideClient::recvSubscribeMessage(SubscribeMessage* m) {
    std::vector<SubackCode> returnCodes;

    MQTT_ERROR err; // this sould be duplicate?
    for (std::vector<SubscribeTopic*>::iterator it = m->subTopics.begin(); it != m->subTopics.end(); it++) {
        std::vector<TopicNode*> nodes = broker->topicRoot->getTopicNode((*it)->topic, true, err);
        SubackCode code = (SubackCode)(*it)->qos;

        if (err != NO_ERROR) {
            code = FAILURE;
        } else {
            for (std::vector<TopicNode*>::iterator nIt = nodes.begin(); nIt != nodes.end(); nIt++) {
                (*nIt)->subscribers[ID] = (*it)->qos;
                subTopics[(*it)->topic] = (*it)->qos;
                if ((*nIt)->retainMessage.size() > 0) {
                    err = this->broker->checkQoSAndPublish(this, (*nIt)->retainQoS, (*it)->qos, true, (*nIt)->fullPath,(*nIt)->retainMessage);
                    if (err != NO_ERROR) {
                        return err;
                    }
                }
            }
        }
        returnCodes.push_back(code);
    }
    return sendMessage(new SubackMessage(m->fh->PacketID, returnCodes));
}

MQTT_ERROR BrokerSideClient::recvSubackMessage(SubackMessage* m) {return INVALID_MESSAGE_CAME;}

MQTT_ERROR BrokerSideClient::recvUnsubscribeMessage(UnsubscribeMessage* m) {
    if (m->topics.size() == 0) {
        return PROTOCOL_VIOLATION;
    }

    MQTT_ERROR err = NO_ERROR;
    for (std::vector<std::string>::iterator it = m->topics.begin(); it != m->topics.end(); it++) {
        this->broker->topicRoot->deleteSubscriber(this->ID, *it, err);
        this->subTopics.erase(*it);
    }

    this->sendMessage(new UnsubackMessage(m->fh->PacketID));
    return err;
}

MQTT_ERROR BrokerSideClient::recvUnsubackMessage(UnsubackMessage* m) {return INVALID_MESSAGE_CAME;}
MQTT_ERROR BrokerSideClient::recvPingreqMessage(PingreqMessage* m) {return NO_ERROR;}
MQTT_ERROR BrokerSideClient::recvPingrespMessage(PingrespMessage* m) {return INVALID_MESSAGE_CAME;}
MQTT_ERROR BrokerSideClient::recvDisconnectMessage(DisconnectMessage* m) {return NO_ERROR;}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#include "db/skiplist.h"

#include <atomic>
#include <set>

#include "gtest/gtest.h"
#include "leveldb/env.h"
#include "port/port.h"
#include "port/thread_annotations.h"
#include "util/arena.h"
#include "util/hash.h"
#include "util/random.h"
#include "util/testutil.h"

namespace leveldb {

typedef uint64_t Key;

struct Comparator {
  int operator()(const Key& a, const Key& b) const {
    if (a < b) {
      return -1;
    } else if (a > b) {
      return +1;
    } else {
      return 0;
    }
  }
};

TEST(SkipTest, Empty) {
  Arena arena;
  Comparator cmp;
  SkipList<Key, Comparator> list(cmp, &arena);
  ASSERT_TRUE(!list.Contains(10));

  SkipList<Key, Comparator>::Iterator iter(&list);
  ASSERT_TRUE(!iter.Valid());
  iter.SeekToFirst();
  ASSERT_TRUE(!iter.Valid());
  iter.Seek(100);
  ASSERT_TRUE(!iter.Valid());
  iter.SeekToLast();
  ASSERT_TRUE(!iter.Valid());
}

TEST(SkipTest, InsertAndLookup) {
  const int N = 2000;
  const int R = 5000;
  Random rnd(1000);
  std::set<Key> keys;
  Arena arena;
  Comparator cmp;
  SkipList<Key, Comparator> list(cmp, &arena);
  for (int i = 0; i < N; i++) {
    Key key = rnd.Next() % R;
    if (keys.insert(key).second) {
      list.Insert(key);
    }
  }

  for (int i = 0; i < R; i++) {
    if (list.Contains(i)) {
      ASSERT_EQ(keys.count(i), 1);
    } else {
      ASSERT_EQ(keys.count(i), 0);
    }
  }

  // Simple iterator tests
  {
    SkipList<Key, Comparator>::Iterator iter(&list);
    ASSERT_TRUE(!iter.Valid());

    iter.Seek(0);
    ASSERT_TRUE(iter.Valid());
    ASSERT_EQ(*(keys.begin()), iter.key());

    iter.SeekToFirst();
    ASSERT_TRUE(iter.Valid());
    ASSERT_EQ(*(keys.begin()), iter.key());

    iter.SeekToLast();
    ASSERT_TRUE(iter.Valid());
    ASSERT_EQ(*(keys.rbegin()), iter.key());
  }

  // Forward iteration test
  for (int i = 0; i < R; i++) {
    SkipList<Key, Comparator>::Iterator iter(&list);
    iter.Seek(i);

    // Compare against model iterator
    std::set<Key>::iterator model_iter = keys.lower_bound(i);
    for (int j = 0; j < 3; j++) {
      if (model_iter == keys.end()) {
        ASSERT_TRUE(!iter.Valid());
        break;
      } else {
        ASSERT_TRUE(iter.Valid());
        ASSERT_EQ(*model_iter, iter.key());
        ++model_iter;
        iter.Next();
      }
    }
  }

  // Backward iteration test
  {
    SkipList<Key, Comparator>::Iterator iter(&list);
    iter.SeekToLast();

    // Compare against model iterator
    for (std::set<Key>::reverse_iterator model_iter = keys.rbegin();
         model_iter != keys.rend(); ++model_iter) {
      ASSERT_TRUE(iter.Valid());
      ASSERT_EQ(*model_iter, iter.key());
      iter.Prev();
    }
    ASSERT_TRUE(!iter.Valid());
  }
}

// We want to make sure that with a single writer and multiple
// concurrent readers (with no synchronization other than when a
// reader's iterator is created), the reader always observes all the
// data that was present in the skip list when the iterator was
// constructed.  Because insertions are happening concurrently, we may
// also observe new values that were inserted since the iterator was
// constructed, but we should never miss any values that were present
// at iterator construction time.
//
// We generate multi-part keys:
//     <key,gen,hash>
// where:
//     key is in range [0..K-1]
//     gen is a generation number for key
//     hash is hash(key,gen)
//
// The insertion code picks a random key, sets gen to be 1 + the last
// generation number inserted for that key, and sets hash to Hash(key,gen).
//
// At the beginning of a read, we snapshot the last inserted
// generation number for each key.  We then iterate, including random
// calls to Next() and Seek().  For every key we encounter, we
// check that it is either expected given the initial snapshot or has
// been concurrently added since the iterator started.
class ConcurrentTest {
 private:
  static constexpr uint32_t K = 4;

  static uint64_t key(Key key) { return (key >> 40); }
  static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; }
  static uint64_t hash(Key key) { return key & 0xff; }

  static uint64_t HashNumbers(uint64_t k, uint64_t g) {
    uint64_t data[2] = {k, g};
    return Hash(reinterpret_cast<char*>(data), sizeof(data), 0);
  }

  static Key MakeKey(uint64_t k, uint64_t g) {
    static_assert(sizeof(Key) == sizeof(uint64_t), "");
    assert(k <= K);  // We sometimes pass K to seek to the end of the skiplist
    assert(g <= 0xffffffffu);
    return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff));
  }

  static bool IsValidKey(Key k) {
    return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff);
  }

  static Key RandomTarget(Random* rnd) {
    switch (rnd->Next() % 10) {
      case 0:
        // Seek to beginning
        return MakeKey(0, 0);
      case 1:
        // Seek to end
        return MakeKey(K, 0);
      default:
        // Seek to middle
        return MakeKey(rnd->Next() % K, 0);
    }
  }

  // Per-key generation
  struct State {
    std::atomic<int> generation[K];
    void Set(int k, int v) {
      generation[k].store(v, std::memory_order_release);
    }
    int Get(int k) { return generation[k].load(std::memory_order_acquire); }

    State() {
      for (int k = 0; k < K; k++) {
        Set(k, 0);
      }
    }
  };

  // Current state of the test
  State current_;

  Arena arena_;

  // SkipList is not protected by mu_.  We just use a single writer
  // thread to modify it.
  SkipList<Key, Comparator> list_;

 public:
  ConcurrentTest() : list_(Comparator(), &arena_) {}

  // REQUIRES: External synchronization
  void WriteStep(Random* rnd) {
    const uint32_t k = rnd->Next() % K;
    const intptr_t g = current_.Get(k) + 1;
    const Key key = MakeKey(k, g);
    list_.Insert(key);
    current_.Set(k, g);
  }

  void ReadStep(Random* rnd) {
    // Remember the initial committed state of the skiplist.
    State initial_state;
    for (int k = 0; k < K; k++) {
      initial_state.Set(k, current_.Get(k));
    }

    Key pos = RandomTarget(rnd);
    SkipList<Key, Comparator>::Iterator iter(&list_);
    iter.Seek(pos);
    while (true) {
      Key current;
      if (!iter.Valid()) {
        current = MakeKey(K, 0);
      } else {
        current = iter.key();
        ASSERT_TRUE(IsValidKey(current)) << current;
      }
      ASSERT_LE(pos, current) << "should not go backwards";

      // Verify that everything in [pos,current) was not present in
      // initial_state.
      while (pos < current) {
        ASSERT_LT(key(pos), K) << pos;

        // Note that generation 0 is never inserted, so it is ok if
        // <*,0,*> is missing.
        ASSERT_TRUE((gen(pos) == 0) ||
                    (gen(pos) > static_cast<Key>(initial_state.Get(key(pos)))))
            << "key: " << key(pos) << "; gen: " << gen(pos)
            << "; initgen: " << initial_state.Get(key(pos));

        // Advance to next key in the valid key space
        if (key(pos) < key(current)) {
          pos = MakeKey(key(pos) + 1, 0);
        } else {
          pos = MakeKey(key(pos), gen(pos) + 1);
        }
      }

      if (!iter.Valid()) {
        break;
      }

      if (rnd->Next() % 2) {
        iter.Next();
        pos = MakeKey(key(pos), gen(pos) + 1);
      } else {
        Key new_target = RandomTarget(rnd);
        if (new_target > pos) {
          pos = new_target;
          iter.Seek(new_target);
        }
      }
    }
  }
};

// Simple test that does single-threaded testing of the ConcurrentTest
// scaffolding.
TEST(SkipTest, ConcurrentWithoutThreads) {
  ConcurrentTest test;
  Random rnd(test::RandomSeed());
  for (int i = 0; i < 10000; i++) {
    test.ReadStep(&rnd);
    test.WriteStep(&rnd);
  }
}

class TestState {
 public:
  ConcurrentTest t_;
  int seed_;
  std::atomic<bool> quit_flag_;

  enum ReaderState { STARTING, RUNNING, DONE };

  explicit TestState(int s)
      : seed_(s), quit_flag_(false), state_(STARTING), state_cv_(&mu_) {}

  void Wait(ReaderState s) LOCKS_EXCLUDED(mu_) {
    mu_.Lock();
    while (state_ != s) {
      state_cv_.Wait();
    }
    mu_.Unlock();
  }

  void Change(ReaderState s) LOCKS_EXCLUDED(mu_) {
    mu_.Lock();
    state_ = s;
    state_cv_.Signal();
    mu_.Unlock();
  }

 private:
  port::Mutex mu_;
  ReaderState state_ GUARDED_BY(mu_);
  port::CondVar state_cv_ GUARDED_BY(mu_);
};

static void ConcurrentReader(void* arg) {
  TestState* state = reinterpret_cast<TestState*>(arg);
  Random rnd(state->seed_);
  int64_t reads = 0;
  state->Change(TestState::RUNNING);
  while (!state->quit_flag_.load(std::memory_order_acquire)) {
    state->t_.ReadStep(&rnd);
    ++reads;
  }
  state->Change(TestState::DONE);
}

static void RunConcurrent(int run) {
  const int seed = test::RandomSeed() + (run * 100);
  Random rnd(seed);
  const int N = 1000;
  const int kSize = 1000;
  for (int i = 0; i < N; i++) {
    if ((i % 100) == 0) {
      fprintf(stderr, "Run %d of %d\n", i, N);
    }
    TestState state(seed + 1);
    Env::Default()->Schedule(ConcurrentReader, &state);
    state.Wait(TestState::RUNNING);
    for (int i = 0; i < kSize; i++) {
      state.t_.WriteStep(&rnd);
    }
    state.quit_flag_.store(true, std::memory_order_release);
    state.Wait(TestState::DONE);
  }
}

TEST(SkipTest, Concurrent1) { RunConcurrent(1); }
TEST(SkipTest, Concurrent2) { RunConcurrent(2); }
TEST(SkipTest, Concurrent3) { RunConcurrent(3); }
TEST(SkipTest, Concurrent4) { RunConcurrent(4); }
TEST(SkipTest, Concurrent5) { RunConcurrent(5); }

}  // namespace leveldb

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>Fix C++11 build.<commit_after>// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#include "db/skiplist.h"

#include <atomic>
#include <set>

#include "gtest/gtest.h"
#include "leveldb/env.h"
#include "port/port.h"
#include "port/thread_annotations.h"
#include "util/arena.h"
#include "util/hash.h"
#include "util/random.h"
#include "util/testutil.h"

namespace leveldb {

typedef uint64_t Key;

struct Comparator {
  int operator()(const Key& a, const Key& b) const {
    if (a < b) {
      return -1;
    } else if (a > b) {
      return +1;
    } else {
      return 0;
    }
  }
};

TEST(SkipTest, Empty) {
  Arena arena;
  Comparator cmp;
  SkipList<Key, Comparator> list(cmp, &arena);
  ASSERT_TRUE(!list.Contains(10));

  SkipList<Key, Comparator>::Iterator iter(&list);
  ASSERT_TRUE(!iter.Valid());
  iter.SeekToFirst();
  ASSERT_TRUE(!iter.Valid());
  iter.Seek(100);
  ASSERT_TRUE(!iter.Valid());
  iter.SeekToLast();
  ASSERT_TRUE(!iter.Valid());
}

TEST(SkipTest, InsertAndLookup) {
  const int N = 2000;
  const int R = 5000;
  Random rnd(1000);
  std::set<Key> keys;
  Arena arena;
  Comparator cmp;
  SkipList<Key, Comparator> list(cmp, &arena);
  for (int i = 0; i < N; i++) {
    Key key = rnd.Next() % R;
    if (keys.insert(key).second) {
      list.Insert(key);
    }
  }

  for (int i = 0; i < R; i++) {
    if (list.Contains(i)) {
      ASSERT_EQ(keys.count(i), 1);
    } else {
      ASSERT_EQ(keys.count(i), 0);
    }
  }

  // Simple iterator tests
  {
    SkipList<Key, Comparator>::Iterator iter(&list);
    ASSERT_TRUE(!iter.Valid());

    iter.Seek(0);
    ASSERT_TRUE(iter.Valid());
    ASSERT_EQ(*(keys.begin()), iter.key());

    iter.SeekToFirst();
    ASSERT_TRUE(iter.Valid());
    ASSERT_EQ(*(keys.begin()), iter.key());

    iter.SeekToLast();
    ASSERT_TRUE(iter.Valid());
    ASSERT_EQ(*(keys.rbegin()), iter.key());
  }

  // Forward iteration test
  for (int i = 0; i < R; i++) {
    SkipList<Key, Comparator>::Iterator iter(&list);
    iter.Seek(i);

    // Compare against model iterator
    std::set<Key>::iterator model_iter = keys.lower_bound(i);
    for (int j = 0; j < 3; j++) {
      if (model_iter == keys.end()) {
        ASSERT_TRUE(!iter.Valid());
        break;
      } else {
        ASSERT_TRUE(iter.Valid());
        ASSERT_EQ(*model_iter, iter.key());
        ++model_iter;
        iter.Next();
      }
    }
  }

  // Backward iteration test
  {
    SkipList<Key, Comparator>::Iterator iter(&list);
    iter.SeekToLast();

    // Compare against model iterator
    for (std::set<Key>::reverse_iterator model_iter = keys.rbegin();
         model_iter != keys.rend(); ++model_iter) {
      ASSERT_TRUE(iter.Valid());
      ASSERT_EQ(*model_iter, iter.key());
      iter.Prev();
    }
    ASSERT_TRUE(!iter.Valid());
  }
}

// We want to make sure that with a single writer and multiple
// concurrent readers (with no synchronization other than when a
// reader's iterator is created), the reader always observes all the
// data that was present in the skip list when the iterator was
// constructed.  Because insertions are happening concurrently, we may
// also observe new values that were inserted since the iterator was
// constructed, but we should never miss any values that were present
// at iterator construction time.
//
// We generate multi-part keys:
//     <key,gen,hash>
// where:
//     key is in range [0..K-1]
//     gen is a generation number for key
//     hash is hash(key,gen)
//
// The insertion code picks a random key, sets gen to be 1 + the last
// generation number inserted for that key, and sets hash to Hash(key,gen).
//
// At the beginning of a read, we snapshot the last inserted
// generation number for each key.  We then iterate, including random
// calls to Next() and Seek().  For every key we encounter, we
// check that it is either expected given the initial snapshot or has
// been concurrently added since the iterator started.
class ConcurrentTest {
 private:
  static constexpr uint32_t K = 4;

  static uint64_t key(Key key) { return (key >> 40); }
  static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; }
  static uint64_t hash(Key key) { return key & 0xff; }

  static uint64_t HashNumbers(uint64_t k, uint64_t g) {
    uint64_t data[2] = {k, g};
    return Hash(reinterpret_cast<char*>(data), sizeof(data), 0);
  }

  static Key MakeKey(uint64_t k, uint64_t g) {
    static_assert(sizeof(Key) == sizeof(uint64_t), "");
    assert(k <= K);  // We sometimes pass K to seek to the end of the skiplist
    assert(g <= 0xffffffffu);
    return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff));
  }

  static bool IsValidKey(Key k) {
    return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff);
  }

  static Key RandomTarget(Random* rnd) {
    switch (rnd->Next() % 10) {
      case 0:
        // Seek to beginning
        return MakeKey(0, 0);
      case 1:
        // Seek to end
        return MakeKey(K, 0);
      default:
        // Seek to middle
        return MakeKey(rnd->Next() % K, 0);
    }
  }

  // Per-key generation
  struct State {
    std::atomic<int> generation[K];
    void Set(int k, int v) {
      generation[k].store(v, std::memory_order_release);
    }
    int Get(int k) { return generation[k].load(std::memory_order_acquire); }

    State() {
      for (int k = 0; k < K; k++) {
        Set(k, 0);
      }
    }
  };

  // Current state of the test
  State current_;

  Arena arena_;

  // SkipList is not protected by mu_.  We just use a single writer
  // thread to modify it.
  SkipList<Key, Comparator> list_;

 public:
  ConcurrentTest() : list_(Comparator(), &arena_) {}

  // REQUIRES: External synchronization
  void WriteStep(Random* rnd) {
    const uint32_t k = rnd->Next() % K;
    const intptr_t g = current_.Get(k) + 1;
    const Key key = MakeKey(k, g);
    list_.Insert(key);
    current_.Set(k, g);
  }

  void ReadStep(Random* rnd) {
    // Remember the initial committed state of the skiplist.
    State initial_state;
    for (int k = 0; k < K; k++) {
      initial_state.Set(k, current_.Get(k));
    }

    Key pos = RandomTarget(rnd);
    SkipList<Key, Comparator>::Iterator iter(&list_);
    iter.Seek(pos);
    while (true) {
      Key current;
      if (!iter.Valid()) {
        current = MakeKey(K, 0);
      } else {
        current = iter.key();
        ASSERT_TRUE(IsValidKey(current)) << current;
      }
      ASSERT_LE(pos, current) << "should not go backwards";

      // Verify that everything in [pos,current) was not present in
      // initial_state.
      while (pos < current) {
        ASSERT_LT(key(pos), K) << pos;

        // Note that generation 0 is never inserted, so it is ok if
        // <*,0,*> is missing.
        ASSERT_TRUE((gen(pos) == 0) ||
                    (gen(pos) > static_cast<Key>(initial_state.Get(key(pos)))))
            << "key: " << key(pos) << "; gen: " << gen(pos)
            << "; initgen: " << initial_state.Get(key(pos));

        // Advance to next key in the valid key space
        if (key(pos) < key(current)) {
          pos = MakeKey(key(pos) + 1, 0);
        } else {
          pos = MakeKey(key(pos), gen(pos) + 1);
        }
      }

      if (!iter.Valid()) {
        break;
      }

      if (rnd->Next() % 2) {
        iter.Next();
        pos = MakeKey(key(pos), gen(pos) + 1);
      } else {
        Key new_target = RandomTarget(rnd);
        if (new_target > pos) {
          pos = new_target;
          iter.Seek(new_target);
        }
      }
    }
  }
};

// Needed when building in C++11 mode.
constexpr uint32_t ConcurrentTest::K;

// Simple test that does single-threaded testing of the ConcurrentTest
// scaffolding.
TEST(SkipTest, ConcurrentWithoutThreads) {
  ConcurrentTest test;
  Random rnd(test::RandomSeed());
  for (int i = 0; i < 10000; i++) {
    test.ReadStep(&rnd);
    test.WriteStep(&rnd);
  }
}

class TestState {
 public:
  ConcurrentTest t_;
  int seed_;
  std::atomic<bool> quit_flag_;

  enum ReaderState { STARTING, RUNNING, DONE };

  explicit TestState(int s)
      : seed_(s), quit_flag_(false), state_(STARTING), state_cv_(&mu_) {}

  void Wait(ReaderState s) LOCKS_EXCLUDED(mu_) {
    mu_.Lock();
    while (state_ != s) {
      state_cv_.Wait();
    }
    mu_.Unlock();
  }

  void Change(ReaderState s) LOCKS_EXCLUDED(mu_) {
    mu_.Lock();
    state_ = s;
    state_cv_.Signal();
    mu_.Unlock();
  }

 private:
  port::Mutex mu_;
  ReaderState state_ GUARDED_BY(mu_);
  port::CondVar state_cv_ GUARDED_BY(mu_);
};

static void ConcurrentReader(void* arg) {
  TestState* state = reinterpret_cast<TestState*>(arg);
  Random rnd(state->seed_);
  int64_t reads = 0;
  state->Change(TestState::RUNNING);
  while (!state->quit_flag_.load(std::memory_order_acquire)) {
    state->t_.ReadStep(&rnd);
    ++reads;
  }
  state->Change(TestState::DONE);
}

static void RunConcurrent(int run) {
  const int seed = test::RandomSeed() + (run * 100);
  Random rnd(seed);
  const int N = 1000;
  const int kSize = 1000;
  for (int i = 0; i < N; i++) {
    if ((i % 100) == 0) {
      fprintf(stderr, "Run %d of %d\n", i, N);
    }
    TestState state(seed + 1);
    Env::Default()->Schedule(ConcurrentReader, &state);
    state.Wait(TestState::RUNNING);
    for (int i = 0; i < kSize; i++) {
      state.t_.WriteStep(&rnd);
    }
    state.quit_flag_.store(true, std::memory_order_release);
    state.Wait(TestState::DONE);
  }
}

TEST(SkipTest, Concurrent1) { RunConcurrent(1); }
TEST(SkipTest, Concurrent2) { RunConcurrent(2); }
TEST(SkipTest, Concurrent3) { RunConcurrent(3); }
TEST(SkipTest, Concurrent4) { RunConcurrent(4); }
TEST(SkipTest, Concurrent5) { RunConcurrent(5); }

}  // namespace leveldb

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/*
** Author(s):
**  - Herve Cuche <hcuche@aldebaran-robotics.com>
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <qimessaging/object.hpp>
#include <qimessaging/gateway.hpp>
#include <qimessaging/session.hpp>
#include <qimessaging/transport/transport_server.hpp>
#include <qimessaging/transport/network_thread.hpp>
#include <boost/bind.hpp>

static int reqid = 500;

namespace qi
{
  class GatewayPrivate : public TransportServerInterface, public TransportSocketInterface
  {
  public:
    virtual void newConnection()
    {
      TransportSocket *socket = _ts.nextPendingConnection();
      if (!socket)
        return;
      socket->setDelegate(this);
    }

    void run(TransportSocket *client, const qi::Message &msg)
    {
      qi::Message retval;
      if (msg.function() == "services")
        services(msg, retval);
      else if (msg.function() == "service")
        service(msg, retval);
      else
      {
        qi::Object* obj;
        std::map<std::string, qi::Object*>::iterator servicesIt;
        servicesIt = _services.find(msg.destination());
        if (servicesIt == _services.end())
        {
          obj = _session->service(msg.destination());
          _services[msg.destination()] = obj;
        }
        else
        {
          obj = servicesIt->second;
        }

        qi::DataStream ds(msg.data());
        qi::DataStream rs;

        obj->metaCall(msg.function(), "", ds, rs);

        retval.setType(qi::Message::Reply);
        retval.setId(msg.id());
        retval.setSource(msg.destination());
        retval.setDestination(msg.source());
        retval.setData(rs.str());
      }

      client->send(retval);

    }

    virtual void onReadyRead(TransportSocket *client, const qi::Message &msg)
    {
      boost::thread thd = boost::thread(boost::bind(&GatewayPrivate::run, this, client, msg));
    }

    virtual void onWriteDone(TransportSocket *client)
    {
    }

    virtual void onConnected(TransportSocket *client)
    {
    }

    virtual void onDisconnected(TransportSocket *client)
    {
    }

    void services(const qi::Message &msg, qi::Message &retval)
    {
      std::vector<std::string> result = _session->services();

      qi::DataStream d;
      d << result;

      retval.setType(qi::Message::Reply);
      retval.setId(msg.id());
      retval.setSource(msg.destination());
      retval.setDestination(msg.source());
      retval.setData(d.str());
    }

    void service(const qi::Message &msg, qi::Message &retval)
    {
      qi::DataStream d;
      d << _endpoints;

      retval.setType(qi::Message::Reply);
      retval.setId(msg.id());
      retval.setSource(msg.destination());
      retval.setDestination(msg.source());
      retval.setData(d.str());
    }

  public:
    std::map<std::string, qi::Object*> _services;
    std::vector<qi::EndpointInfo>      _endpoints;
    TransportServer                    _ts;
    qi::Session                       *_session;
  }; // !GatewayPrivate

  Gateway::Gateway()
    : _p(new GatewayPrivate())
  {
  }

  Gateway::~Gateway()
  {
    delete _p;
  }

  void Gateway::start(const std::string &addr, unsigned short port, qi::Session *session)
  {
    qi::EndpointInfo e;
    e.type = "tcp";
    e.ip = addr;
    e.port = port;
    _p->_endpoints.push_back(e);

    std::vector<std::string> result = session->services();

    _p->_session = session;
    _p->_ts.setDelegate(_p);
    _p->_ts.start(addr, port, _p->_session->_nthd->getEventBase());
  }

  void Gateway::advertiseService(const std::string &name, qi::Object *obj)
  {
    _p->_services[name] = obj;
  }
} // !qi
<commit_msg>New async gateway<commit_after>/*
** Author(s):
**  - Herve Cuche <hcuche@aldebaran-robotics.com>
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <qimessaging/object.hpp>
#include <qimessaging/gateway.hpp>
#include <qimessaging/session.hpp>
#include <qimessaging/transport/transport_server.hpp>
#include <qimessaging/transport/network_thread.hpp>
#include <boost/bind.hpp>
#include <qi/log.hpp>

static int reqid = 500;

namespace qi
{

class GatewayPrivate : public TransportServerInterface, public TransportSocketInterface
{
public:

  typedef std::vector< std::pair<qi::Message, TransportSocket *> > PendingMessageVector;
  typedef std::map< std::string, PendingMessageVector>             PendingMessageMap;

  typedef std::map< int, std::pair<int, TransportSocket *> >       RequestIdMap;
  typedef std::map<TransportSocket *, RequestIdMap>                ServiceRequestIdMap;

  typedef std::map<std::string, qi::TransportSocket *>             ServiceSocketMap;

  GatewayPrivate();

protected:

  void handleClientRead(TransportSocket *client, const qi::Message &msg);
  void handleGatewayServiceRead(TransportSocket *master, const qi::Message &msg);
  void handleServiceRead(TransportSocket *service, const qi::Message &msg);
  void forwardClientMessage(TransportSocket *client,
                            TransportSocket *service,
                            const qi::Message &msg);
  //ServerInterface
  virtual void newConnection();

  //SocketInterface
  virtual void onReadyRead(TransportSocket *client, const qi::Message &msg);
  virtual void onWriteDone(TransportSocket *client);
  virtual void onConnected(TransportSocket *client);
  virtual void onDisconnected(TransportSocket *client);

public:
  ServiceSocketMap                             _services;
  std::vector<qi::TransportSocket *>           _clients;
  std::vector<std::string>                     _endpoints;
  TransportServer                              _ts;
  TransportSocket                             *_tso;
  qi::NetworkThread                           *_nthd;

  //for each service socket, associated if request to a client socket. 0 mean gateway
  ServiceRequestIdMap                         _serviceToClient;
  PendingMessageMap                           _pendingMessage;
}; // !GatewayPrivate

GatewayPrivate::GatewayPrivate()
{
  _nthd = new qi::NetworkThread();

  _tso = new qi::TransportSocket();
  _tso->setDelegate(this);
  _tso->connect("127.0.0.1", 5555, _nthd->getEventBase());
  _tso->waitForConnected();
  _services["qi.master"] = _tso;
}

void GatewayPrivate::newConnection()
{
  TransportSocket *socket = _ts.nextPendingConnection();
  if (!socket)
    return;
  socket->setDelegate(this);
  _clients.push_back(socket);
}

void GatewayPrivate::forwardClientMessage(TransportSocket *client, TransportSocket *service, const qi::Message &msg)
{
  qi::Message   servMsg(msg);
  RequestIdMap &reqIdMap = _serviceToClient[service];

  servMsg.setId(reqid++);
  reqIdMap[servMsg.id()] = std::make_pair(msg.id(), client);
  service->send(servMsg);
}

//From Client
// C.1/ new client which ask master for a service        => return gateway endpoint, enter C.2 or C.3
// C.2/ new message from client to unknown destination   => ask master, enter S.1
// C.3/ new message from client to know services         => forward, enter S.3
void GatewayPrivate::handleClientRead(TransportSocket *client, const qi::Message &msg)
{
  // C.1/ We are the Master!
  // unique case: service always return gateway endpoint
  if (msg.destination() == "qi.master" && msg.function() == "service")
  {
    qi::Message retval;
    qi::DataStream d;
    std::vector<std::string> tmpEndPoint;
    tmpEndPoint.push_back(msg.destination());
    for (int i = 0; i < _endpoints.size(); ++i)
      tmpEndPoint.push_back(_endpoints[i]);

    d << tmpEndPoint;

    retval.setType(qi::Message::Reply);
    retval.setId(msg.id());
    retval.setSource(msg.destination());
    retval.setDestination(msg.source());
    retval.setFunction(msg.function());
    retval.setData(d.str());
    client->send(retval);
    return;
  }

  std::map<std::string, qi::TransportSocket*>::iterator it;
  it = _services.find(msg.destination());

  //// C.3/
  if (it != _services.end())
  {
    forwardClientMessage(client, it->second, msg);
  }
  //// C.2/
  else
  {
    //request to gateway to have the endpoint
    qi::Message masterMsg;
    qi::DataStream d;
    d << msg.destination();

    //associate the transportSoket client = 0
    //this will allow S.1 to be handle correctly
    masterMsg.setType(qi::Message::Call);
    masterMsg.setDestination("qi.master");
    masterMsg.setFunction("service");
    masterMsg.setData(d.str());

    RequestIdMap &reqIdMap = _serviceToClient[_tso];
    reqIdMap[masterMsg.id()] = std::make_pair(0, (qi::TransportSocket*)NULL);

    //store the pending message
    PendingMessageMap::iterator itPending;
    itPending = _pendingMessage.find(msg.destination());
    if (itPending == _pendingMessage.end())
    {
      PendingMessageVector pendingMsg;
      pendingMsg.push_back(std::make_pair(msg, client));
      _pendingMessage[msg.destination()] = pendingMsg;
    }
    else
    {
      PendingMessageVector &pendingMsg = itPending->second;
      pendingMsg.push_back(std::make_pair(msg, client));
    }
    _tso->send(masterMsg);

    return;
  }
}

//Only be master request
//S1 answer from master for us
void GatewayPrivate::handleGatewayServiceRead(TransportSocket *master, const qi::Message &msg)
{
  ServiceRequestIdMap::iterator it;
  // get the map of request => client
  it = _serviceToClient.find(master);

  //assert it's really from master
  if (it == _serviceToClient.end())
    return;

  std::vector<std::string>      result;
  qi::DataStream                d(msg.data());

  d >> result;

  qi::EndpointInfo endpoint;
  size_t begin = 0;
  size_t end = 0;
  end = result[1].find(":");
  endpoint.type = result[1].substr(begin, end);
  begin = end + 3;
  end = result[1].find(":", begin);
  endpoint.ip = result[1].substr(begin, end - begin);
  begin = end + 1;
  std::stringstream ss(result[1].substr(begin));
  ss >> endpoint.port;

  //new socket
  qi::TransportSocket *servSocket = new qi::TransportSocket();
  servSocket->setDelegate(this);
  //call connect
  servSocket->connect(endpoint.ip, endpoint.port, _nthd->getEventBase());

  //TODO: serviceName = endpointIt.name();
  std::string serviceName = result[0];
  _services[serviceName] = servSocket;
  //   go to S.2
}

//From Service
// S.1/ new message from master from us                  => create new service, enter S.2
// S.3/ new message from service                         => forward, (end)
void GatewayPrivate::handleServiceRead(TransportSocket *service, const qi::Message &msg)
{
  // get the map of request => client
  ServiceRequestIdMap::iterator it;
  it = _serviceToClient.find(service);
  // should not fail
  if (it == _serviceToClient.end())
  {
    //log error
    return;
  }

  RequestIdMap &request = it->second;
  RequestIdMap::iterator itReq;

  itReq = request.find(msg.id());
  if (itReq != request.end())
  {
    if (itReq->second.second == 0)
      handleGatewayServiceRead(service, msg);
    else
    {
      // S.3
      // id should be rewritten
      qi::Message ans(msg);
      ans.setId(itReq->second.first);
      itReq->second.second->send(ans);
    }
  }
}

void GatewayPrivate::onReadyRead(TransportSocket *client, const qi::Message &msg)
{
  if (std::find(_clients.begin(), _clients.end(), client) != _clients.end())
  {
    // Client
    handleClientRead(client, msg);
  }
  else
  {
    // Server
    handleServiceRead(client, msg);
  }
}

void GatewayPrivate::onWriteDone(TransportSocket *client)
{
}

// S.2/ new service connection                           => handle pending message, jump to S.3
void GatewayPrivate::onConnected(TransportSocket *service)
{
  if (service == _tso)
    return;

  std::string serviceName;
  ServiceSocketMap::const_iterator it;

  //TODO: optimise?  O(log(n)) instead O(n)
  for (it = _services.begin(); it != _services.end(); ++it)
  {
    if ((TransportSocket *)it->second == service)
    {
      serviceName = it->first;
      break;
    }
  }

  if (serviceName.empty())
  {
    qiLogError("Gateway", "fail baby\n");
    return;
  }

  //handle pending message
  PendingMessageVector &pmv = _pendingMessage[serviceName];
  PendingMessageVector::iterator itPending;

  for (itPending = pmv.begin(); itPending != pmv.end(); ++itPending)
  {
    TransportSocket *client = itPending->second;
    qi::Message &msg = itPending->first;
    forwardClientMessage(client, service, msg);
  }
}

void GatewayPrivate::onDisconnected(TransportSocket *client)
{
}

Gateway::Gateway()
  : _p(new GatewayPrivate())
{
}

Gateway::~Gateway()
{
  delete _p;
}

void Gateway::start(const std::string &addr, unsigned short port, qi::Session *session)
{
  std::stringstream ss;
  ss << "tcp://" << addr << ":" << port;
  _p->_endpoints.push_back(ss.str());

  _p->_ts.setDelegate(_p);
  _p->_ts.start(addr, port, session->_nthd->getEventBase());
}
} // !qi
<|endoftext|>


<commit_before>/*
*  Author(s):
*  - Cedric Gestes <gestes@aldebaran-robotics.com>
*  - Herve Cuche <hcuche@aldebaran-robotics.com>
*
*  Copyright (C) 2012 Aldebaran Robotics
*/

#include <qimessaging/session.hpp>
#include <qimessaging/message.hpp>
#include <qimessaging/datastream.hpp>
#include <qimessaging/transport_socket.hpp>
#include <qimessaging/object.hpp>
#include <qimessaging/service_info.hpp>
#include "src/remoteobject_p.hpp"
#include "src/network_thread.hpp"
#include "src/session_p.hpp"

namespace qi {

  SessionInterface::~SessionInterface() {
  }

  SessionPrivate::SessionPrivate(qi::Session *session)
    : _serviceSocket(new qi::TransportSocket()),
      _networkThread(new qi::NetworkThread()),
      _self(session),
      _callbacks(0)
  {
    _serviceSocket->setCallbacks(this);
  }

  SessionPrivate::~SessionPrivate() {
    _networkThread->stop();
    delete _networkThread;
    delete _serviceSocket;
  }

  void SessionPrivate::onSocketConnected(TransportSocket *client)
  {
    // Come from connection between transport socket and service
    std::map<void *, ServiceRequest>::iterator it = _futureConnect.find(client);
    if (it != _futureConnect.end())
    {
      ServiceRequest &sr = it->second;
      qi::Message msg;
      msg.setType(qi::Message::Type_Call);
      msg.setService(sr.serviceId);
      msg.setPath(qi::Message::Path_Main);
      msg.setFunction(qi::Message::Function_MetaObject);
      _futureService[msg.id()] = sr;
      _futureConnect.erase(client);
      client->send(msg);
      return;
    }

    {
      // Comes from session connected to ServiceDirectory
      if (_callbacks)
        _callbacks->onSessionConnected(_self);
      return;
    }
  }

  void SessionPrivate::onSocketConnectionError(TransportSocket *client)
  {
    std::map<void *, ServiceRequest>::iterator it = _futureConnect.find(client);
    if (it != _futureConnect.end())
    {
      _futureConnect.erase(client);
      return;
    }

    {
      if (_callbacks)
        _callbacks->onSessionConnectionError(_self);
      return;
    }
  }

  void SessionPrivate::onSocketDisconnected(TransportSocket *client)
  {
    if (_callbacks)
      _callbacks->onSessionDisconnected(_self);
  }

  void SessionPrivate::onSocketReadyRead(qi::TransportSocket *client, int id)
  {
    qi::Message msg;
    client->read(id, &msg);

    // request for service method
    std::map<int, ServiceRequest>::iterator it;
    {
      boost::mutex::scoped_lock l(_mutexFuture);
      it = _futureService.find(id);
    }
    if (it != _futureService.end())
    {
      if (client == _serviceSocket)
        serviceEndpointEnd(id, client, &msg, it->second); // Come from ServiceDirectory with endpoints to connect
      else
        serviceMetaobjectEnd(id, client, &msg, it->second); // Come from Service to get the MetaObject
      return;
    }

    // request from services method
    std::map<int, qi::Promise<std::vector<qi::ServiceInfo> > >::iterator it2;
    {
      boost::mutex::scoped_lock l(_mutexFuture);
      it2 = _futureServices.find(id);
    }
    if (it2 != _futureServices.end())
    {
      servicesEnd(client, &msg, it2->second);
      {
        boost::mutex::scoped_lock l(_mutexFuture);
        _futureServices.erase(it2);
      }
      return;
    }

    // Request for register/unregister methods
    std::map<int, qi::FunctorResult>::iterator it3;
    {
      boost::mutex::scoped_lock l(_mutexFuture);
      it3 = _futureFunctor.find(id);
    }
    if (it3 != _futureFunctor.end())
    {
      serviceRegisterUnregisterEnd(id, &msg, it3->second);
      {
        boost::mutex::scoped_lock l(_mutexFuture);
        _futureFunctor.erase(it3);
      }
      return;
    }
  }

  void SessionPrivate::serviceRegisterUnregisterEnd(int id,
                                                    qi::Message *msg,
                                                    qi::FunctorResult promise)
  {
    if (!promise.isValid())
    {
      qiLogError("qimessaging.sessionprivate") << "No promise found for req id:" << id;
      return;
    }

    switch (msg->type())
    {
      case qi::Message::Type_Reply:
        promise.setValue(msg->buffer());
        break;
      case qi::Message::Type_Event:
        promise.setValue(msg->buffer());
        break;
      default:
        qiLogError("qimessaging.sessionprivate") << "Message (#" << id << ") type not handled: "
            << msg->type();
        return;
    }
  }

  void SessionPrivate::serviceEndpointEnd(int id,
                                          qi::TransportSocket *QI_UNUSED(client),
                                          qi::Message *msg,
                                          ServiceRequest &sr)
  {
    qi::ServiceInfo si;
    qi::DataStream  d(msg->buffer());
    d >> si;

    if (d.status() == qi::DataStream::Status_Ok)
    {
      sr.serviceId = si.serviceId();
      for (std::vector<std::string>::const_iterator it = si.endpoints().begin();
           it != si.endpoints().end();
           ++it)
      {
        qi::Url url(*it);
        if (sr.protocol == qi::Url::Protocol_Any || sr.protocol == url.protocol())
        {
          qi::TransportSocket *ts = NULL;
          ts = new qi::TransportSocket();
          ts->setCallbacks(this);
          {
            boost::mutex::scoped_lock l(_mutexFuture);
            _futureConnect[ts] = sr;
            _futureService.erase(id);
          }
          ts->connect(_self, url);
          return;
        }
      }
    }
    {
      boost::mutex::scoped_lock l(_mutexFuture);
      _futureService.erase(id);
    }
    return;
  }

  void SessionPrivate::serviceMetaobjectEnd(int QI_UNUSED(id),
                                            qi::TransportSocket *client,
                                            qi::Message *msg,
                                            ServiceRequest &sr)
  {
    qi::MetaObject *mo = new qi::MetaObject();
    qi::DataStream  d(msg->buffer());
    d >> *mo;

    if (d.status() == qi::DataStream::Status_Ok)
    {
      client->setCallbacks(0);
      qi::RemoteObject *robj = new qi::RemoteObject(client, sr.serviceId, mo);
      qi::Object *obj;
      obj = robj;
      sr.promise.setValue(obj);
    }
  }

  void SessionPrivate::servicesEnd(qi::TransportSocket *QI_UNUSED(client),
                                   qi::Message *msg,
                                   qi::Promise<std::vector<qi::ServiceInfo> > &fut)
  {
    std::vector<qi::ServiceInfo> result;
    qi::DataStream d(msg->buffer());
    d >> result;
    if (d.status() == qi::DataStream::Status_Ok)
      fut.setValue(result);
  }

  qi::Future<unsigned int> SessionPrivate::registerService(const qi::ServiceInfo &si)
  {
    qi::Message msg;
    msg.setType(qi::Message::Type_Call);
    msg.setService(qi::Message::Service_ServiceDirectory);
    msg.setPath(qi::Message::Path_Main);
    msg.setFunction(qi::Message::ServiceDirectoryFunction_RegisterService);

    qi::Buffer     buf;
    qi::DataStream d(buf);
    d << si;

    qi::Future<unsigned int> future;
    if (d.status() == qi::DataStream::Status_Ok)
    {
      msg.setBuffer(buf);

      qi::FunctorResult        ret;
      qi::makeFunctorResult<unsigned int>(&ret, &future);
      {
        boost::mutex::scoped_lock l(_mutexFuture);
        _futureFunctor[msg.id()] = ret;
      }

      if (!_serviceSocket->send(msg))
      {
        qi::DataStream dout(msg.buffer());
        qi::ServiceInfo si;
        dout >> si;
        qiLogError("qimessaging.Session") << "Error while register service: "
                                          << si.name() << " request";
        qi::Buffer buf;
        qi::DataStream dse(buf);

        dse << "Error while register service: "
            << si.name() << " request";
        ret.setError(buf);
      }
    }
    return future;
  }

  qi::Future<void> SessionPrivate::unregisterService(unsigned int idx)
  {
    qi::Message msg;
    qi::Buffer  buf;
    msg.setType(qi::Message::Type_Call);
    msg.setService(qi::Message::Service_ServiceDirectory);
    msg.setPath(qi::Message::Path_Main);
    msg.setFunction(qi::Message::ServiceDirectoryFunction_UnregisterService);

    qi::DataStream d(buf);
    d << idx;

    qi::Future<void> future;
    if (d.status() == qi::DataStream::Status_Ok)
    {
      msg.setBuffer(buf);

      qi::FunctorResult ret;
      qi::makeFunctorResult<void>(&ret, &future);
      {
        boost::mutex::scoped_lock l(_mutexFuture);
        _futureFunctor[msg.id()] = ret;
      }

      if (!_serviceSocket->send(msg))
      {
        qi::DataStream dout(msg.buffer());
        unsigned int idx;
        dout >> idx;
        qiLogError("qimessaging.Session") << "Error while unregister serviceId: "
                                          << idx << " request";

        qi::Buffer buf;
        qi::DataStream dse(buf);

        dse << "Error while unregister serviceId: "
            << idx << " request";
        ret.setError(buf);
      }
    }
    return future;
  }

  // ###### Session
  Session::Session()
    : _p(new SessionPrivate(this))
  {
  }

  Session::~Session()
  {
    delete _p;
  }

  bool Session::connect(const qi::Url &serviceDirectoryURL)
  {
    return _p->_serviceSocket->connect(_p->_self, serviceDirectoryURL);
  }

  bool Session::disconnect()
  {
    _p->_serviceSocket->disconnect();
    return true;
  }

  bool Session::waitForConnected(int msecs)
  {
    return _p->_serviceSocket->waitForConnected(msecs);
  }

  bool Session::waitForDisconnected(int msecs)
  {
    return _p->_serviceSocket->waitForDisconnected(msecs);
  }

  qi::Future< std::vector<ServiceInfo> > Session::services()
  {
    qi::Promise<std::vector<ServiceInfo> > promise;
    qi::Message msg;

    msg.setType(qi::Message::Type_Call);
    msg.setService(qi::Message::Service_ServiceDirectory);
    msg.setPath(qi::Message::Path_Main);
    msg.setFunction(qi::Message::ServiceDirectoryFunction_Services);
    {
      boost::mutex::scoped_lock l(_p->_mutexFuture);
      _p->_futureServices[msg.id()] = promise;
    }
    _p->_serviceSocket->send(msg);
    return promise.future();
  }

  qi::Future< qi::Object * > Session::service(const std::string &service,
                                              qi::Url::Protocol  type)
  {
    ServiceRequest sr;
    qi::Message    msg;
    qi::Buffer     buf;

    msg.setBuffer(buf);
    sr.name      = service;
    sr.protocol  = type;

    msg.setType(qi::Message::Type_Call);
    msg.setService(qi::Message::Service_ServiceDirectory);
    msg.setPath(qi::Message::Path_Main);
    msg.setFunction(qi::Message::ServiceDirectoryFunction_Service);
    qi::DataStream dr(buf);
    dr << service;
    {
      boost::mutex::scoped_lock l(_p->_mutexFuture);
      _p->_futureService[msg.id()] = sr;
    }
    _p->_serviceSocket->send(msg);
    return sr.promise.future();
  }

  bool Session::join()
  {
    _p->_networkThread->join();
    return true;
  }

  void Session::setCallbacks(SessionInterface *delegate) {
    _p->_callbacks = delegate;
  }

  qi::Url Session::url() const {
    return _p->_serviceSocket->url();
  }
}
<commit_msg>session: error handling<commit_after>/*
*  Author(s):
*  - Cedric Gestes <gestes@aldebaran-robotics.com>
*  - Herve Cuche <hcuche@aldebaran-robotics.com>
*
*  Copyright (C) 2012 Aldebaran Robotics
*/

#include <qimessaging/session.hpp>
#include <qimessaging/message.hpp>
#include <qimessaging/datastream.hpp>
#include <qimessaging/transport_socket.hpp>
#include <qimessaging/object.hpp>
#include <qimessaging/service_info.hpp>
#include "src/remoteobject_p.hpp"
#include "src/network_thread.hpp"
#include "src/session_p.hpp"

namespace qi {

  SessionInterface::~SessionInterface() {
  }

  SessionPrivate::SessionPrivate(qi::Session *session)
    : _serviceSocket(new qi::TransportSocket()),
      _networkThread(new qi::NetworkThread()),
      _self(session),
      _callbacks(0)
  {
    _serviceSocket->setCallbacks(this);
  }

  SessionPrivate::~SessionPrivate() {
    _networkThread->stop();
    delete _networkThread;
    delete _serviceSocket;
  }

  void SessionPrivate::onSocketConnected(TransportSocket *client)
  {
    // Come from connection between transport socket and service
    std::map<void *, ServiceRequest>::iterator it = _futureConnect.find(client);
    if (it != _futureConnect.end())
    {
      ServiceRequest &sr = it->second;
      qi::Message msg;
      msg.setType(qi::Message::Type_Call);
      msg.setService(sr.serviceId);
      msg.setPath(qi::Message::Path_Main);
      msg.setFunction(qi::Message::Function_MetaObject);
      _futureService[msg.id()] = sr;
      _futureConnect.erase(client);
      client->send(msg);
      return;
    }

    {
      // Comes from session connected to ServiceDirectory
      if (_callbacks)
        _callbacks->onSessionConnected(_self);
      return;
    }
  }

  void SessionPrivate::onSocketConnectionError(TransportSocket *client)
  {
    std::map<void *, ServiceRequest>::iterator it = _futureConnect.find(client);
    if (it != _futureConnect.end())
    {
      _futureConnect.erase(client);
      return;
    }

    {
      if (_callbacks)
        _callbacks->onSessionConnectionError(_self);
      return;
    }
  }

  void SessionPrivate::onSocketDisconnected(TransportSocket *client)
  {
    if (_callbacks)
      _callbacks->onSessionDisconnected(_self);
  }

  void SessionPrivate::onSocketReadyRead(qi::TransportSocket *client, int id)
  {
    qi::Message msg;
    client->read(id, &msg);

    // request for service method
    std::map<int, ServiceRequest>::iterator it;
    {
      boost::mutex::scoped_lock l(_mutexFuture);
      it = _futureService.find(id);
    }
    if (it != _futureService.end())
    {
      if (client == _serviceSocket)
        serviceEndpointEnd(id, client, &msg, it->second); // Come from ServiceDirectory with endpoints to connect
      else
        serviceMetaobjectEnd(id, client, &msg, it->second); // Come from Service to get the MetaObject
      return;
    }

    // request from services method
    std::map<int, qi::Promise<std::vector<qi::ServiceInfo> > >::iterator it2;
    {
      boost::mutex::scoped_lock l(_mutexFuture);
      it2 = _futureServices.find(id);
    }
    if (it2 != _futureServices.end())
    {
      servicesEnd(client, &msg, it2->second);
      {
        boost::mutex::scoped_lock l(_mutexFuture);
        _futureServices.erase(it2);
      }
      return;
    }

    // Request for register/unregister methods
    std::map<int, qi::FunctorResult>::iterator it3;
    {
      boost::mutex::scoped_lock l(_mutexFuture);
      it3 = _futureFunctor.find(id);
    }
    if (it3 != _futureFunctor.end())
    {
      serviceRegisterUnregisterEnd(id, &msg, it3->second);
      {
        boost::mutex::scoped_lock l(_mutexFuture);
        _futureFunctor.erase(it3);
      }
      return;
    }
    qiLogError("qimessaging") << "Session::Private: onSocketReadyRead: unknow message id";
  }

  void SessionPrivate::serviceRegisterUnregisterEnd(int id,
                                                    qi::Message *msg,
                                                    qi::FunctorResult promise)
  {
    if (!promise.isValid())
    {
      qiLogError("qimessaging.sessionprivate") << "No promise found for req id:" << id;
      return;
    }

    switch (msg->type())
    {
    case qi::Message::Type_Reply:
      promise.setValue(msg->buffer());
      break;
    case qi::Message::Type_Event:
      promise.setValue(msg->buffer());
      break;
    default:
      {
        qi::Buffer b;
        qi::DataStream ds(b);
        ds << "Bad message type";
        promise.setError(b);
        qiLogError("qimessaging.sessionprivate") << "Message (#" << id << ") type not handled: "
                                                 << msg->type();
        return;
      }
    }
  }

  void SessionPrivate::serviceEndpointEnd(int id,
                                          qi::TransportSocket *QI_UNUSED(client),
                                          qi::Message *msg,
                                          ServiceRequest &sr)
  {
    qi::ServiceInfo si;
    qi::DataStream  d(msg->buffer());
    d >> si;

    if (d.status() == qi::DataStream::Status_Ok)
    {
      sr.serviceId = si.serviceId();
      for (std::vector<std::string>::const_iterator it = si.endpoints().begin();
           it != si.endpoints().end();
           ++it)
      {
        qi::Url url(*it);
        if (sr.protocol == qi::Url::Protocol_Any || sr.protocol == url.protocol())
        {
          qi::TransportSocket *ts = NULL;
          ts = new qi::TransportSocket();
          ts->setCallbacks(this);
          {
            boost::mutex::scoped_lock l(_mutexFuture);
            _futureConnect[ts] = sr;
            _futureService.erase(id);
          }
          ts->connect(_self, url);
          return;
        }
      }
    }
    {
      boost::mutex::scoped_lock l(_mutexFuture);
      _futureService[id].promise.setError("No service found");
      _futureService.erase(id);
    }
    return;
  }

  void SessionPrivate::serviceMetaobjectEnd(int QI_UNUSED(id),
                                            qi::TransportSocket *client,
                                            qi::Message *msg,
                                            ServiceRequest &sr)
  {
    qi::MetaObject *mo = new qi::MetaObject();
    qi::DataStream  d(msg->buffer());
    d >> *mo;

    if (d.status() == qi::DataStream::Status_Ok)
    {
      client->setCallbacks(0);
      qi::RemoteObject *robj = new qi::RemoteObject(client, sr.serviceId, mo);
      qi::Object *obj;
      obj = robj;
      sr.promise.setValue(obj);
    } else {
      sr.promise.setError("Serialization error");
    }
  }

  void SessionPrivate::servicesEnd(qi::TransportSocket *QI_UNUSED(client),
                                   qi::Message *msg,
                                   qi::Promise<std::vector<qi::ServiceInfo> > &promise)
  {
    std::vector<qi::ServiceInfo> result;
    qi::DataStream d(msg->buffer());
    d >> result;
    if (d.status() == qi::DataStream::Status_Ok)
      promise.setValue(result);
    else
      promise.setError("Serialization error");
  }

  qi::Future<unsigned int> SessionPrivate::registerService(const qi::ServiceInfo &si)
  {
    qi::Message msg;
    msg.setType(qi::Message::Type_Call);
    msg.setService(qi::Message::Service_ServiceDirectory);
    msg.setPath(qi::Message::Path_Main);
    msg.setFunction(qi::Message::ServiceDirectoryFunction_RegisterService);

    qi::Buffer     buf;
    qi::DataStream d(buf);
    d << si;

    qi::Future<unsigned int> future;
    if (d.status() == qi::DataStream::Status_Ok)
    {
      msg.setBuffer(buf);

      qi::FunctorResult        ret;
      qi::makeFunctorResult<unsigned int>(&ret, &future);
      {
        boost::mutex::scoped_lock l(_mutexFuture);
        _futureFunctor[msg.id()] = ret;
      }

      if (!_serviceSocket->send(msg))
      {
        qi::DataStream dout(msg.buffer());
        qi::ServiceInfo si;
        dout >> si;
        qiLogError("qimessaging.Session") << "Error while register service: "
                                          << si.name() << " request";
        qi::Buffer buf;
        qi::DataStream dse(buf);

        dse << "Error while register service: "
            << si.name() << " request";
        ret.setError(buf);
      }
    } else {
      qi::Promise<unsigned int> prom;
      future = prom.future();
      prom.setError("serialization error");
    }
    return future;
  }

  qi::Future<void> SessionPrivate::unregisterService(unsigned int idx)
  {
    qi::Message msg;
    qi::Buffer  buf;
    msg.setType(qi::Message::Type_Call);
    msg.setService(qi::Message::Service_ServiceDirectory);
    msg.setPath(qi::Message::Path_Main);
    msg.setFunction(qi::Message::ServiceDirectoryFunction_UnregisterService);

    qi::DataStream d(buf);
    d << idx;

    qi::Future<void> future;
    if (d.status() == qi::DataStream::Status_Ok)
    {
      msg.setBuffer(buf);

      qi::FunctorResult ret;
      qi::makeFunctorResult<void>(&ret, &future);
      {
        boost::mutex::scoped_lock l(_mutexFuture);
        _futureFunctor[msg.id()] = ret;
      }

      if (!_serviceSocket->send(msg))
      {
        qi::DataStream dout(msg.buffer());
        unsigned int idx;
        dout >> idx;
        qiLogError("qimessaging.Session") << "Error while unregister serviceId: "
                                          << idx << " request";

        qi::Buffer buf;
        qi::DataStream dse(buf);

        dse << "Error while unregister serviceId: "
            << idx << " request";
        ret.setError(buf);
      }
    }
    return future;
  }

  // ###### Session
  Session::Session()
    : _p(new SessionPrivate(this))
  {
  }

  Session::~Session()
  {
    delete _p;
  }

  bool Session::connect(const qi::Url &serviceDirectoryURL)
  {
    return _p->_serviceSocket->connect(_p->_self, serviceDirectoryURL);
  }

  bool Session::disconnect()
  {
    _p->_serviceSocket->disconnect();
    return true;
  }

  bool Session::waitForConnected(int msecs)
  {
    return _p->_serviceSocket->waitForConnected(msecs);
  }

  bool Session::waitForDisconnected(int msecs)
  {
    return _p->_serviceSocket->waitForDisconnected(msecs);
  }

  qi::Future< std::vector<ServiceInfo> > Session::services()
  {
    qi::Promise<std::vector<ServiceInfo> > promise;
    qi::Message msg;

    msg.setType(qi::Message::Type_Call);
    msg.setService(qi::Message::Service_ServiceDirectory);
    msg.setPath(qi::Message::Path_Main);
    msg.setFunction(qi::Message::ServiceDirectoryFunction_Services);
    {
      boost::mutex::scoped_lock l(_p->_mutexFuture);
      _p->_futureServices[msg.id()] = promise;
    }
    _p->_serviceSocket->send(msg);
    return promise.future();
  }

  qi::Future< qi::Object * > Session::service(const std::string &service,
                                              qi::Url::Protocol  type)
  {
    ServiceRequest sr;
    qi::Message    msg;
    qi::Buffer     buf;

    msg.setBuffer(buf);
    sr.name      = service;
    sr.protocol  = type;

    msg.setType(qi::Message::Type_Call);
    msg.setService(qi::Message::Service_ServiceDirectory);
    msg.setPath(qi::Message::Path_Main);
    msg.setFunction(qi::Message::ServiceDirectoryFunction_Service);
    qi::DataStream dr(buf);
    dr << service;
    {
      boost::mutex::scoped_lock l(_p->_mutexFuture);
      _p->_futureService[msg.id()] = sr;
    }
    _p->_serviceSocket->send(msg);
    return sr.promise.future();
  }

  bool Session::join()
  {
    _p->_networkThread->join();
    return true;
  }

  void Session::setCallbacks(SessionInterface *delegate) {
    _p->_callbacks = delegate;
  }

  qi::Url Session::url() const {
    return _p->_serviceSocket->url();
  }
}
<|endoftext|>