MySVC
an open source UNIX framework for shell script based web services provider
»Home
»Tools
»Man Page
»User Guide
»ChangeLog
»Installation
»Source Code
»Downloads
»FAQ
»Support
»License

»My Apps

protocol.cc

// $Id$

//  myspl - My Service Protocol Library - Version 1.0 (www.mysvc.it)
//  Copyright (C) 2009 Davide Cucciniello <davide6169@gmail.com>
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

/* **********************************************************************
 *
 *  ***   **        *** **  **  ****
 *   **  **        *  *  *  ** **  *
 *   *** **  **  * ***   *  *  *
 *   * ** *   * **   **   * *  *
 *   * *  *   * *  *  *   **   **
 *  ***  ***   **  ***     *    ****
 *             *
 *            *
 *
 *  My Service
 *
 * ***********************************************************************
 *
 *  ***   **        *** ****  ***
 *   **  **        *  *  *  *  *
 *   *** **  **  * ***   *  *  *
 *   * ** *   * **   **  ***   *
 *   * *  *   * *  *  *  *     *  *
 *  ***  ***   **  ***  ***   *****
 *             *
 *            *
 *
 *  My Service Protocol Library
 *
 *  File: protocol.cc
 *
 *  Description:
 *    C++ library to implement any TCP/IP socket client/server
 *    for binary or ascii protocols
 *
 * ***********************************************************************
 *
 *  History:
 *    1.0               first version
 *
 * *********************************************************************** */

#include "protocol.hh"

/*
 *  class Exception
 */

Exception::Exception(string message__,
                     int code__,
                     string file__,
                     int line__):
  message_(message__),
  code_(code__),
  file_(file__),
  line_(line__)
{
}

string& Exception::file()
{
  return file_;
}

int& Exception::line()
{
  return line_;
}

string& Exception::message()
{
  return message_;
}

int& Exception::code()
{
  return code_;
}

void Exception::write(ostream& os)
{
  os << "Exception:" << endl;
  os << "  message: " << message_ << endl;
  os << "  code: " << code_ << endl;
  os << "  file: " << file_ << endl;
  os << "  line: " << line_ << endl;
}

ostream& operator<<(ostream& os,Exception& e)
{
  e.write(os);

  return os;
}

/*
 *  class SocketException
 */

SocketException::SocketException(string message__,
                                 int code__,
                                 string file__,
                                 int line__):
  Exception(message__,code__,file__,line__)
{
}

/*
 *  class SocketReader:
 */

SocketReader::SocketReader(int fd)
{
  this->fd = fd;
}

int SocketReader::read(char* buffer,int n,bool peek,bool line)
{
  if(!line)
  {
    if(peek)
      return recv(fd,buffer,n,MSG_WAITALL|MSG_PEEK);
    else
      return recv(fd,buffer,n,MSG_WAITALL);
  }
  else
  {
    int i = -1;

    do
    {
      i++;
      if(recv(fd,buffer+i,1,MSG_WAITALL) <= 0)
        return -1;
    }while((i<n-1) && (buffer[i] != '\n'));

    buffer[i] = '\0';

    return n;
  }
}

/*
 *  class SocketWriter
 */

SocketWriter::SocketWriter(int fd)
{
  this->fd = fd;
}

int SocketWriter::write(char* buffer,int n,bool line)
{
  if(!line)
  {
    size_t nleft = n;
    size_t nwritten;

    char* buffptr = (char*) buffer;

    while(nleft > 0)
    {
      if((nwritten = ::write(fd,buffptr,nleft)) <= 0)
        return nwritten;
      else
      {
        nleft -= nwritten;
        buffptr += nwritten;
      }
    }
  }
  else
  {
    int len = strlen(buffer);

    if(buffer[len-1] == '\n')
      send(fd,buffer,len,0);
    else
    {
      strcat(buffer,"\n");

      send(fd,buffer,len+1,0);
    }
  }

  return n;
}

/*
 *  class FileReader:
 */

FileReader::FileReader(int fd)
{
  this->fd = fd;
}

int FileReader::read(char* buffer,int n,bool peek,bool line)
{
  return ::read(fd,buffer,n);
}

/*
 *  class FileWriter
 */

FileWriter::FileWriter(int fd)
{
  this->fd = fd;
}

int FileWriter::write(char* buffer,int n,bool line)
{
  return ::write(fd,buffer,n);
}

/*
 *  class Field
 */

Field::Field()
{
  size_ = 0;
  data_ = 0;
}

Field::Field(int size_,string name__):
  name_(name__)
{
  this->size_ = size_;

  if(size_ > 0)
  {
    data_ = new char[size_];

    empty();
  }
  else
    data_ = 0;
}

Field::Field(const Field& f)
{
  size_ = f.size_;

  if(size_ > 0)
  {
    data_ = new char[f.size_];

    memcpy(data_,f.data_,f.size_);
  }
  else
    data_ = 0;

  name_ = f.name_;
}

void Field::copy(const Field& f)
{
  size_ = f.size_;

  if(size_ > 0)
  {
    data_ = new char[f.size_];

    memcpy(data_,f.data_,f.size_);
  }
  else
    data_ = 0;

  name_ = f.name_;
}

ostream& operator<<(ostream& os,Field& f)
{
  f.write(os);

  return os;
}

int Field::size()
{
  return size_;
}

char* Field::data()
{
  return data_;
}

void Field::init(int size_)
{
  if(data_)
    delete[] data_;

  this->size_ = size_;

  if(size_ > 0)
  {
    data_ = new char[size_];

    memset(data_,0,size_);
  }
  else
    data_ = 0;
}

char& Field::operator[](int i)
{
  if(i >= 0 && i < size_)
    return data_[i];
  else
    throw Exception("char& Field::operator[](int)",-1,__FILE__,__LINE__);
}

Field& Field::operator=(Field& f)
{
  if(this != &f)
  {
    if(data_)
      delete[] data_;

    size_ = f.size_;

    if(size_ > 0)
    {
      data_ = new char[size_];

      memcpy(data_,f.data_,f.size_);
    }
    else
      data_ = 0;
  }

  return *this;
}

Field& Field::operator=(string value)
{
  assign(value);

  return *this;
}

void Field::assign(char* buffer,int n)
{
  if(!size())
  {
    init(n);
    memcpy(data(),buffer,n);
  }
  else
  {
    if(n<=size())
      memcpy(data(),buffer,n);
    else
      throw Exception("void Field::assign(char*,int)",-1,__FILE__,__LINE__);
  }
}

void Field::assign(string value)
{
  const char* s = value.c_str();

  if(!size())
  {
    init(strlen(s)+2);

    strcpy(data(),s);
  }
  else
  {
    if(strlen(s) < size())
      strcpy(data(),s);
    else
      throw Exception("void Field::assign(string)",-1,__FILE__,__LINE__);
  }
}

bool Field::operator==(Field& f)
{
  return equal(f);
}

bool Field::operator!=(Field& f)
{
  return !equal(f);
}

bool Field::equal(Field& f)
{
  return (size_ == f.size_) && !memcmp(data_,f.data_,size_);
}

Field::operator char*()
{
  return data_;
}

Field* Field::clone()
{
  return new Field(*this);
}

string Field::name()
{
  return name_;
}

Field& Field::operator<<(Reader& r)
{
  read(r);

  return *this;
}

Field& Field::operator>>(Writer& w)
{
  write(w);

  return *this;
}

void Field::read(Reader& r,bool peek,bool line)
{
  if(r.read(data_,size_,peek,line) != size_)
    throw Exception("void Field::read(Reader&,bool,bool)",errno,__FILE__,__LINE__);
}

void Field::write(Writer& w,bool line)
{
  if(w.write(data_,size_,line) != size_)
    throw Exception("void Field::write(Writer&,bool)",errno,__FILE__,__LINE__);
}

void Field::read(Field& f,int from)
{
  for(int i=0;i<size_;i++)
    (*this)[i] = f[i+from];
}

void Field::write(Field& f,int from)
{
  for(int i=0;i<size_;i++)
    f[i+from] = (*this)[i];
}

bool Field::isAscii()
{
  return true;
}

void Field::write(ostream& os)
{
  if(size_ > 0)
  {
    if(isAscii())
    {
      os << "    <field>" << endl;
      os << "      <name> " << name() << " </name>" << endl;
      os << "      <size> " << size_ << " </size>" << endl;
      os << "      <data> " << data_ << " </data>" << endl;
      os << "    </field>" << endl;
    }
    else
    {
      os << "    <field>" << endl;
      os << "      <name> " << name() << " </name>" << endl;
      os << "      <size> " << size_ << " </size>" << endl;
      os << "      <data>" << endl;

      char byte[6];
      char idx[8];

      for(int i=0;i<size_;i++)
      {
        sprintf(idx,"%.4d",i);
        sprintf(byte,"%0.2X",(unsigned char)data_[i]);

        os << "        <offset> " << idx << " </offset> "
           << "<byte> " << byte << " </byte>";

        if(isprint(data_[i]))
        {
          if(data_[i] == '&')
            os << " <ascii> '&amp;' </ascii>";
          else if(data_[i] == '<')
            os << " <ascii> '&lt;' </ascii>";
          else if(data_[i] == '>')
            os << " <ascii> '&gt;' </ascii>";
          else
            os << " <ascii> '" << data_[i] << "' </ascii>";
        }

        os << endl;
      }

      os << "      </data>" << endl;

      writeValue(os);

      os << "    </field>" << endl;
    }
  }
}

void Field::writeValue(ostream& os)
{
}

void Field::empty()
{
  if(size_ > 0)
    memset(data_,0,size_);
}

Field::~Field()
{
  if(size_ >  0)
    delete[] data_;
}

/*
 *  class Message
 */


Message::Message()
{
  data_ = 0;
  size_ = 0;

  nextfield = 0;
}

Message::Message(int size_,string name__):
  name_(name__)
{
  this->size_ = size_;

  if(size_ > 0)
  {
    data_ = new Field*[size_];

    for(int i=0;i<size_;i++)
      data_[i] = 0;
  }
  else
    data_ = 0;

  nextfield = 0;
}

Message::Message(const Message& m)
{
  size_ = m.size_;

  if(size_ > 0)
  {
    data_ = new Field*[size_];

    for(int i=0;i<size_;i++)
      if(m.data_[i])
        data_[i] = (m.data_[i])->clone();
      else
        data_[i] = 0;
  }
  else
    data_ = 0;

  name_ = m.name_;

  nextfield = m.nextfield;
}

void Message::copy(const Message& m)
{
  size_ = m.size_;

  if(size_ > 0)
  {
    data_ = new Field*[size_];

    for(int i=0;i<size_;i++)
      if(m.data_[i])
        data_[i] = (m.data_[i])->clone();
      else
        data_[i] = 0;
  }
  else
    data_ = 0;

  name_ = m.name_;

  nextfield = m.nextfield;
}

ostream& operator<<(ostream& os,Message& m)
{
  m.write(os);

  return os;
}

void Message::write(ostream& os)
{
  os << "<message>" << endl;
  os << "  <name> " << name() << " </name>" << endl;
  os << "  <size> " << size_ << " </size>" << endl;

  if(size_ > 0)
  {
    os << "  <data>" << endl;

    char idx[8];

    for(int i=0;i<size_;i++)
    {
      sprintf(idx,"%.4d",i);

      os << "    <offset> " << idx << " </offset>" << endl;

      if(data_[i])
        os << (*this)[i];
      else
        os << "    <field> null </field>" << endl;
    }

    os << "  </data>" << endl;
  }

  os << "</message>" << endl;
}

void Message::assign(int i,Field* f)
{
  if(i>=0 && i<size_)
  {
    if(data_[i])
      delete data_[i];

    data_[i] = f;
  }
  else
    throw Exception("void Message::assign(int,Field*)",-1,__FILE__,__LINE__);
}

void Message::assign(Message* m)
{
  if(m && (nextfield + m->size() < size_))
  {
    for(int i=nextfield;i<nextfield+(m->size());i++)
    {
      int j = i-nextfield;

      Field* f = m->data_[j];

      if(f)
        assign(i,f->clone());
      else
        data_[i] = 0;
    }

    nextfield += m->size();

    delete m;
  }
  else
    throw Exception("void Message::assign(Message*)",-1,__FILE__,__LINE__);
}

int Message::size()
{
  return size_;
}

unsigned long Message::bytes()
{
  unsigned long n = 0;

  for(int i=0;i<size_;i++)
    n += (data_[i]->size());

  return n;
}

Field** Message::data()
{
  return data_;
}

Field*& Message::data(int i)
{
  if(i >= 0 && i < size_)
    return data_[i];
  else
    throw Exception("Field* Message::data(int)",-1,__FILE__,__LINE__);
}

Field& Message::operator[](int i)
{
  if(i >= 0 && i < size_ && data_[i])
    return *(data_[i]);
  else
    throw Exception("Field& Message::operator[](int)",-1,__FILE__,__LINE__);
}

Message& Message::operator=(Message& m)
{
  if(size_ > 0)
  {
    for(int i=0;i<size_;i++)
      if(data_[i])
        delete data_[i];

    delete[] data_;
  }

  size_ = m.size_;

  if(size_ > 0)
  {
    data_ = new Field*[size_];

    for(int i=0;i<size_;i++)
      if(m.data_[i])
        data_[i] = (m.data_[i])->clone();
      else
        data_[i] = 0;
  }
  else
    data_ = 0;

  return *this;
}

bool Message::operator==(Message& m)
{
  return equal(m);
}

bool Message::operator!=(Message& m)
{
  return !equal(m);
}

bool Message::equal(Message& m)
{
  if(size_ != m.size_)
    return false;
  else
  {
    for(int i=0;i<size_;i++)
    {
      if(!data_[i])
      {
        if(m.data_[i])
          return false;
      }
      else
      {
        if(!m.data_[i] || !(data_[i]->equal(*(m.data_[i]))))
          return false;
      }
    }

    return true;
  }
}

string Message::name()
{
  return name_;
}

void Message::empty()
{
  if(size_ > 0)
  {
    for(int i=0;i<size_;i++)
      if(data_[i])
        data_[i]->empty();
  }
}

Message& Message::operator<<(Reader& r)
{
  read(r);

  return *this;
}

Message& Message::operator>>(Writer& w)
{
  write(w);

  return *this;
}

void Message::read(Reader& r,bool peek,bool line)
{
  if(peek)
  {
    int fsize = 0;

    for(int i=0;i<size_;i++)
      fsize += (data_[i]->size());

    Field f(fsize);

    f.read(r,true);

    int j = 0;

    for(int i=0;i<size_;i++)
    {
      data_[i]->read(f,j);

      j += (data_[i]->size());
    }
  }
  else
  {
    for(int i=0;i<size_;i++)
      if(data_[i])
        data_[i]->read(r,false,line);
  }
}

void Message::write(Writer& w,bool line)
{
  for(int i=0;i<size_;i++)
    if(data_[i])
      data_[i]->write(w,line);
}

Message* Message::clone()
{
  return new Message(*this);
}

Message::~Message()
{
  if(size_ > 0)
  {
    for(int i=0;i<size_;i++)
      if(data_[i])
        delete data_[i];

    delete[] data_;
  }
}

/*
 *  class TreeMessage
 */

TreeMessage::TreeMessage()
{
  // empty tree

  data_ = 0;
  size_ = 0;
  info_ = 0;
}

TreeMessage::TreeMessage(Message* info_)
{
  // leaf tree

  data_ = 0;
  size_ = 0;

  this->info_ = info_;
}

TreeMessage::TreeMessage(int size_,string name__):
  name_(name__)
{
  // tree with childes

  info_ = 0;

  this->size_ = size_;

  if(size_ > 0)
  {
    data_ = new TreeMessage*[size_];

    for(int i=0;i<size_;i++)
      data_[i] = 0;
  }
  else
    data_ = 0;
}

void TreeMessage::init(Message* info_)
{
  empty();

  // leaf tree

  data_ = 0;
  size_ = 0;

  this->info_ = info_;
}

void TreeMessage::init(int size_)
{
  empty();

  // tree with childes

  info_ = 0;

  this->size_ = size_;

  if(size_ > 0)
  {
    data_ = new TreeMessage*[size_];

    for(int i=0;i<size_;i++)
      data_[i] = 0;
  }
  else
    data_ = 0;
}

TreeMessage* TreeMessage::clone()
{
  return new TreeMessage(*this);
}

bool TreeMessage::isEmpty()
{
  return ((data_ == 0) && (info_ == 0));
}

bool TreeMessage::isTree()
{
  return ((data_ != 0) && (info_ == 0));
}

bool TreeMessage::isLeaf()
{
  return ((data_ == 0) && (info_ != 0));
}

TreeMessage::TreeMessage(const TreeMessage& m)
{
  if(!m.data_ && !m.info_)
  {
    data_ = 0;
    size_ = 0;
    info_ = 0;
  }
  else if(!m.data_ && m.info_)
  {
    data_ = 0;
    size_ = 0;

    this->info_ = m.info_->clone();
  }
  else
  {
    info_ = 0;
    size_ = m.size_;

    if(size_ > 0)
    {
      data_ = new TreeMessage*[size_];

      for(int i=0;i<size_;i++)
        if(m.data_[i])
          data_[i] = (m.data_[i])->clone();
        else
          data_[i] = 0;
    }
    else
      data_ = 0;
  }

  name_ = m.name_;
}

unsigned long TreeMessage::bytes()
{
  if(isEmpty())
    return 0;
  else if(isLeaf())
    return (*this)().bytes();
  else
  {
    unsigned long n = 0;

    for(int i=0;i<size_;i++)
      if((*this)(i))
        n += (*this)[i].bytes();

    return n;
  }
}

ostream& operator<<(ostream& os,TreeMessage& m)
{
  m.write(os);

  return os;
}

void TreeMessage::write(ostream& os)
{
  if(isLeaf())
  {
    os << "<tree>" << endl;
    os << "  <name> " << name() << " </name>" << endl;
    os << "  <leaf>" << endl;
    os << *info_;
    os << "  </leaf>" << endl;
    os << "</tree>" << endl;
  }
  else if(isTree())
  {
    os << "<tree>" << endl;
    os << "  <name> " << name() << " </name>" << endl;
    os << "  <node>" << endl;
    os << "  <size> " << size_ << " </size>" << endl;

    if(size_ > 0)
    {
      char idx[8];

      for(int i=0;i<size_;i++)
        if((*this)(i))
        {
          sprintf(idx,"%.4d",i);

          os << "  <offset> " << idx << " </offset>" << endl;
          os << (*this)[i];
        }
        else
          os << "  <message> null </message>" << endl;
    }

    os << "  </node>" << endl;
    os << "</tree>" << endl;
  }
  else
  {
    os << "<error>" << endl;
    os << "</error>" << endl;
  }
}

void TreeMessage::assign(Message* info_)
{
  if(isTree())
    throw Exception("void TreeMessage::assign(Message*)",-1,__FILE__,__LINE__);
  else
  {
    if(this->info_)
      delete this->info_;

    this->info_ = info_;
  }
}

void TreeMessage::assign(int i,TreeMessage* m)
{
  if(!isTree())
    throw Exception("void TreeMessage::assign(int,TreeMessage*)",-1,__FILE__,__LINE__);
  else
  {
    if(i>=0 && i<size_)
    {
      if(data_[i])
        delete data_[i];

      data_[i] = m;
    }
    else
      throw Exception("void TreeMessage::assign(int,TreeMessage*)",-1,__FILE__,__LINE__);
  }
}

int TreeMessage::size()
{
  return size_;
}

TreeMessage** TreeMessage::data()
{
  return data_;
}

TreeMessage*& TreeMessage::data(int i)
{
  if(i >= 0 && i < size_)
    return data_[i];
  else
    throw Exception("TreeMessage*& TreeMessage::data(int)",-1,__FILE__,__LINE__);
}

TreeMessage& TreeMessage::operator[](int i)
{
  if(i >= 0 && i < size_ && data_[i])
    return *(data_[i]);
  else
    throw Exception("TreeMessage& TreeMessage::operator[](int)",-1,__FILE__,__LINE__);
}

Message& TreeMessage::operator()()
{
  if(info_)
    return *info_;
  else
    throw Exception("Message& TreeMessage::operator()()",-1,__FILE__,__LINE__);
}

TreeMessage*& TreeMessage::operator()(int i)
{
  if(i >= 0 && i < size_)
    return data_[i];
  else
    throw Exception("TreeMessage& TreeMessage::operator()(int)",-1,__FILE__,__LINE__);
}

Message*& TreeMessage::info()
{
  return info_;
}

TreeMessage& TreeMessage::operator=(TreeMessage& m)
{
  if(info_)
    delete info_;

  if(size_ > 0)
  {
    for(int i=0;i<size_;i++)
      if(data_[i])
        delete data_[i];

    delete[] data_;
  }

  if(m.info_)
    info_ = m.info_->clone();
  else
    info_ = 0;

  size_ = m.size_;

  if(size_ > 0)
  {
    data_ = new TreeMessage*[size_];

    for(int i=0;i<size_;i++)
      if(m.data_[i])
        data_[i] = (m.data_[i])->clone();
      else
        data_[i] = 0;
  }
  else
    data_ = 0;

  return *this;
}

bool TreeMessage::operator==(TreeMessage& m)
{
  return equal(m);
}

bool TreeMessage::operator!=(TreeMessage& m)
{
  return !equal(m);
}

bool TreeMessage::equal(TreeMessage& m)
{
  if((info_  && !m.info_) || (!info_ && m.info_))
    return false;
  else if(info_ && m.info_ && (*info_ != *(m.info_)))
    return false;
  else if(size_ != m.size_)
    return false;
  else
  {
    for(int i=0;i<size_;i++)
    {
      if(!data_[i])
      {
        if(m.data_[i])
          return false;
      }
      else
      {
        if(!m.data_[i] || !(data_[i]->equal(*(m.data_[i]))))
          return false;
      }
    }

    return true;
  }
}

string TreeMessage::name()
{
  return name_;
}

void TreeMessage::empty()
{
  if(info_)
  {
    delete info_;
    info_ = 0;
  }

  if(size_ > 0)
  {
    for(int i=0;i<size_;i++)
      if(data_[i])
        data_[i]->empty();

    delete[] data_;

    data_ = 0;
  }
}

TreeMessage& TreeMessage::operator<<(Reader& r)
{
  read(r);

  return *this;
}

TreeMessage& TreeMessage::operator>>(Writer& w)
{
  write(w);

  return *this;
}

void TreeMessage::update()
{
}

void TreeMessage::updateTree()
{
  if(info_)
    update();
  else if(size_ > 0)
  {
    for(int i=0;i<size_;i++)
      if(data_[i])
        data_[i]->updateTree();

     update();
  }
}

int TreeMessage::update(int size_)
{
  return 0;
}

TreeMessage* TreeMessage::child(int pos)
{
  return new TreeMessage();
}

bool TreeMessage::isReadable(int i)
{
  return true;
}

void TreeMessage::read(Reader& r,bool peek,bool line)
{
  if(info_)
    info_->read(r,peek,line);
  else if(size_ > 0)
  {
    for(int i=0;i<size_;i++)
      if(data_[i] && isReadable(i))
        data_[i]->read(r,peek,line);

    int newsize_;

    while((newsize_ = update(size_)) > 0)
    {
      TreeMessage* m = clone();

      int j = size_;

      init(newsize_);

      for(int i=0;i<j;i++)
        if((*m)(i))
          data_[i] = (*m)[i].clone();

      delete m;

      for(int i=j;i<newsize_;i++)
      {
        data_[i] = child(i);
        if(isReadable(i))
          data_[i]->read(r,peek,line);
      }
    }
  }
}

void TreeMessage::write(Writer& w,bool line)
{
  update();

  if(info_)
    info_->write(w,line);
  else if(size_ > 0)
  {
    for(int i=0;i<size_;i++)
      if(data_[i])
        data_[i]->write(w,line);
  }
}

TreeMessage::~TreeMessage()
{
  if(info_)
    delete info_;

  if(size_ > 0)
  {
    for(int i=0;i<size_;i++)
      if(data_[i])
        delete data_[i];

    delete[] data_;
  }
}

/*
 *  class Int2Field
 */

Int2Field::Int2Field(string name_,int value_):
  Field(2,name_)
{
  assign(value_);
}

Field& Int2Field::operator=(int value_)
{
  assign(value_);

  return *this;
}

Field* Int2Field::clone()
{
  return new Int2Field(*this);
}

bool Int2Field::isAscii()
{
  return false;
}

int Int2Field::value()
{
  int value_ = ntohs(*((short*)data()));

  return value_;
}

Int2Field::operator int()
{
  return value();
}

void Int2Field::assign(string value_)
{
  assign(atoi(value_.c_str()));
}

void Int2Field::write(ostream& os)
{
  Field::write(os);
}

void Int2Field::writeValue(ostream& os)
{
  os << "      <value> " << value() << " </value>" << endl;
}

void Int2Field::assign(int value_)
{
  char byte0 = (char) (value_ & 255);
  char byte1 = (char) ((value_ >> 8) & 255);

  (*this)[0] = byte1;
  (*this)[1] = byte0;
}

/*
 *  class Int4Field
 */

Int4Field::Int4Field(string name_,int value_):
  Field(4,name_)
{
  assign(value_);
}

Field& Int4Field::operator=(int value_)
{
  assign(value_);

  return *this;
}

bool Int4Field::isAscii()
{
  return false;
}

int Int4Field::value()
{
  int value_ = ntohl(*((int*)data()));

  return value_;
}

Int4Field::operator int()
{
  return value();
}

Field* Int4Field::clone()
{
  return new Int4Field(*this);
}

void Int4Field::assign(string value_)
{
  assign(atoi(value_.c_str()));
}

void Int4Field::write(ostream& os)
{
  Field::write(os);
}

void Int4Field::writeValue(ostream& os)
{
  os << "      <value> " << value() << " </value>" << endl;
}

void Int4Field::assign(int value_)
{
  char byte0 = (char) (value_ & 255);
  char byte1 = (char) ((value_ >> 8) & 255);
  char byte2 = (char) ((value_ >> 16) & 255);
  char byte3 = (char) ((value_ >> 24) & 255);

  (*this)[0] = byte3;
  (*this)[1] = byte2;
  (*this)[2] = byte1;
  (*this)[3] = byte0;
}

/*
 *  class BoolField
 */

BoolField::BoolField(string name_,bool value_,char truevalue_,char falsevalue_):
  Field(1,name_),
  truevalue(truevalue_),
  falsevalue(falsevalue_)
{
  assign(value_);
}

Field* BoolField::clone()
{
  return new BoolField(*this);
}

Field& BoolField::operator=(bool value_)
{
  assign(value_);

  return *this;
}

void BoolField::assign(bool value_)
{
  if(value_)
   (*this)[0] = truevalue;
  else
   (*this)[0] = falsevalue;
}

BoolField::operator bool()
{
  return value();
}

bool BoolField::value()
{
  if((*this)[0] == truevalue)
    return true;
  else
    return false;
}

void BoolField::assign(string value_)
{
  if(value_ == "T" || value_ == "t" || value_ == "1" ||
     value_ == "true" || value_ == "TRUE" || value_ == "True")
    assign(true);
  else
    assign(false);
}

bool BoolField::isAscii()
{
  return false;
}

void BoolField::write(ostream& os)
{
  Field::write(os);
}

void BoolField::writeValue(ostream& os)
{
  if(value())
    os << "    <value> true </value>" << endl;
  else
    os << "    <value> false </value>" << endl;
}

/*
 *  class OctetField
 */

OctetField::OctetField(string name_,char value_):
  Field(1,name_)
{
  assign(value_);
}

Field* OctetField::clone()
{
  return new OctetField(*this);
}

Field& OctetField::operator=(char value_)
{
  assign(value_);

  return *this;
}

void OctetField::assign(char value_)
{
   (*this)[0] = value_;
}

OctetField::operator char()
{
  return value();
}

char OctetField::value()
{
  return (*this)[0];
}

void OctetField::assign(string value_)
{
  assign(value_[0]);
}

bool OctetField::isAscii()
{
  return false;
}

void OctetField::write(ostream& os)
{
  Field::write(os);
}

void OctetField::writeValue(ostream& os)
{
  if(isprint(value()))
  {
    if(value() == '&')
      os << " <value> '&amp;' </value>";
    else if(value() == '<')
      os << " <value> '&lt;' </value>";
    else if(value() == '>')
      os << " <value> '&gt;' </value>";
    else
      os << "      <value> '" << value() << "' </value>" << endl;
  }
}

/*
 *  class StringField
 */

StringField::StringField(int size_,string name_,string value_):
  Field(size_,name_),
  isVariable(false)
{
  assign(value_);
}

StringField::StringField(string name_,string value_):
  Field(value_.length()+2,name_),
  isVariable(true)
{
  assign(value_);
}

Field* StringField::clone()
{
  return new StringField(*this);
}

Field& StringField::operator=(string value_)
{
  assign(value_);

  return *this;
}

void StringField::assign(string value_)
{
  const char* s = value_.c_str();

  if(!isVariable)
  {
    if(strlen(s) < size())
      strcpy(data(),s);
    else
      throw Exception("void StringField::assign(string)",-1,__FILE__,__LINE__);
  }
  else
  {
    init(strlen(s)+2);

    strcpy(data(),s);
  }
}

string StringField::value()
{
  return string(data());
}

StringField::operator string()
{
  return value();
}

bool StringField::isAscii()
{
  return false;
}

void StringField::write(ostream& os)
{
  Field::write(os);
}

void StringField::writeValue(ostream& os)
{
  os << "      <value> " << value() << " </value>" << endl;
}

/*
 *  class Client
 */

Client::Client(bool binary)
{
  this->binary = binary;
}

void Client::peek(Field& f)
{
  Reader* r = getReader();

  f.read(*r,true);
}

void Client::peek(Message& m)
{
  Reader* r = getReader();

  m.read(*r,true);
}

void Client::peek(TreeMessage& m)
{
  Reader* r = getReader();

  m.read(*r,true);
}

Client& Client::operator>>(TreeMessage& m)
{
  Reader* r = getReader();

  if(binary)
    m << (*r);
  else
    m.read(*r,false,true);

  return *this;
}

Client& Client::operator<<(TreeMessage& m)
{
  Writer* w = getWriter();

  if(binary)
    m >> (*w);
  else
    m.write(*w,true);

  return *this;
}

Client& Client::operator>>(Message& m)
{
  Reader* r = getReader();

  if(binary)
    m << (*r);
  else
    m.read(*r,false,true);

  return *this;
}

Client& Client::operator<<(Message& m)
{
  Writer* w = getWriter();

  if(binary)
    m >> (*w);
  else
    m.write(*w,true);

  return *this;
}

Client& Client::operator>>(Field& f)
{
  Reader* r = getReader();

  if(binary)
    f << (*r);
  else
    f.read(*r,false,true);

  return *this;
}

Client& Client::operator<<(Field& f)
{
  Writer* w = getWriter();

  if(binary)
    f >> (*w);
  else
    f.write(*w,true);

  return *this;
}

Client::~Client()
{
}

Server::Server(bool binary)
{
  this->binary = binary;
}

Server::~Server()
{
}

/*
 *  class SocketClient
 */

SocketClient::SocketClient(string ipaddress_,int port_,bool binary):
  Client(binary),
  ipaddress(ipaddress_),
  port(port_),
  clientfd(-1),
  reader(0),
  writer(0),
  isConnected(false)
{
  clientfd = init(ipaddress,port,sSockaddrin);
}

SocketClient::SocketClient(int socketfd,bool binary):
  Client(binary)
{
  this->clientfd = socketfd;

  isConnected = true;
}

int SocketClient::init(string ipaddress,int port,
                        struct sockaddr_in& sSockaddrin)
{
  struct hostent* sHostent;
  struct linger sLinger;
  struct in_addr* sInaddr;

  int clientfd;

  sHostent = gethostbyname(ipaddress.c_str());

  if (!sHostent)
    throw SocketException("void SocketClient::init()",SocketException::gethostbynameError,__FILE__,__LINE__);

  clientfd = socket(AF_INET,SOCK_STREAM,0);

  if(clientfd == -1)
    throw SocketException("void SocketClient::init()",SocketException::socketError,__FILE__,__LINE__);

  sLinger.l_onoff = 1;
  sLinger.l_linger = 0;

  if(setsockopt(clientfd,SOL_SOCKET,SO_LINGER,(char*)&sLinger,sizeof(struct linger)) == -1)
    throw SocketException("void SocketClient::init()",SocketException::setsockoptError,__FILE__,__LINE__);

  sInaddr = (struct in_addr *)* (sHostent->h_addr_list);

  sSockaddrin.sin_addr=*sInaddr;
  sSockaddrin.sin_family=AF_INET;
  sSockaddrin.sin_port=htons(port);

  return clientfd;
}

void SocketClient::connect()
{
  if(::connect(clientfd,(struct sockaddr *) &sSockaddrin, sizeof(sSockaddrin)) != 0)
    throw SocketException("void SocketClient::connect()",SocketException::connectError,__FILE__,__LINE__);

  isConnected = true;
}

void SocketClient::close()
{
  if(isConnected)
  {
    if((::close(clientfd)) == -1)
      throw SocketException("void SocketClient::close()",SocketException::closeError,__FILE__,__LINE__);
  }

  isConnected = false;
}

Reader* SocketClient::getReader()
{
  if(reader)
    return reader;
  else
  {
    if(!isConnected)
      throw Exception("Reader* SocketClient::getReader()",-1,__FILE__,__LINE__);
    else
    {
      reader = new SocketReader(clientfd);
      return reader;
    }
  }
}

Writer* SocketClient::getWriter()
{
  if(writer)
    return writer;
  else
  {
    if(!isConnected)
      throw Exception("Writer* SocketClient::getWriter()",-1,__FILE__,__LINE__);
    else
    {
      writer = new SocketWriter(clientfd);
      return writer;
    }
  }
}

/*
 *  class SocketServer
 */

SocketServer::SocketServer(int port_,bool binary):
  Server(binary),
  port(port_)
{
  serverfd = init(port,sSockaddrin);
}

int SocketServer::init(int port,struct sockaddr_in& sSockaddrin)
{
  struct linger sLinger;
  struct in_addr* sInaddr;

  int option;

  int serverfd;

  serverfd = socket(AF_INET,SOCK_STREAM,0);

  if(serverfd == -1)
    throw SocketException("void SocketServer::init()",SocketException::socketError,__FILE__,__LINE__);

  memset(&sSockaddrin,0,sizeof(sSockaddrin));

  sSockaddrin.sin_family = AF_INET;
  sSockaddrin.sin_addr.s_addr = htonl(INADDR_ANY);
  sSockaddrin.sin_port = htons(port);

  option = 1;

  if(setsockopt(serverfd,SOL_SOCKET,SO_REUSEADDR,(char*)&option,sizeof(int)) == -1)
    throw SocketException("void SocketServer::init()",SocketException::setsockoptError,__FILE__,__LINE__);

  if(bind(serverfd,(struct sockaddr*)&sSockaddrin,sizeof(sSockaddrin)))
    throw SocketException("void SocketServer::init()",SocketException::bindError,__FILE__,__LINE__);

  if(listen(serverfd,5) == -1)
    throw SocketException("void SocketServer::init()",SocketException::listenError,__FILE__,__LINE__);

  return serverfd;
}

Client* SocketServer::accept()
{
  int clientfd;

  if((clientfd = ::accept(serverfd,(struct sockaddr *) 0,0)) == -1)
    throw SocketException("void SocketServer::accept()",SocketException::acceptError,__FILE__,__LINE__);
  else
    return new SocketClient(clientfd,binary);
}

void SocketServer::close()
{
  if((::close(serverfd)) == -1)
    throw SocketException("void SocketServer::close()",SocketException::closeError,__FILE__,__LINE__);
}

/*
 *  class FileClient
 */

FileClient::FileClient(string infilename_,string outfilename_,bool binary):
  Client(binary),
  infilename(infilename_),
  outfilename(outfilename_),
  infd(-1),
  outfd(-1),
  reader(0),
  writer(0),
  isOpened(false)
{
}

void FileClient::connect()
{
  if(!infilename.empty())
  {
    infd = ::open(infilename.c_str(),O_RDONLY);

    if(infd == -1)
      throw Exception("void FileClient::connect()",-1,__FILE__,__LINE__);
  }

  if(!outfilename.empty())
  {
    mode_t stdmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;

    outfd = ::open(outfilename.c_str(),O_WRONLY | O_CREAT,stdmode);

    if(outfd == -1)
      throw Exception("void FileClient::connect()",-1,__FILE__,__LINE__);
  }

  isOpened = true;
}

void FileClient::close()
{
  if(isOpened)
  {
    if(((infd != -1) && (::close(infd)) == -1) ||
       ((outfd != -1) && (::close(outfd)) == -1))
      throw Exception("void FileClient::close()",-1,__FILE__,__LINE__);
  }

  isOpened = false;
}

Reader* FileClient::getReader()
{
  if(reader)
    return reader;
  else
  {
    if(!isOpened)
      throw Exception("Reader* FileClient::getReader()",-1,__FILE__,__LINE__);
    else
    {
      if(infd != -1)
        reader = new FileReader(infd);

      return reader;
    }
  }
}

Writer* FileClient::getWriter()
{
  if(writer)
    return writer;
  else
  {
    if(!isOpened)
      throw Exception("Writer* FileClient::getWriter()",-1,__FILE__,__LINE__);
    else
    {
      if(outfd != -1)
        writer = new FileWriter(outfd);

      return writer;
    }
  }
}

/*
 *  Helper functions
 */

void daemon()
{
  int i;
  pid_t pid;

  if(((pid = fork()) != 0))
    exit(0);

  setsid();

  signal(SIGHUP,SIG_IGN);

  if((pid = fork()) != 0)
    exit(0);
}

unsigned long getLocalIPAddress()
{
  struct hostent* hptr;
  struct utsname local_host_name;

  if(uname(&local_host_name) == -1)
    return 0;

  if(!(hptr = gethostbyname(local_host_name.nodename)))
    return 0;

  return ((struct in_addr*) (hptr->h_addr_list[0]))->s_addr;
}

/* end of file */