<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    Plane.h
  \author  Jens Krueger
           SCI Institute
           University of Utah
*/

#include "Plane.h"

const PLANE<float> ExtendedPlane::ms_Plane(0,0,1,0);
const FLOATVECTOR3 ExtendedPlane::ms_Perpendicular(0,1,0);
const FLOATVECTOR3 ExtendedPlane::ms_Point(0,0,0);

ExtendedPlane::ExtendedPlane(const PLANE<float>& p,
                             const FLOATVECTOR3& perp,
                             const FLOATVECTOR3& pt): m_Plane(p),
                                                      m_Perpendicular(perp),
                                                      m_Point(pt) {
}

void ExtendedPlane::Transform(const FLOATMATRIX4& mat)
{
  m_Plane = m_Plane * mat;
  m_Perpendicular = m_Perpendicular * mat;
}

void ExtendedPlane::TransformIT(const FLOATMATRIX4& mat)
{
  FLOATMATRIX4 mIT(mat.inverse());
  mIT = mIT.Transpose();
  m_Plane = m_Plane * mIT;
  m_Perpendicular = (FLOATVECTOR4(m_Perpendicular,0) * mIT).xyz();
  m_Perpendicular.normalize();
}

bool ExtendedPlane::Quad(const FLOATVECTOR3& vEye,
                         const FLOATVECTOR3& vDatasetCenter,
                         std::vector<FLOATVECTOR3>& quad,
                         const float fWidgetSize)
{
  FLOATVECTOR3 vec = m_Plane.xyz() % m_Perpendicular;
  float plane_d = m_Plane.d();
  FLOATVECTOR3 pt_on_plane(-(plane_d-0.01f)*m_Plane.xyz());

  float dist = m_Plane.xyz() ^ vDatasetCenter;
  FLOATVECTOR3 vCenter = vDatasetCenter - (dist+plane_d)*m_Plane.xyz();
  pt_on_plane = vCenter;

  FLOATVECTOR3 viewDir = pt_on_plane-vEye;

  // "push back" the triangulated quad
  if((m_Plane.xyz() ^ viewDir) < 0) {
    quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(vec  - m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));

    quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(-vec + m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));
  } else {
    quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(vec  - m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));

    quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(-vec + m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));
  }

  // "push back" the lines for the border
  quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));
  quad.push_back((pt_on_plane + (fWidgetSize*(vec  - m_Perpendicular))));

  quad.push_back((pt_on_plane + (fWidgetSize*(vec  - m_Perpendicular))));
  quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));

  quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));
  quad.push_back((pt_on_plane + (fWidgetSize*(-vec + m_Perpendicular))));

  quad.push_back((pt_on_plane + (fWidgetSize*(-vec + m_Perpendicular))));
  quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));

  return (m_Plane.xyz() ^ viewDir) < 0;
}

/// Sets the plane back to default values.
void ExtendedPlane::Default()
{
  m_Plane = ms_Plane;
  m_Perpendicular = ms_Perpendicular;
  m_Point = ms_Point;
}
<commit_msg>Fix Transform.<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    Plane.h
  \author  Jens Krueger
           SCI Institute
           University of Utah
*/

#include "Plane.h"

const PLANE<float> ExtendedPlane::ms_Plane(0,0,1,0);
const FLOATVECTOR3 ExtendedPlane::ms_Perpendicular(0,1,0);
const FLOATVECTOR3 ExtendedPlane::ms_Point(0,0,0);

ExtendedPlane::ExtendedPlane(const PLANE<float>& p,
                             const FLOATVECTOR3& perp,
                             const FLOATVECTOR3& pt): m_Plane(p),
                                                      m_Perpendicular(perp),
                                                      m_Point(pt) {
}

void ExtendedPlane::Transform(const FLOATMATRIX4& mat)
{
  m_Plane = m_Plane * mat;
  m_Perpendicular = (FLOATVECTOR4(m_Perpendicular,0) * mat).xyz();
  m_Perpendicular.normalize();
  m_Point = (FLOATVECTOR4(m_Point,1) * mat).xyz();
}

void ExtendedPlane::TransformIT(const FLOATMATRIX4& mat)
{
  FLOATMATRIX4 mIT(mat.inverse());
  mIT = mIT.Transpose();
  m_Plane = m_Plane * mIT;
  m_Perpendicular = (FLOATVECTOR4(m_Perpendicular,0) * mIT).xyz();
  m_Perpendicular.normalize();
  m_Point = (FLOATVECTOR4(m_Point,1) * mIT).xyz();
}

bool ExtendedPlane::Quad(const FLOATVECTOR3& vEye,
                         const FLOATVECTOR3& vDatasetCenter,
                         std::vector<FLOATVECTOR3>& quad,
                         const float fWidgetSize)
{
  FLOATVECTOR3 vec = m_Plane.xyz() % m_Perpendicular;
  float plane_d = m_Plane.d();
  FLOATVECTOR3 pt_on_plane(-(plane_d-0.01f)*m_Plane.xyz());

  float dist = m_Plane.xyz() ^ vDatasetCenter;
  FLOATVECTOR3 vCenter = vDatasetCenter - (dist+plane_d)*m_Plane.xyz();
  pt_on_plane = vCenter;

  FLOATVECTOR3 viewDir = pt_on_plane-vEye;

  // "push back" the triangulated quad
  if((m_Plane.xyz() ^ viewDir) < 0) {
    quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(vec  - m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));

    quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(-vec + m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));
  } else {
    quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(vec  - m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));

    quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(-vec + m_Perpendicular))));
    quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));
  }

  // "push back" the lines for the border
  quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));
  quad.push_back((pt_on_plane + (fWidgetSize*(vec  - m_Perpendicular))));

  quad.push_back((pt_on_plane + (fWidgetSize*(vec  - m_Perpendicular))));
  quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));

  quad.push_back((pt_on_plane + (fWidgetSize*(-vec - m_Perpendicular))));
  quad.push_back((pt_on_plane + (fWidgetSize*(-vec + m_Perpendicular))));

  quad.push_back((pt_on_plane + (fWidgetSize*(-vec + m_Perpendicular))));
  quad.push_back((pt_on_plane + (fWidgetSize*(vec  + m_Perpendicular))));

  return (m_Plane.xyz() ^ viewDir) < 0;
}

/// Sets the plane back to default values.
void ExtendedPlane::Default()
{
  m_Plane = ms_Plane;
  m_Perpendicular = ms_Perpendicular;
  m_Point = ms_Point;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>

#include <iostream>
#include <string>
#include <boost/regex.hpp>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <boost/algorithm/string.hpp>

#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>

#include <glog/logging.h>

#include "osquery/core.h"
#include "osquery/database.h"

namespace osquery {
namespace tables {

void crawl_proc(QueryData &results) {
  boost::filesystem::path dir_path = "/proc";
  for (boost::filesystem::directory_iterator itr(dir_path), end_itr; itr != end_itr; ++itr) {

    if (itr->path().string().find("self") != std::string::npos) {
      continue;
    }

    if (boost::filesystem::is_directory(itr->status())) {
      std::string d_path = itr->path().string();

      // make sure /proc/*/fd is there
      d_path.append("/fd");
      struct stat s;
      int err = stat(d_path.c_str(), &s);
      if (err == -1) {
        continue;
      }

      for (boost::filesystem::directory_iterator i(d_path), e_i; i != e_i; ++i) {
        char* linkname = (char *)malloc(32);
        std::string path = i->path().string();
        auto r = readlink(path.c_str(), linkname, 32);
        std::string link_str(linkname, linkname + 32);

        // matches socket:[13415]
        if (link_str.find("socket") != std::string::npos) {
          boost::regex e("[0-9]+");
          boost::smatch inode;
          boost::regex_search(link_str, inode, e);
          if (inode[0].str().length() > 0) {
            std::vector<std::string> pid;
            boost::split(pid, path, boost::is_any_of("/"));
            Row r;
            r["pid"] = boost::lexical_cast<std::string>(pid[2].c_str());
            r["inode"] = boost::lexical_cast<std::string>(inode[0].str());
            results.push_back(r);
            free(linkname);
            continue;
          }
        }
        free(linkname);
      }
    }
  }
  return;
}

QueryData genSocketInode() {
  QueryData results;
  crawl_proc(results);
  return results;
}
}
}
<commit_msg>free(linkname) and no more 'self'<commit_after>#include <stdio.h>
#include <stdlib.h>

#include <iostream>
#include <string>
#include <boost/regex.hpp>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <boost/algorithm/string.hpp>

#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>

#include <glog/logging.h>

#include "osquery/core.h"
#include "osquery/database.h"

namespace osquery {
namespace tables {

void crawl_proc(QueryData &results) {
  boost::filesystem::path dir_path = "/proc";
  for (boost::filesystem::directory_iterator itr(dir_path), end_itr; itr != end_itr; ++itr) {

    if (boost::filesystem::is_directory(itr->status())) {
      std::string d_path = itr->path().string();

      // make sure /proc/*/fd is there
      d_path.append("/fd");
      struct stat s;
      int err = stat(d_path.c_str(), &s);
      if (err == -1) {
        continue;
      }

      for (boost::filesystem::directory_iterator i(d_path), e_i; i != e_i; ++i) {
        char* linkname = (char *)malloc(32);
        std::string path = i->path().string();
        auto r = readlink(path.c_str(), linkname, 32);
        std::string link_str(linkname, linkname + 32);
        free(linkname);

        // matches socket:[13415]
        if (link_str.find("socket") != std::string::npos) {
          boost::regex e("[0-9]+");
          boost::smatch inode;
          boost::regex_search(link_str, inode, e);
          if (inode[0].str().length() > 0) {
            std::vector<std::string> pid;
            boost::split(pid, path, boost::is_any_of("/"));
            Row r;
            r["pid"] = boost::lexical_cast<std::string>(pid[2].c_str());
            r["inode"] = boost::lexical_cast<std::string>(inode[0].str());
            results.push_back(r);
            continue;
          }
        }
      }
    }
  }
  return;
}

QueryData genSocketInode() {
  QueryData results;
  crawl_proc(results);
  return results;
}
}
}
<|endoftext|>


<commit_before>#include "StorageFileChunk.h"
#include "System/FileSystem.h"
#include "StorageBulkCursor.h"
#include "StoragePageCache.h"
#include "FDGuard.h"

static int KeyCmp(const ReadBuffer& a, const ReadBuffer& b)
{
    return ReadBuffer::Cmp(a, b);
}

static const ReadBuffer& Key(StorageFileKeyValue* kv)
{
    return kv->GetKey();
}

StorageFileChunk::StorageFileChunk() : headerPage(this)
{
    prev = next = this;
    written = false;
    dataPagesSize = 64;
    dataPages = (StorageDataPage**) malloc(sizeof(StorageDataPage*) * dataPagesSize);
    memset(dataPages, 0, sizeof(StorageDataPage*) * dataPagesSize);
    indexPage = NULL;
    bloomPage = NULL;
    numDataPages = 0;
    fileSize = 0;
    minLogSegmentID = 0;
}

void StorageFileChunk::ReadHeaderPage()
{
    Buffer      buffer;
    uint32_t    offset;

    offset = 0;

    if (!ReadPage(offset, buffer))
    {
        Log_Message("Unable to read header page from %B at offset %U", &filename, offset);
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }

    if (!headerPage.Read(buffer))
    {
        Log_Message("Unable to parse header page read from %B at offset %U with size %u",
         &filename, offset, buffer.GetLength());
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
}

StorageFileChunk::~StorageFileChunk()
{
    unsigned    i;

    for (i = 0; i < numDataPages; i++)
    {
        if (dataPages[i] != NULL)
        {
            if (dataPages[i]->IsCached())
                StoragePageCache::RemovePage(dataPages[i]);

            delete dataPages[i];
        }
    }
    free(dataPages);

    if (indexPage && indexPage->IsCached())
        StoragePageCache::RemovePage(indexPage);
    delete indexPage;

    if (bloomPage && bloomPage->IsCached())
        StoragePageCache::RemovePage(bloomPage);
    delete bloomPage;
}

void StorageFileChunk::SetFilename(Buffer& filename_)
{
    filename.Write(filename_);
    filename.NullTerminate();
}

Buffer& StorageFileChunk::GetFilename()
{
    return filename;
}

StorageChunk::ChunkState StorageFileChunk::GetChunkState()
{
    if (written)
        return StorageChunk::Written;
    else
        return StorageChunk::Unwritten;
}

void StorageFileChunk::NextBunch(StorageCursorBunch& bunch)
{
    uint32_t                index, offset, pos;
    ReadBuffer              nextKey, key, value;
    StorageFileKeyValue*    it;
    StorageFileKeyValue*    kv;

    nextKey = bunch.GetNextKey();

    if (!indexPage->Locate(nextKey, index, offset))
    {
        index = 0;
        offset = STORAGE_HEADER_PAGE_SIZE;
    }

    if (index >= numDataPages)
    {
        bunch.isLast = true;
        return;
    }

    if (dataPages[index] == NULL)
        LoadDataPage(index, offset, true);

    bunch.buffer.Write(dataPages[index]->buffer);
    FOREACH(it, dataPages[index]->keyValues)
    {
        kv = new StorageFileKeyValue;

        pos = it->GetKey().GetBuffer() - dataPages[index]->buffer.GetBuffer();
        key.Wrap(bunch.buffer.GetBuffer() + pos, it->GetKey().GetLength());
        if (it->GetType() == STORAGE_KEYVALUE_TYPE_SET)
        {
            pos = it->GetValue().GetBuffer() - dataPages[index]->buffer.GetBuffer();
            value.Wrap(bunch.buffer.GetBuffer() + pos, it->GetValue().GetLength());
            kv->Set(key, value);
        }
        else
        {
            kv->Delete(key);
        }

        bunch.keyValues.Insert(kv);
    }

    if (index == (numDataPages - 1))
    {
        bunch.isLast = true;
        return;
    }

    index++;
    if (dataPages[index] == NULL)
        LoadDataPage(index, dataPages[index - 1]->GetSize(), true);

    bunch.nextKey.Write(dataPages[index]->keyValues.First()->GetKey());
    bunch.isLast = false;
}

uint64_t StorageFileChunk::GetChunkID()
{
    return headerPage.GetChunkID();
}

bool StorageFileChunk::UseBloomFilter()
{
    return headerPage.UseBloomFilter();
}

StorageKeyValue* StorageFileChunk::Get(ReadBuffer& key)
{
    uint32_t    index, offset;
    Buffer      buffer;

    if (headerPage.UseBloomFilter())
    {
        if (bloomPage == NULL)
            LoadBloomPage(); // evicted, load back
        if (bloomPage->IsCached())
            StoragePageCache::RegisterHit(bloomPage);
        if (!bloomPage->Check(key))
            return NULL;
    }

    if (indexPage == NULL)
        LoadIndexPage(); // evicted, load back
    if (indexPage->IsCached())
        StoragePageCache::RegisterHit(indexPage);
    if (!indexPage->Locate(key, index, offset))
        return NULL;

    if (dataPages[index] == NULL)
        LoadDataPage(index, offset); // evicted, load back

    if (dataPages[index]->IsCached())
        StoragePageCache::RegisterHit(dataPages[index]);
    return dataPages[index]->Get(key);
}

uint64_t StorageFileChunk::GetMinLogSegmentID()
{
    return minLogSegmentID;
}

uint64_t StorageFileChunk::GetMaxLogSegmentID()
{
    return headerPage.GetLogSegmentID();
}

uint32_t StorageFileChunk::GetMaxLogCommandID()
{
    return headerPage.GetLogCommandID();
}

uint64_t StorageFileChunk::GetSize()
{
    return fileSize;
}

void StorageFileChunk::AddPagesToCache()
{
    uint32_t i;

    if (UseBloomFilter())
        StoragePageCache::AddPage(bloomPage);

    StoragePageCache::AddPage(indexPage);

    for (i = 0; i < numDataPages; i++)
        StoragePageCache::AddPage(dataPages[i]);
}

void StorageFileChunk::OnBloomPageEvicted()
{
    delete bloomPage;
    bloomPage = NULL;
}

void StorageFileChunk::OnIndexPageEvicted()
{
    delete indexPage;
    indexPage = NULL;
}

void StorageFileChunk::OnDataPageEvicted(uint32_t index)
{
    assert(dataPages[index] != NULL);

    delete dataPages[index];
    dataPages[index] = NULL;
}

void StorageFileChunk::LoadBloomPage()
{
    Buffer      buffer;
    uint32_t    offset;

    bloomPage = new StorageBloomPage(this);
    offset = headerPage.GetBloomPageOffset();
    if (!ReadPage(offset, buffer))
    {
        Log_Message("Unable to read bloom page from %B at offset %U", &filename, offset);
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    if (!bloomPage->Read(buffer))
    {
        Log_Message("Unable to parse bloom page read from %B at offset %U with size %u",
         &filename, offset, buffer.GetLength());
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    StoragePageCache::AddPage(bloomPage);
}

void StorageFileChunk::LoadIndexPage()
{
    Buffer      buffer;
    uint32_t    offset;

    indexPage = new StorageIndexPage(this);
    offset = headerPage.GetIndexPageOffset();
    if (!ReadPage(offset, buffer))
    {
        Log_Message("Unable to read index page from %B at offset %U", &filename, offset);
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    if (!indexPage->Read(buffer))
    {
        Log_Message("Unable to parse index page read from %B at offset %U with size %u",
         &filename, offset, buffer.GetLength());
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    StoragePageCache::AddPage(indexPage);
}

void StorageFileChunk::LoadDataPage(uint32_t index, uint32_t offset, bool bulk)
{
    Buffer buffer;

    dataPages[index] = new StorageDataPage(this, index);
    if (!ReadPage(offset, buffer))
    {
        Log_Message("Unable to read data page from %B at offset %U", &filename, offset);
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    if (!dataPages[index]->Read(buffer))
    {
        Log_Message("Unable to parse data page read from %B at offset %U with size %u",
         &filename, offset, buffer.GetLength());
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    StoragePageCache::AddPage(dataPages[index], bulk);
}

void StorageFileChunk::AppendDataPage(StorageDataPage* dataPage)
{
    if (numDataPages == dataPagesSize)
        ExtendDataPageArray();

    dataPages[numDataPages] = dataPage;
    numDataPages++;
}

void StorageFileChunk::ExtendDataPageArray()
{
    StorageDataPage**   newDataPages;
    unsigned            newSize, i;

    newSize = dataPagesSize * 2;
    newDataPages = (StorageDataPage**) malloc(sizeof(StorageDataPage*) * newSize);

    for (i = 0; i < numDataPages; i++)
        newDataPages[i] = dataPages[i];

    free(dataPages);
    dataPages = newDataPages;
    dataPagesSize = newSize;
}

bool StorageFileChunk::ReadPage(uint32_t offset, Buffer& buffer)
{
    uint32_t    size, rest;
    ReadBuffer  parse;
    FDGuard     fd;

    if (fd.Open(filename.GetBuffer(), FS_READONLY) == INVALID_FD)
        return false;

    size = STORAGE_DEFAULT_PAGE_GRAN;
    buffer.Allocate(size);
    if (FS_FileReadOffs(fd.GetFD(), buffer.GetBuffer(), size, offset) != size)
        return false;
    buffer.SetLength(size);

    // first 4 bytes on all pages is the page size
    parse.Wrap(buffer);
    if (!parse.ReadLittle32(size))
        return false;

    rest = size - buffer.GetLength();
    if (rest > 0)
    {
        // read rest
        buffer.Allocate(size);
        if (FS_FileReadOffs(fd.GetFD(), buffer.GetPosition(), rest, offset + buffer.GetLength()) != rest)
            return false;
        buffer.SetLength(size);
    }

    fd.Close();

    return true;
}
<commit_msg>Fixed StorageFileChunk error message output.<commit_after>#include "StorageFileChunk.h"
#include "System/FileSystem.h"
#include "StorageBulkCursor.h"
#include "StoragePageCache.h"
#include "FDGuard.h"

static int KeyCmp(const ReadBuffer& a, const ReadBuffer& b)
{
    return ReadBuffer::Cmp(a, b);
}

static const ReadBuffer& Key(StorageFileKeyValue* kv)
{
    return kv->GetKey();
}

StorageFileChunk::StorageFileChunk() : headerPage(this)
{
    prev = next = this;
    written = false;
    dataPagesSize = 64;
    dataPages = (StorageDataPage**) malloc(sizeof(StorageDataPage*) * dataPagesSize);
    memset(dataPages, 0, sizeof(StorageDataPage*) * dataPagesSize);
    indexPage = NULL;
    bloomPage = NULL;
    numDataPages = 0;
    fileSize = 0;
    minLogSegmentID = 0;
}

void StorageFileChunk::ReadHeaderPage()
{
    Buffer      buffer;
    uint32_t    offset;

    offset = 0;

    if (!ReadPage(offset, buffer))
    {
        Log_Message("Unable to read header page from %s at offset %U", filename.GetBuffer(), offset);
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }

    if (!headerPage.Read(buffer))
    {
        Log_Message("Unable to parse header page read from %s at offset %U with size %u",
         filename.GetBuffer(), offset, buffer.GetLength());
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
}

StorageFileChunk::~StorageFileChunk()
{
    unsigned    i;

    for (i = 0; i < numDataPages; i++)
    {
        if (dataPages[i] != NULL)
        {
            if (dataPages[i]->IsCached())
                StoragePageCache::RemovePage(dataPages[i]);

            delete dataPages[i];
        }
    }
    free(dataPages);

    if (indexPage && indexPage->IsCached())
        StoragePageCache::RemovePage(indexPage);
    delete indexPage;

    if (bloomPage && bloomPage->IsCached())
        StoragePageCache::RemovePage(bloomPage);
    delete bloomPage;
}

void StorageFileChunk::SetFilename(Buffer& filename_)
{
    filename.Write(filename_);
    filename.NullTerminate();
}

Buffer& StorageFileChunk::GetFilename()
{
    return filename;
}

StorageChunk::ChunkState StorageFileChunk::GetChunkState()
{
    if (written)
        return StorageChunk::Written;
    else
        return StorageChunk::Unwritten;
}

void StorageFileChunk::NextBunch(StorageCursorBunch& bunch)
{
    uint32_t                index, offset, pos;
    ReadBuffer              nextKey, key, value;
    StorageFileKeyValue*    it;
    StorageFileKeyValue*    kv;

    nextKey = bunch.GetNextKey();

    if (!indexPage->Locate(nextKey, index, offset))
    {
        index = 0;
        offset = STORAGE_HEADER_PAGE_SIZE;
    }

    if (index >= numDataPages)
    {
        bunch.isLast = true;
        return;
    }

    if (dataPages[index] == NULL)
        LoadDataPage(index, offset, true);

    bunch.buffer.Write(dataPages[index]->buffer);
    FOREACH(it, dataPages[index]->keyValues)
    {
        kv = new StorageFileKeyValue;

        pos = it->GetKey().GetBuffer() - dataPages[index]->buffer.GetBuffer();
        key.Wrap(bunch.buffer.GetBuffer() + pos, it->GetKey().GetLength());
        if (it->GetType() == STORAGE_KEYVALUE_TYPE_SET)
        {
            pos = it->GetValue().GetBuffer() - dataPages[index]->buffer.GetBuffer();
            value.Wrap(bunch.buffer.GetBuffer() + pos, it->GetValue().GetLength());
            kv->Set(key, value);
        }
        else
        {
            kv->Delete(key);
        }

        bunch.keyValues.Insert(kv);
    }

    if (index == (numDataPages - 1))
    {
        bunch.isLast = true;
        return;
    }

    index++;
    if (dataPages[index] == NULL)
        LoadDataPage(index, dataPages[index - 1]->GetSize(), true);

    bunch.nextKey.Write(dataPages[index]->keyValues.First()->GetKey());
    bunch.isLast = false;
}

uint64_t StorageFileChunk::GetChunkID()
{
    return headerPage.GetChunkID();
}

bool StorageFileChunk::UseBloomFilter()
{
    return headerPage.UseBloomFilter();
}

StorageKeyValue* StorageFileChunk::Get(ReadBuffer& key)
{
    uint32_t    index, offset;
    Buffer      buffer;

    if (headerPage.UseBloomFilter())
    {
        if (bloomPage == NULL)
            LoadBloomPage(); // evicted, load back
        if (bloomPage->IsCached())
            StoragePageCache::RegisterHit(bloomPage);
        if (!bloomPage->Check(key))
            return NULL;
    }

    if (indexPage == NULL)
        LoadIndexPage(); // evicted, load back
    if (indexPage->IsCached())
        StoragePageCache::RegisterHit(indexPage);
    if (!indexPage->Locate(key, index, offset))
        return NULL;

    if (dataPages[index] == NULL)
        LoadDataPage(index, offset); // evicted, load back

    if (dataPages[index]->IsCached())
        StoragePageCache::RegisterHit(dataPages[index]);
    return dataPages[index]->Get(key);
}

uint64_t StorageFileChunk::GetMinLogSegmentID()
{
    return minLogSegmentID;
}

uint64_t StorageFileChunk::GetMaxLogSegmentID()
{
    return headerPage.GetLogSegmentID();
}

uint32_t StorageFileChunk::GetMaxLogCommandID()
{
    return headerPage.GetLogCommandID();
}

uint64_t StorageFileChunk::GetSize()
{
    return fileSize;
}

void StorageFileChunk::AddPagesToCache()
{
    uint32_t i;

    if (UseBloomFilter())
        StoragePageCache::AddPage(bloomPage);

    StoragePageCache::AddPage(indexPage);

    for (i = 0; i < numDataPages; i++)
        StoragePageCache::AddPage(dataPages[i]);
}

void StorageFileChunk::OnBloomPageEvicted()
{
    delete bloomPage;
    bloomPage = NULL;
}

void StorageFileChunk::OnIndexPageEvicted()
{
    delete indexPage;
    indexPage = NULL;
}

void StorageFileChunk::OnDataPageEvicted(uint32_t index)
{
    assert(dataPages[index] != NULL);

    delete dataPages[index];
    dataPages[index] = NULL;
}

void StorageFileChunk::LoadBloomPage()
{
    Buffer      buffer;
    uint32_t    offset;

    bloomPage = new StorageBloomPage(this);
    offset = headerPage.GetBloomPageOffset();
    if (!ReadPage(offset, buffer))
    {
        Log_Message("Unable to read bloom page from %s at offset %U", filename.GetBuffer(), offset);
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    if (!bloomPage->Read(buffer))
    {
        Log_Message("Unable to parse bloom page read from %s at offset %U with size %u",
         filename.GetBuffer(), offset, buffer.GetLength());
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    StoragePageCache::AddPage(bloomPage);
}

void StorageFileChunk::LoadIndexPage()
{
    Buffer      buffer;
    uint32_t    offset;

    indexPage = new StorageIndexPage(this);
    offset = headerPage.GetIndexPageOffset();
    if (!ReadPage(offset, buffer))
    {
        Log_Message("Unable to read index page from %s at offset %U", filename.GetBuffer(), offset);
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    if (!indexPage->Read(buffer))
    {
        Log_Message("Unable to parse index page read from %s at offset %U with size %u",
         filename.GetBuffer(), offset, buffer.GetLength());
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    StoragePageCache::AddPage(indexPage);
}

void StorageFileChunk::LoadDataPage(uint32_t index, uint32_t offset, bool bulk)
{
    Buffer buffer;

    dataPages[index] = new StorageDataPage(this, index);
    if (!ReadPage(offset, buffer))
    {
        Log_Message("Unable to read data page from %s at offset %U", filename.GetBuffer(), offset);
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    if (!dataPages[index]->Read(buffer))
    {
        Log_Message("Unable to parse data page read from %s at offset %U with size %u",
         filename.GetBuffer(), offset, buffer.GetLength());
        Log_Message("This should not happen.");
        Log_Message("Possible causes: software bug, damaged file, corrupted file...");
        Log_Message("Exiting...");
        ASSERT_FAIL();
    }
    StoragePageCache::AddPage(dataPages[index], bulk);
}

void StorageFileChunk::AppendDataPage(StorageDataPage* dataPage)
{
    if (numDataPages == dataPagesSize)
        ExtendDataPageArray();

    dataPages[numDataPages] = dataPage;
    numDataPages++;
}

void StorageFileChunk::ExtendDataPageArray()
{
    StorageDataPage**   newDataPages;
    unsigned            newSize, i;

    newSize = dataPagesSize * 2;
    newDataPages = (StorageDataPage**) malloc(sizeof(StorageDataPage*) * newSize);

    for (i = 0; i < numDataPages; i++)
        newDataPages[i] = dataPages[i];

    free(dataPages);
    dataPages = newDataPages;
    dataPagesSize = newSize;
}

bool StorageFileChunk::ReadPage(uint32_t offset, Buffer& buffer)
{
    uint32_t    size, rest;
    ReadBuffer  parse;
    FDGuard     fd;

    if (fd.Open(filename.GetBuffer(), FS_READONLY) == INVALID_FD)
        return false;

    size = STORAGE_DEFAULT_PAGE_GRAN;
    buffer.Allocate(size);
    if (FS_FileReadOffs(fd.GetFD(), buffer.GetBuffer(), size, offset) != size)
        return false;
    buffer.SetLength(size);

    // first 4 bytes on all pages is the page size
    parse.Wrap(buffer);
    if (!parse.ReadLittle32(size))
        return false;

    rest = size - buffer.GetLength();
    if (rest > 0)
    {
        // read rest
        buffer.Allocate(size);
        if (FS_FileReadOffs(fd.GetFD(), buffer.GetPosition(), rest, offset + buffer.GetLength()) != rest)
            return false;
        buffer.SetLength(size);
    }

    fd.Close();

    return true;
}
<|endoftext|>


<commit_before>#include "server.h"
#include "unique_fd.h"

#include <iostream>
#include <cstdlib>
#include <iomanip>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

namespace
{

const int fail = -1;
const int inet_aton_fail = 0;

static bool terminated = false;

void termination(int signum)
{
    terminated = true;
}

bool setSignalsHandlers()
{
    struct sigaction sa;
    sa.sa_handler = termination;
    sigaddset(&sa.sa_mask, SIGTERM);
    sigaddset(&sa.sa_mask, SIGINT);
    sa.sa_flags = 0;
    if (sigaction(SIGTERM, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    if (sigaction(SIGINT, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    return true;
}

bool init(const http_server::Options& options)
{

    if (options.daemon()) {
        if (daemon(0, 1) == fail) {
            perror("daemon");
            return false;
        }
    }

    if (options.verbose()) {
        std::cout << "The server started as "
                  << (options.daemon()? "daemon": "application")
                  << std::endl;
        std::cout << "pid = " << getpid() << std::endl;
    }

    return setSignalsHandlers();
}

aux::UniqueFd makeListeningSocket()
{
    //aux::UniqueFd sd {socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)};
    aux::UniqueFd sockfd {socket(AF_INET, SOCK_STREAM, 0)};
    if (!sockfd) {
        perror("socket");
        return aux::UniqueFd();
    }

    const int yes = 1;
    if (setsockopt(sockfd, SOL_SOCKET,
                   SO_REUSEADDR, &yes, sizeof(yes)) == fail) {
        perror("setsockopt");
        return aux::UniqueFd();
    }

    return sockfd;
}

bool startListen(const aux::UniqueFd& sockfd, const http_server::Options& options)
{
    struct sockaddr_in addr_in;
    addr_in.sin_family = AF_INET;
    addr_in.sin_port = htons(options.port());
    if (inet_aton(options.ip(), &addr_in.sin_addr) == inet_aton_fail) {
        std::cerr << "inet_aton: " << "The address '"
                  << options.ip() << "' is wrong" << std::endl;
        return false;
    }

    if (options.verbose()) {
        std::cout << "Listening: "
                  << inet_ntoa(addr_in.sin_addr) << ":" << ntohs(addr_in.sin_port)
                  << std::endl;
    }

    if (bind(sockfd,
             reinterpret_cast<struct sockaddr*>(&addr_in),
             sizeof(addr_in)) == fail) {
        perror("bind");
        return false;
    }

    if (listen(sockfd, SOMAXCONN) == fail) {
        perror("listen");
        return false;
    }

    return true;
}

void outputBinaryData(const char * data, size_t size)
{
    std::cout << std::setfill('0');
    for(size_t i = 0; i < size; ++i)
        std::cout << std::setw(2) << std::hex
                  << static_cast<int>(data[i]) << " ";
    std::cout << std::endl;
    std::cout << std::setfill(' ');
}

} /* anonymous namespace */

int http_server::run(const http_server::Options& options)
{
    if (!init(options))
        return EXIT_FAILURE;

    aux::UniqueFd sockfd { makeListeningSocket() };
    if (!sockfd)
        return EXIT_FAILURE;

    if (!startListen(sockfd, options))
        return EXIT_FAILURE;

    while(!terminated) {
        struct sockaddr_in peerAddr;
        socklen_t peerAddrSize = sizeof(peerAddr);
        aux::UniqueFd clientfd {
            accept(sockfd,
                   reinterpret_cast<sockaddr*>(&peerAddr),
                   &peerAddrSize)
            };

        if (clientfd) {
            if (options.verbose()) {
                std::cout << "Connection with: "
                          << inet_ntoa(peerAddr.sin_addr)
                          << ":" << ntohs(peerAddr.sin_port)
                          << std::endl;
            }
            char buf[1024];
            ssize_t received = recv(clientfd, &buf, sizeof(buf), 0);
            switch (received)
            {
                case -1:
                    perror("recv");
                    break;
                case 0:
                    break;
                default:
                    if (options.verbose()) {
                        std::cout << "Received: ";
                        outputBinaryData(buf, received);
                    }

                    const char notFound[] = "HTTP/1.0 404 Not Found\r\n"
                                            "Content-Length:37\r\n"
                                            "\r\n"
                                            "Not Found\r\n";
                    std::cout << "Send: ";
                    outputBinaryData(notFound, sizeof(notFound) - 1);
                    if (send(clientfd, notFound, sizeof(notFound) - 1, 0) == -1)
                        perror("send");
                    break;
            }
        } else {
            perror("accept");
        }
    }

    if (options.verbose())
        std::cout << "The server stoped" << std::endl;

    return 0;
}

<commit_msg>Send requesting file if it exists<commit_after>#include "server.h"
#include "unique_fd.h"

#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <cstring>
#include <sstream>
#include <fstream>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

namespace
{

const int fail = -1;
const int inet_aton_fail = 0;

static bool terminated = false;

void termination(int signum)
{
    terminated = true;
}

bool setSignalsHandlers()
{
    struct sigaction sa;
    sa.sa_handler = termination;
    sigaddset(&sa.sa_mask, SIGTERM);
    sigaddset(&sa.sa_mask, SIGINT);
    sa.sa_flags = 0;
    if (sigaction(SIGTERM, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    if (sigaction(SIGINT, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    return true;
}

bool init(const http_server::Options& options)
{

    if (options.daemon()) {
        if (daemon(0, 1) == fail) {
            perror("daemon");
            return false;
        }
    }

    if (options.verbose()) {
        std::cout << "The server started as "
                  << (options.daemon()? "daemon": "application")
                  << std::endl;
        std::cout << "pid = " << getpid() << std::endl;
    }

    return setSignalsHandlers();
}

aux::UniqueFd makeListeningSocket()
{
    //aux::UniqueFd sd {socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)};
    aux::UniqueFd sockfd {socket(AF_INET, SOCK_STREAM, 0)};
    if (!sockfd) {
        perror("socket");
        return aux::UniqueFd();
    }

    const int yes = 1;
    if (setsockopt(sockfd, SOL_SOCKET,
                   SO_REUSEADDR, &yes, sizeof(yes)) == fail) {
        perror("setsockopt");
        return aux::UniqueFd();
    }

    return sockfd;
}

bool startListen(const aux::UniqueFd& sockfd, const http_server::Options& options)
{
    struct sockaddr_in addr_in;
    addr_in.sin_family = AF_INET;
    addr_in.sin_port = htons(options.port());
    if (inet_aton(options.ip(), &addr_in.sin_addr) == inet_aton_fail) {
        std::cerr << "inet_aton: " << "The address '"
                  << options.ip() << "' is wrong" << std::endl;
        return false;
    }

    if (options.verbose()) {
        std::cout << "Listening: "
                  << inet_ntoa(addr_in.sin_addr) << ":" << ntohs(addr_in.sin_port)
                  << std::endl;
    }

    if (bind(sockfd,
             reinterpret_cast<struct sockaddr*>(&addr_in),
             sizeof(addr_in)) == fail) {
        perror("bind");
        return false;
    }

    if (listen(sockfd, SOMAXCONN) == fail) {
        perror("listen");
        return false;
    }

    return true;
}

void outputBinaryData(const char * data, size_t size)
{
    std::cout << std::setfill('0');
    for(size_t i = 0; i < size; ++i)
        std::cout << std::setw(2) << std::hex
                  << static_cast<int>(data[i]) << " ";
    std::cout << std::setfill(' ');
    std::cout << std::dec;
    std::cout << std::endl;
    std::cout << std::endl;
}

int sendData(int sockfd, const char * data, size_t size, bool verbose)
{
    if (verbose)
    {
        std::cout << "Send: ";
        outputBinaryData(data, size);
    }

    int res = send(sockfd, data, size, 0);
    if (res == -1)
        perror("send");

    return res;
}

int sendBadRequest(int sockfd, bool verbose)
{
    static const char badRequest[] = "HTTP/1.0 400 Bad Request\r\n"
                                     "Content-Length:43\r\n"
                                     "\r\n"
                                     "400 Bad Request\r\n";

    return sendData(sockfd, badRequest, sizeof(badRequest) - 1, verbose);
}

int sendNotFound(int sockfd, bool verbose)
{
    static const char notFound[] = "HTTP/1.0 404 Not Found\r\n"
                                   "Content-Length:41\r\n"
                                   "\r\n"
                                   "404 Not Found\r\n";

    return sendData(sockfd, notFound, sizeof(notFound) - 1, verbose);
}

int sendAnswer(int sockfd, const std::string& data, bool verbose)
{
    std::ostringstream os;
    os << "HTTP/1.0 200 OK\r\n"
       << "Content-Length:" << data.length() << "\r\n"
       << "\r\n"
       << data;

    return sendData(sockfd, os.str().c_str(), os.str().length(), verbose);
}

void clientWorker(aux::UniqueFd&& sockfd,
                  const sockaddr_in peerAddr,
                  const http_server::Options& options)
{
    aux::UniqueFd clientfd(std::move(sockfd));
    if (options.verbose()) {
        std::cout << "Connection with: "
                  << inet_ntoa(peerAddr.sin_addr)
                  << ":" << ntohs(peerAddr.sin_port)
                  << std::endl;
    }
    char buf[1024];
    ssize_t received = recv(clientfd, &buf, sizeof(buf), 0);
    switch (received)
    {
        case -1:
            perror("recv");
            break;
        case 0:
            break;
        default:
            if (options.verbose()) {
                std::cout << "Received: ";
                outputBinaryData(buf, received);
            }

            const char* getLine = std::strtok(buf, "\r\n");

            if ((getLine == NULL) || (strncmp(getLine, "GET ", 4) != 0))
            {
                sendBadRequest(clientfd, options.verbose());
                return;
            }

            const char* protocolStr = std::strrchr(getLine, 'H');
            if ((protocolStr == NULL) || (std::strncmp(protocolStr, "HTTP/", 5) != 0))
            {
                sendBadRequest(clientfd, options.verbose());
                return;
            }

            std::string filename(getLine + 4, protocolStr - getLine - 5);

            std::filebuf file;
            if (file.open(options.directory() + filename, std::ios_base::in) == nullptr)
            {
                sendNotFound(clientfd, options.verbose());
                return;
            }

            using std::ios_base;
            auto posEnd = file.pubseekoff(0, ios_base::end);
            file.pubseekpos(0);

            //sendAnswer(clientfd, filename, options.verbose());

            if (options.verbose())
                std::cout << "Sending header..." << std::endl;

            std::ostringstream os;
            os << "HTTP/1.0 200 OK\r\n"
               << "Content-Length:" << posEnd << "\r\n"
               << "\r\n";

            if (sendData(clientfd, os.str().c_str(), os.str().length(), options.verbose()) == -1)
                return;

            if (options.verbose())
                std::cout << "Sending content..." << std::endl;
            int read = 0;
            do
            {
                read = file.sgetn(buf, sizeof(buf));
                if (sendData(clientfd, buf, read, options.verbose()) == -1)
                    return;
            } while(read == sizeof(buf));

            break;
    }
}

} /* anonymous namespace */

int http_server::run(const http_server::Options& options)
{
    if (!init(options))
        return EXIT_FAILURE;

    aux::UniqueFd sockfd { makeListeningSocket() };
    if (!sockfd)
        return EXIT_FAILURE;

    if (!startListen(sockfd, options))
        return EXIT_FAILURE;

    while(!terminated) {
        struct sockaddr_in peerAddr;
        socklen_t peerAddrSize = sizeof(peerAddr);
        aux::UniqueFd clientfd {
            accept(sockfd,
                   reinterpret_cast<sockaddr*>(&peerAddr),
                   &peerAddrSize)
            };

        if (clientfd) {
            clientWorker(std::move(clientfd), peerAddr, options);
        } else {
            perror("accept");
        }
    }

    if (options.verbose())
        std::cout << "The server stoped" << std::endl;

    return 0;
}

<|endoftext|>


<commit_before>#include "installercontroller.h"

#include <QProcess>
#include <QtTest>

static const QString configFile = SRCDIR + QStringLiteral("../../../installer/config/config.xml");
static const QString configScript = SRCDIR + QStringLiteral("../../../installer/config/controller.qs");
static const QString pkgFile = SRCDIR + QStringLiteral("../../../installer/packages/de.skycoder42.QtAutoUpdaterTestInstaller/meta/package.xml");
static const QString binarycreator = BINDIR + QStringLiteral("binarycreator");
static const QString repogen = BINDIR + QStringLiteral("repogen");

InstallerController::InstallerController(QObject *parent) :
	QObject(parent),
	_version(1, 0, 0),
	_buildDir()
{
	setVersion(_version);
}

void InstallerController::createRepository()
{
	qDebug() << "Creating repository";
	auto res = QProcess::execute(repogen, {"--update-new-components", "-p", _buildDir.path() + "/packages", _buildDir.path() + "/repository"});
	QCOMPARE(res, 0);
}

void InstallerController::createInstaller()
{
	qDebug() << "Creating installer";
	QFile configSrc(configFile);
	QFile configOut(_buildDir.path() + "/config.xml");

	QVERIFY(configSrc.open(QIODevice::ReadOnly | QIODevice::Text));
	QVERIFY(configOut.open(QIODevice::WriteOnly | QIODevice::Text));
	auto src = QString::fromUtf8(configSrc.readAll());
	configOut.write(src
					.arg(_buildDir.path() + "/install")
					.arg(_buildDir.path())
					.toUtf8());
	configSrc.close();
	configOut.close();

	auto res = QProcess::execute(binarycreator, {"-n", "-c", configOut.fileName(), "-p", _buildDir.path() + "/packages", _buildDir.path() + "/QtAutoUpdaterTestInstaller"});
	QCOMPARE(res, 0);
}

void InstallerController::installLocal()
{
	qDebug() << "Installing example";
	auto res = QProcess::execute(_buildDir.path() + "/QtAutoUpdaterTestInstaller", {"--script", configScript, "--verbose"});
	QCOMPARE(res, 0);
}

void InstallerController::runUpdater()
{
	qDebug() << "Running updater";
}

QVersionNumber InstallerController::version() const
{
	return _version;
}

QString InstallerController::maintenanceToolPath() const
{
	return _buildDir.path() + "/install";
}

void InstallerController::setVersion(QVersionNumber version)
{
	qDebug() << "Updating repository version";
	_version = version;

	QDir tDir(_buildDir.path());
	QVERIFY(tDir.mkpath("packages/de.skycoder42.QtAutoUpdaterTestInstaller/meta"));
	QVERIFY(tDir.mkpath("packages/de.skycoder42.QtAutoUpdaterTestInstaller/data"));

	QFile pkgSrc(pkgFile);
	QFile pkgOut(_buildDir.path() + "/packages/de.skycoder42.QtAutoUpdaterTestInstaller/meta/package.xml");

	QVERIFY(pkgSrc.open(QIODevice::ReadOnly | QIODevice::Text));
	QVERIFY(pkgOut.open(QIODevice::WriteOnly | QIODevice::Text));
	auto src = QString::fromUtf8(pkgSrc.readAll());
	pkgOut.write(src.arg(_version.toString()).toUtf8());
	pkgSrc.close();
	pkgOut.close();

	QFile dataFile(_buildDir.path() + "/packages/de.skycoder42.QtAutoUpdaterTestInstaller/data/version.txt");
	QVERIFY(dataFile.open(QIODevice::WriteOnly | QIODevice::Text));
	dataFile.write(_version.toString().toUtf8());
	dataFile.close();
}
<commit_msg>more test out<commit_after>#include "installercontroller.h"

#include <QProcess>
#include <QtTest>

static const QString configFile = SRCDIR + QStringLiteral("../../../installer/config/config.xml");
static const QString configScript = SRCDIR + QStringLiteral("../../../installer/config/controller.qs");
static const QString pkgFile = SRCDIR + QStringLiteral("../../../installer/packages/de.skycoder42.QtAutoUpdaterTestInstaller/meta/package.xml");
static const QString binarycreator = BINDIR + QStringLiteral("binarycreator");
static const QString repogen = BINDIR + QStringLiteral("repogen");

InstallerController::InstallerController(QObject *parent) :
	QObject(parent),
	_version(1, 0, 0),
	_buildDir()
{
	setVersion(_version);
}

void InstallerController::createRepository()
{
	qDebug() << "Creating repository";
	auto res = QProcess::execute(repogen, {"--update-new-components", "-p", _buildDir.path() + "/packages", _buildDir.path() + "/repository"});
	QCOMPARE(res, 0);
}

void InstallerController::createInstaller()
{
	qDebug() << "Creating installer";
	QFile configSrc(configFile);
	QFile configOut(_buildDir.path() + "/config.xml");

	QVERIFY(configSrc.open(QIODevice::ReadOnly | QIODevice::Text));
	QVERIFY(configOut.open(QIODevice::WriteOnly | QIODevice::Text));
	auto src = QString::fromUtf8(configSrc.readAll());
	configOut.write(src
					.arg(_buildDir.path() + "/install")
					.arg(_buildDir.path())
					.toUtf8());
	configSrc.close();
	configOut.close();

	auto res = QProcess::execute(binarycreator, {"-n", "-c", configOut.fileName(), "-p", _buildDir.path() + "/packages", _buildDir.path() + "/QtAutoUpdaterTestInstaller"});
	QCOMPARE(res, 0);
}

QString toSystemExe(QString basePath)
{
#if defined(Q_OS_WIN32)
	if(!basePath.endsWith(QStringLiteral(".exe")))
		return basePath + QStringLiteral(".exe");
	else
		return basePath;
#elif defined(Q_OS_OSX)
	if(basePath.endsWith(QStringLiteral(".app")))
		basePath.truncate(basePath.lastIndexOf(QStringLiteral(".")));
	return basePath + QStringLiteral(".app/Contents/MacOS/") + QFileInfo(basePath).fileName();
#elif defined(Q_OS_UNIX)
	return basePath;
#endif
}

void InstallerController::installLocal()
{
	qDebug() << "Installing example";
	QVERIFY(QFile::exists(toSystemExe(_buildDir.path() + "/QtAutoUpdaterTestInstaller")));
	auto res = QProcess::execute(toSystemExe(_buildDir.path() + "/QtAutoUpdaterTestInstaller"), {"--script", configScript, "--verbose"});
	QCOMPARE(res, 0);
}

void InstallerController::runUpdater()
{
	qDebug() << "Running updater";
}

QVersionNumber InstallerController::version() const
{
	return _version;
}

QString InstallerController::maintenanceToolPath() const
{
	return _buildDir.path() + "/install";
}

void InstallerController::setVersion(QVersionNumber version)
{
	qDebug() << "Updating repository version";
	_version = version;

	QDir tDir(_buildDir.path());
	QVERIFY(tDir.mkpath("packages/de.skycoder42.QtAutoUpdaterTestInstaller/meta"));
	QVERIFY(tDir.mkpath("packages/de.skycoder42.QtAutoUpdaterTestInstaller/data"));

	QFile pkgSrc(pkgFile);
	QFile pkgOut(_buildDir.path() + "/packages/de.skycoder42.QtAutoUpdaterTestInstaller/meta/package.xml");

	QVERIFY(pkgSrc.open(QIODevice::ReadOnly | QIODevice::Text));
	QVERIFY(pkgOut.open(QIODevice::WriteOnly | QIODevice::Text));
	auto src = QString::fromUtf8(pkgSrc.readAll());
	pkgOut.write(src.arg(_version.toString()).toUtf8());
	pkgSrc.close();
	pkgOut.close();

	QFile dataFile(_buildDir.path() + "/packages/de.skycoder42.QtAutoUpdaterTestInstaller/data/version.txt");
	QVERIFY(dataFile.open(QIODevice::WriteOnly | QIODevice::Text));
	dataFile.write(_version.toString().toUtf8());
	dataFile.close();
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2015-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include<iostream>
#include<sstream>
#include<thread>
#include<vector>
#include<algorithm>

#include<cstdlib>
#include<cstdio>
#include<cstring>

#include<sys/socket.h>
#include<sys/un.h>
#include<sys/types.h>
#include<unistd.h>
#include<signal.h>

#include <ctime>

#include <mongoose/Server.h>
#include <mongoose/WebController.h>

#include "asgard/utils.hpp"

#include "db.hpp"
#include "led.hpp"
#include "display_controller.hpp"

namespace {

const std::size_t UNIX_PATH_MAX = 108;
const std::size_t socket_buffer_size = 4096;
const std::size_t max_sources = 32;

const char* socket_path = "/tmp/asgard_socket";

int socket_fd;

// Allocate space for the buffers
char receive_buffer[socket_buffer_size];
char write_buffer[socket_buffer_size];

struct sensor_t {
    std::size_t id;
    std::string type;
    std::string name;
};

struct action_t {
    std::size_t id;
    std::string type;
    std::string name;
};

struct actuator_t {
    std::size_t id;
    std::string name;
};

struct source_t {
    std::size_t id;
    std::string name;
    std::vector<sensor_t> sensors;
    std::vector<actuator_t> actuators;
    std::vector<action_t> actions;

    std::size_t id_sql;
    std::size_t sensors_counter;
    std::size_t actuators_counter;
    std::size_t actions_counter;
};

std::size_t current_source = 0;

std::vector<source_t> sources;

source_t& select_source(std::size_t source_id) {
    for (auto& source : sources) {
        if (source.id == source_id) {
            return source;
        }
    }

    std::cerr << "asgard: server: Invalid request for source id " << source_id << std::endl;

    return sources.front();
}

// Create the controller handling the requests
display_controller controller;

void cleanup();

void handle_command(const std::string& message, sockaddr_un& client_address, socklen_t& address_length) {
    std::stringstream message_ss(message);

    std::string command;
    message_ss >> command;

    if (command == "REG_SOURCE") {
        sources.emplace_back();

        auto& source             = sources.back();
        source.id                = current_source++;
        source.sensors_counter   = 0;
        source.actuators_counter = 0;
        source.actions_counter   = 0;

        message_ss >> source.name;

        // Give the source id back to the client
        auto nbytes = snprintf(write_buffer, 4096, "%d", (int) source.id);
        if (sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr*)&client_address, address_length) < 0) {
            std::perror("asgard: server: failed to answer");
            return;
        }

        try {
            CppSQLite3Buffer buffSQL;
            buffSQL.format("insert into source(name,fk_pi) select \"%s\", 1 where not exists(select 1 from source where name=\"%s\");",
                           source.name.c_str(), source.name.c_str());
            get_db().execDML(buffSQL);
            buffSQL.format("select pk_source from source where name=\"%s\";", source.name.c_str());
            source.id_sql = get_db().execScalar(buffSQL);
        } catch (CppSQLite3Exception& e) {
            std::cerr << e.errorCode() << ":" << e.errorMessage() << std::endl;
        }

        std::cout << "asgard: new source registered " << source.id << " : " << source.name << std::endl;
    } else if (command == "UNREG_SOURCE") {
        int source_id;
        message_ss >> source_id;

        sources.erase(std::remove_if(sources.begin(), sources.end(), [&](source_t& source) {
                          return source.id == static_cast<std::size_t>(source_id);
                      }), sources.end());

        std::cout << "asgard: unregistered source " << source_id << std::endl;
    } else if (command == "REG_SENSOR") {
        int source_id;
        message_ss >> source_id;

        auto& source = select_source(source_id);

        source.sensors.emplace_back();
        auto& sensor = source.sensors.back();

        message_ss >> sensor.type;
        message_ss >> sensor.name;

        sensor.id = source.sensors_counter++;

        // Give the sensor id back to the client
        auto nbytes = snprintf(write_buffer, 4096, "%d", (int) sensor.id);
        if (sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr*)&client_address, address_length) < 0) {
            std::perror("asgard: server: failed to answer");
            return;
        }

        if(db_exec_dml(
            get_db(), "insert into sensor(type, name, fk_source) select \"%s\", \"%s\","
            "%d where not exists(select 1 from sensor where type=\"%s\" and name=\"%s\");"
            , sensor.type.c_str(), sensor.name.c_str(), source.id_sql, sensor.type.c_str(), sensor.name.c_str())) {

            auto sensor_type = sensor.type;
            std::transform(sensor_type.begin(), sensor_type.end(), sensor_type.begin(), ::tolower);
            std::string url = "/" + sensor.name + "/" + sensor_type;
            controller.addRoute<display_controller>("GET", url + "/data", &display_controller::sensor_data);
            controller.addRoute<display_controller>("GET", url + "/script", &display_controller::sensor_script);
        }

        std::cout << "asgard: new sensor registered " << sensor.id << " (" << sensor.type << ") : " << sensor.name << std::endl;
    } else if (command == "UNREG_SENSOR") {
        int source_id;
        message_ss >> source_id;

        int sensor_id;
        message_ss >> sensor_id;

        auto& source = select_source(source_id);

        source.sensors.erase(std::remove_if(source.sensors.begin(), source.sensors.end(), [&](sensor_t& sensor) {
                                 return sensor.id == static_cast<std::size_t>(sensor_id);
                             }), source.sensors.end());

        std::cout << "asgard: sensor unregistered from source " << source_id << " : " << sensor_id << std::endl;
    } else if (command == "REG_ACTION") {
        int source_id;
        message_ss >> source_id;

        auto& source = select_source(source_id);

        source.actions.emplace_back();
        auto& action = source.actions.back();

        message_ss >> action.type;
        message_ss >> action.name;

        action.id = source.actions_counter++;

        // Give the action id back to the client
        auto nbytes = snprintf(write_buffer, 4096, "%d", action.id);
        if (sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr*)&client_address, address_length) < 0) {
            std::perror("asgard: server: failed to answer");
            return;
        }

        db_exec_dml(
            get_db(),
            "insert into action(type, name, fk_source) select \"%s\", \"%s\","
            "%d where not exists(select 1 from action where type=\"%s\" and name=\"%s\");",
            action.type.c_str(), action.name.c_str(), source.id_sql, action.type.c_str(), action.name.c_str());

        std::cout << "asgard: new action registered " << action.id << " (" << action.type << ") : " << action.name << std::endl;
    } else if (command == "UNREG_ACTION") {
        int source_id;
        message_ss >> source_id;

        int action_id;
        message_ss >> action_id;

        auto& source = select_source(source_id);

        source.actions.erase(std::remove_if(source.actions.begin(), source.actions.end(), [&](action_t& action) {
                                 return action.id == static_cast<std::size_t>(action_id);
                             }), source.actions.end());

        std::cout << "asgard: action unregistered from source " << source_id << " : " << action_id << std::endl;
    } else if (command == "REG_ACTUATOR") {
        int source_id;
        message_ss >> source_id;

        auto& source = select_source(source_id);

        source.actuators.emplace_back();
        auto& actuator = source.actuators.back();

        message_ss >> actuator.name;

        actuator.id = source.actuators_counter++;

        // Give the sensor id back to the client
        auto nbytes = snprintf(write_buffer, 4096, "%d", (int) actuator.id);
        if (sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr*)&client_address, address_length) < 0) {
            std::perror("asgard: server: failed to answer");
            return;
        }

        if(db_exec_dml(get_db(), "insert into actuator(name, fk_source) select \"%s\", %d where not exists(select 1 from actuator where name=\"%s\");"
                      , actuator.name.c_str(), source.id_sql, actuator.name.c_str())){

            std::string url = "/" + actuator.name;
            controller.addRoute<display_controller>("GET", url + "/data", &display_controller::actuator_data);
            controller.addRoute<display_controller>("GET", url + "/script", &display_controller::actuator_script);
        }

        std::cout << "asgard: new actuator registered " << actuator.id << " : " << actuator.name << std::endl;
    } else if (command == "UNREG_ACTUATOR") {
        int source_id;
        message_ss >> source_id;

        int actuator_id;
        message_ss >> actuator_id;

        auto& source = select_source(source_id);

        source.actuators.erase(std::remove_if(source.actuators.begin(), source.actuators.end(), [&](actuator_t& actuator) {
                                   return actuator.id == static_cast<std::size_t>(actuator_id);
                               }), source.actuators.end());

        std::cout << "asgard: actuator unregistered from source " << source_id << " : " << actuator_id << std::endl;
    } else if (command == "DATA") {
        int source_id;
        message_ss >> source_id;

        int sensor_id;
        message_ss >> sensor_id;

        std::string data;
        message_ss >> data;

        auto& source = select_source(source_id);
        auto& sensor = source.sensors[sensor_id];

        int sensor_pk = db_exec_scalar(get_db(), "select pk_sensor from sensor where name=\"%s\" and type=\"%s\";", sensor.name.c_str(), sensor.type.c_str());

        db_exec_dml(get_db(), "insert into sensor_data (data, fk_sensor) values (\"%s\", %d);", data.c_str(), sensor_pk);

        std::cout << "asgard: server: new data: sensor(" << sensor.type << "): \"" << sensor.name << "\" : " << data << std::endl;
    } else if (command == "EVENT") {
        int source_id;
        message_ss >> source_id;

        int actuator_id;
        message_ss >> actuator_id;

        std::string data;
        message_ss >> data;

        auto& source   = select_source(source_id);
        auto& actuator = source.actuators[actuator_id];

        int actuator_pk = db_exec_scalar(get_db(), "select pk_actuator from actuator where name=\"%s\";", actuator.name.c_str());

        db_exec_dml(get_db(), "insert into actuator_data (data, fk_actuator) values (\"%s\", %d);", data.c_str(), actuator_pk);

        std::cout << "asgard: server: new event: actuator: \"" << actuator.name << "\" : " << data << std::endl;
    }
}

int run(){
    // Create the socket
    socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if(socket_fd < 0){
        std::cerr << "socket() failed" << std::endl;
        return 1;
    }

    // Init the server address
    struct sockaddr_un server_address;
    memset(&server_address, 0, sizeof(struct sockaddr_un));
    server_address.sun_family = AF_UNIX;
    snprintf(server_address.sun_path, UNIX_PATH_MAX, socket_path);

    // Unlink the socket file
    unlink(socket_path);

    // Bind
    if (::bind(socket_fd, (struct sockaddr*)&server_address, sizeof(server_address)) < 0) {
        std::cerr << "bind() failed" << std::endl;
        close(socket_fd);
        return 1;
    }

    std::cout << "asgard: Server started" << std::endl;

    while (true) {
        sockaddr_un client_address;
        socklen_t address_length = sizeof(struct sockaddr_un);

        // Wait for one message
        auto bytes_received = recvfrom(socket_fd, receive_buffer, socket_buffer_size-1, 0, (struct sockaddr *) &client_address, &address_length);
        receive_buffer[bytes_received] = '\0';

        // Handle the message
        handle_command(receive_buffer, client_address, address_length);
    }

    cleanup();

    return 0;
}

void cleanup() {
    set_led_off();
    close(socket_fd);
    unlink("/tmp/asgard_socket");
}

void terminate(int /*signo*/) {
    std::cout << "asgard: server: stopping the server" << std::endl;
    cleanup();
    abort();
}

} //end of anonymous namespace

int main() {
    setup_led_controller();

    //Drop root privileges and run as pi:pi again
    if (!asgard::revoke_root()) {
       std::cout << "asgard: unable to revoke root privileges, exiting..." << std::endl;
       return 1;
    }

    // Open (connect) the database
    if(!db_connect(get_db())){
       std::cout << "asgard: unable to connect to the database, exiting..." << std::endl;
       return 1;
    }

    // Run the server with our controller
    Mongoose::Server server(8080);
    server.registerController(&controller);

    // Start the server and wait forever
    server.start();

    //Register signals for "proper" shutdown
    signal(SIGTERM, terminate);
    signal(SIGINT, terminate);

    init_led();
    set_led_on();

    return run();
}
<commit_msg>Add notes<commit_after>//=======================================================================
// Copyright (c) 2015-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include<iostream>
#include<sstream>
#include<thread>
#include<vector>
#include<algorithm>

#include<cstdlib>
#include<cstdio>
#include<cstring>

#include<sys/socket.h>
#include<sys/un.h>
#include<sys/types.h>
#include<unistd.h>
#include<signal.h>

#include <ctime>

#include <mongoose/Server.h>
#include <mongoose/WebController.h>

#include "asgard/utils.hpp"

#include "db.hpp"
#include "led.hpp"
#include "display_controller.hpp"

namespace {

const std::size_t UNIX_PATH_MAX = 108;
const std::size_t socket_buffer_size = 4096;
const std::size_t max_sources = 32;

const char* socket_path = "/tmp/asgard_socket";

int socket_fd;

// Allocate space for the buffers
char receive_buffer[socket_buffer_size];
char write_buffer[socket_buffer_size];

struct sensor_t {
    std::size_t id;
    std::string type;
    std::string name;
};

struct action_t {
    std::size_t id;
    std::string type;
    std::string name;
};

struct actuator_t {
    std::size_t id;
    std::string name;
};

struct source_t {
    std::size_t id;
    std::string name;
    std::vector<sensor_t> sensors;
    std::vector<actuator_t> actuators;
    std::vector<action_t> actions;

    std::size_t id_sql;
    std::size_t sensors_counter;
    std::size_t actuators_counter;
    std::size_t actions_counter;
};

std::size_t current_source = 0;

std::vector<source_t> sources;

source_t& select_source(std::size_t source_id) {
    for (auto& source : sources) {
        if (source.id == source_id) {
            return source;
        }
    }

    std::cerr << "asgard: server: Invalid request for source id " << source_id << std::endl;

    return sources.front();
}

// Create the controller handling the requests
display_controller controller;

void cleanup();

void handle_command(const std::string& message, sockaddr_un& client_address, socklen_t& address_length) {
    std::stringstream message_ss(message);

    std::string command;
    message_ss >> command;

    if (command == "REG_SOURCE") {
        sources.emplace_back();

        auto& source             = sources.back();
        source.id                = current_source++;
        source.sensors_counter   = 0;
        source.actuators_counter = 0;
        source.actions_counter   = 0;

        message_ss >> source.name;

        // Give the source id back to the client
        auto nbytes = snprintf(write_buffer, 4096, "%d", (int) source.id);
        if (sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr*)&client_address, address_length) < 0) {
            std::perror("asgard: server: failed to answer");
            return;
        }

        try {
            CppSQLite3Buffer buffSQL;
            buffSQL.format("insert into source(name,fk_pi) select \"%s\", 1 where not exists(select 1 from source where name=\"%s\");",
                           source.name.c_str(), source.name.c_str());
            get_db().execDML(buffSQL);
            buffSQL.format("select pk_source from source where name=\"%s\";", source.name.c_str());
            source.id_sql = get_db().execScalar(buffSQL);
        } catch (CppSQLite3Exception& e) {
            std::cerr << e.errorCode() << ":" << e.errorMessage() << std::endl;
        }

        std::cout << "asgard: new source registered " << source.id << " : " << source.name << std::endl;
    } else if (command == "UNREG_SOURCE") {
        int source_id;
        message_ss >> source_id;

        sources.erase(std::remove_if(sources.begin(), sources.end(), [&](source_t& source) {
                          return source.id == static_cast<std::size_t>(source_id);
                      }), sources.end());

        std::cout << "asgard: unregistered source " << source_id << std::endl;
    } else if (command == "REG_SENSOR") {
        int source_id;
        message_ss >> source_id;

        auto& source = select_source(source_id);

        source.sensors.emplace_back();
        auto& sensor = source.sensors.back();

        message_ss >> sensor.type;
        message_ss >> sensor.name;

        sensor.id = source.sensors_counter++;

        // Give the sensor id back to the client
        auto nbytes = snprintf(write_buffer, 4096, "%d", (int) sensor.id);
        if (sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr*)&client_address, address_length) < 0) {
            std::perror("asgard: server: failed to answer");
            return;
        }

        if(db_exec_dml(
            get_db(), "insert into sensor(type, name, fk_source) select \"%s\", \"%s\","
            "%d where not exists(select 1 from sensor where type=\"%s\" and name=\"%s\");"
            , sensor.type.c_str(), sensor.name.c_str(), source.id_sql, sensor.type.c_str(), sensor.name.c_str())) {

            auto sensor_type = sensor.type;
            std::transform(sensor_type.begin(), sensor_type.end(), sensor_type.begin(), ::tolower);
            std::string url = "/" + sensor.name + "/" + sensor_type;
            controller.addRoute<display_controller>("GET", url + "/data", &display_controller::sensor_data);
            controller.addRoute<display_controller>("GET", url + "/script", &display_controller::sensor_script);
        }

        std::cout << "asgard: new sensor registered " << sensor.id << " (" << sensor.type << ") : " << sensor.name << std::endl;
    } else if (command == "UNREG_SENSOR") {
        int source_id;
        message_ss >> source_id;

        int sensor_id;
        message_ss >> sensor_id;

        auto& source = select_source(source_id);

        source.sensors.erase(std::remove_if(source.sensors.begin(), source.sensors.end(), [&](sensor_t& sensor) {
                                 return sensor.id == static_cast<std::size_t>(sensor_id);
                             }), source.sensors.end());

        std::cout << "asgard: sensor unregistered from source " << source_id << " : " << sensor_id << std::endl;
    } else if (command == "REG_ACTION") {
        int source_id;
        message_ss >> source_id;

        auto& source = select_source(source_id);

        source.actions.emplace_back();
        auto& action = source.actions.back();

        message_ss >> action.type;
        message_ss >> action.name;

        action.id = source.actions_counter++;

        // Give the action id back to the client
        auto nbytes = snprintf(write_buffer, 4096, "%d", action.id);
        if (sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr*)&client_address, address_length) < 0) {
            std::perror("asgard: server: failed to answer");
            return;
        }

        db_exec_dml(
            get_db(),
            "insert into action(type, name, fk_source) select \"%s\", \"%s\","
            "%d where not exists(select 1 from action where type=\"%s\" and name=\"%s\");",
            action.type.c_str(), action.name.c_str(), source.id_sql, action.type.c_str(), action.name.c_str());

        //TODO Dynamically register the actions

        std::cout << "asgard: new action registered " << action.id << " (" << action.type << ") : " << action.name << std::endl;
    } else if (command == "UNREG_ACTION") {
        int source_id;
        message_ss >> source_id;

        int action_id;
        message_ss >> action_id;

        auto& source = select_source(source_id);

        source.actions.erase(std::remove_if(source.actions.begin(), source.actions.end(), [&](action_t& action) {
                                 return action.id == static_cast<std::size_t>(action_id);
                             }), source.actions.end());

        std::cout << "asgard: action unregistered from source " << source_id << " : " << action_id << std::endl;
    } else if (command == "REG_ACTUATOR") {
        int source_id;
        message_ss >> source_id;

        auto& source = select_source(source_id);

        source.actuators.emplace_back();
        auto& actuator = source.actuators.back();

        message_ss >> actuator.name;

        actuator.id = source.actuators_counter++;

        // Give the sensor id back to the client
        auto nbytes = snprintf(write_buffer, 4096, "%d", (int) actuator.id);
        if (sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr*)&client_address, address_length) < 0) {
            std::perror("asgard: server: failed to answer");
            return;
        }

        if(db_exec_dml(get_db(), "insert into actuator(name, fk_source) select \"%s\", %d where not exists(select 1 from actuator where name=\"%s\");"
                      , actuator.name.c_str(), source.id_sql, actuator.name.c_str())){

            std::string url = "/" + actuator.name;
            controller.addRoute<display_controller>("GET", url + "/data", &display_controller::actuator_data);
            controller.addRoute<display_controller>("GET", url + "/script", &display_controller::actuator_script);
        }

        std::cout << "asgard: new actuator registered " << actuator.id << " : " << actuator.name << std::endl;
    } else if (command == "UNREG_ACTUATOR") {
        int source_id;
        message_ss >> source_id;

        int actuator_id;
        message_ss >> actuator_id;

        auto& source = select_source(source_id);

        source.actuators.erase(std::remove_if(source.actuators.begin(), source.actuators.end(), [&](actuator_t& actuator) {
                                   return actuator.id == static_cast<std::size_t>(actuator_id);
                               }), source.actuators.end());

        std::cout << "asgard: actuator unregistered from source " << source_id << " : " << actuator_id << std::endl;
    } else if (command == "DATA") {
        int source_id;
        message_ss >> source_id;

        int sensor_id;
        message_ss >> sensor_id;

        std::string data;
        message_ss >> data;

        auto& source = select_source(source_id);
        auto& sensor = source.sensors[sensor_id];

        int sensor_pk = db_exec_scalar(get_db(), "select pk_sensor from sensor where name=\"%s\" and type=\"%s\";", sensor.name.c_str(), sensor.type.c_str());

        db_exec_dml(get_db(), "insert into sensor_data (data, fk_sensor) values (\"%s\", %d);", data.c_str(), sensor_pk);

        std::cout << "asgard: server: new data: sensor(" << sensor.type << "): \"" << sensor.name << "\" : " << data << std::endl;
    } else if (command == "EVENT") {
        int source_id;
        message_ss >> source_id;

        int actuator_id;
        message_ss >> actuator_id;

        std::string data;
        message_ss >> data;

        auto& source   = select_source(source_id);
        auto& actuator = source.actuators[actuator_id];

        int actuator_pk = db_exec_scalar(get_db(), "select pk_actuator from actuator where name=\"%s\";", actuator.name.c_str());

        db_exec_dml(get_db(), "insert into actuator_data (data, fk_actuator) values (\"%s\", %d);", data.c_str(), actuator_pk);

        std::cout << "asgard: server: new event: actuator: \"" << actuator.name << "\" : " << data << std::endl;
    }
}

int run(){
    // Create the socket
    socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if(socket_fd < 0){
        std::cerr << "socket() failed" << std::endl;
        return 1;
    }

    // Init the server address
    struct sockaddr_un server_address;
    memset(&server_address, 0, sizeof(struct sockaddr_un));
    server_address.sun_family = AF_UNIX;
    snprintf(server_address.sun_path, UNIX_PATH_MAX, socket_path);

    // Unlink the socket file
    unlink(socket_path);

    // Bind
    if (::bind(socket_fd, (struct sockaddr*)&server_address, sizeof(server_address)) < 0) {
        std::cerr << "bind() failed" << std::endl;
        close(socket_fd);
        return 1;
    }

    std::cout << "asgard: Server started" << std::endl;

    while (true) {
        sockaddr_un client_address;
        socklen_t address_length = sizeof(struct sockaddr_un);

        // Wait for one message
        auto bytes_received = recvfrom(socket_fd, receive_buffer, socket_buffer_size-1, 0, (struct sockaddr *) &client_address, &address_length);
        receive_buffer[bytes_received] = '\0';

        // Handle the message
        handle_command(receive_buffer, client_address, address_length);
    }

    cleanup();

    return 0;
}

void cleanup() {
    set_led_off();
    close(socket_fd);
    unlink("/tmp/asgard_socket");
}

void terminate(int /*signo*/) {
    std::cout << "asgard: server: stopping the server" << std::endl;
    cleanup();
    abort();
}

} //end of anonymous namespace

int main() {
    setup_led_controller();

    //Drop root privileges and run as pi:pi again
    if (!asgard::revoke_root()) {
       std::cout << "asgard: unable to revoke root privileges, exiting..." << std::endl;
       return 1;
    }

    // Open (connect) the database
    if(!db_connect(get_db())){
       std::cout << "asgard: unable to connect to the database, exiting..." << std::endl;
       return 1;
    }

    // Run the server with our controller
    Mongoose::Server server(8080);
    server.registerController(&controller);

    // Start the server and wait forever
    server.start();

    //Register signals for "proper" shutdown
    signal(SIGTERM, terminate);
    signal(SIGINT, terminate);

    init_led();
    set_led_on();

    return run();
}
<|endoftext|>