Saturday, January 29, 2011

Setting up passwordless SSH logins on ubuntu

First setup a clean install of ssh and config it from local and remote
sudo apt-get install openssh-server
 ssh -l username ipaddresss
 ifconfig | grep "inet addr"

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.factory-defaults
 sudo chmod a-w /etc/ssh/sshd_config.factory-defaults
 sudo vi /etc/ssh/sshd_config

Then add(or change) the lines too read the following (to diable password loging and forwarding and spec limited access)
PasswordAuthentication no
 AllowTcpForwarding no
 X11Forwarding no
 AllowUsers yourRemoteUsername

Then add your key (do it now before restart or you will need a console access)
cat >> .ssh/authorized_keys 

paste in the one line with the rsa public key info and then reboot the machine or restart ssh with.
sudo /etc/init.d/ssh restart

Refer:
https://help.ubuntu.com/community/SSH/OpenSSH/Configuring#disable-password-authentication
https://help.ubuntu.com/community/SSH/OpenSSH/Keys

Thursday, January 27, 2011

Memory Blob Accessors (void*)

Dealing with generic Memory Blobs(The ominous void* or char*) is one thing that most programs know should be avoided. However most of use end up having to work with them. They are essential in homogeneous file and packet reader/writers, where the contents of the data dictate the class and type of next subsection of the data. And in caching and memory pool systems where the data contents and type is unrelated to the management of the blob.

Lucking they are easily handled with templates and reinterpret_cast. Here is some code demonstrating a blob handling class, with a streaming interface and fileIO capabilities. As you can see I got a little ambitious while coding it and so not all of the code is compile tested(ie templates dont compile unless used..) But it will build as is and execute, and I will sooner or latter get back and check the rest of it.

//build with g++
#include <stdint.h>

#include <istream>
#include <iostream>
#include <iomanip>

#include <string> 
#include <cstring>
#include <stdexcept>

using namespace std;

class Blob
{
public:
  //******* CONSTRUCTION ***********//
  
  Blob(uint32_t _size)
  {
    data = new char[_size];
    size = _size;
    memset(data, 0, size);
  }

  //*******  SIZING  ***********//
  uint32_t getSize() const
  { return size; }

  void resize(uint32_t _size)
  {
    uint32_t copySize = std::min(_size,size);
    char* old_data = data;
    data = new char[_size];
    if(_size > size)
       memset(&data[size], 0, _size - size);  //zero new part
    memcpy(data, old_data, copySize);         //copy old
    size = _size;
    delete old_data;
  }
 
  //*******  IMPORT/EXPORT  ***********//

  template<typename T>
  bool importObject(const T& src, 
      uint32_t offset = 0)
  {
    if((offset + sizeof(T)) > size) 
      return false;
    
    memcpy(&data[offset], &src, sizeof(T)); 
    return true;
  }

  template<typename T>
  bool exportObject(T& dst, 
      uint32_t offset = 0)
  {
    if((offset + sizeof(T)) > size) 
      return false;

    T* value = reinterpret_cast<T*>(&data[offset]);
    dst = *value;
    return true;
  }

  template<typename T, typename P>
  bool importObjectGetter(const T& src, 
     const P& (T::*get)() const, 
     uint32_t offset = 0)
  {
    if((offset + sizeof(P)) > size) 
      return false;
    
    const P& value = (src.*get)();
    memcpy(&data[offset], &value, sizeof(P)); 
    return true;
  }

  template<typename T, typename P>
  bool exportObjectSetter(T& dst, 
     bool (T::*set)(P*), 
     uint32_t offset = 0)
  {
    if((offset + sizeof(P)) > size) 
      return false;

    P* value = reinterpret_cast<P*>(&data[offset]);
    (dst.*set)(value);
    return true;
  }

  template<typename T>
  bool importPointer(const T* src, 
       uint32_t len, 
       uint32_t offset = 0)
  {
    if((offset + len) > size) 
      return false;
    
    memcpy(&data[offset], src, len); 
    return true;
  }

  template<typename T>
  bool exportPointer(T* dst, 
       uint32_t len, 
       uint32_t offset = 0)
  {
    if((offset + len) > size) 
      return false;

    memcpy(dst, &data[offset], len); 
    return true;
  }

  bool importZeroTermed(const string src, 
   uint32_t offset = 0)
  {
    uint32_t len = src.length();
    if((offset + len) > size) 
      return false;
    
    memcpy(&data[offset], src.c_str(), len); 
    return true;
  }

  bool exportZeroTermed(string& dst, 
   uint32_t offset = 0)
  {
    uint32_t len = strlen(&data[offset]);
    if((offset + len) > size) 
      return false;

    dst = &data[offset]; 
    return true;
  }

  //*********  DIRECT ACCESS  ***********//

  template<typename T>
  T* accessAsObject(uint32_t offset = 0)
  {
    if((offset + sizeof(T)) > size) 
      throw runtime_error("Out of Range");

    return reinterpret_cast<T*>(&data[offset]);
  }

  //*********  DUMPING  ***********//

  void print(ostream& out)
  {
    const int spaceStep = 4;
    const int lineStep  = 16;
    int totOffset=0;
    int subOffset=0;

    out << "Size(in hex): " << hex << size << endl;
    while(totOffset < size)
      {
 // the label..
 out << hex << setfill('0') << setw(2*sizeof(uint32_t)) 
     << totOffset << ": ";

 // the hex..
 int subOffset=0;
 while(subOffset < lineStep)
   {
     int offset = totOffset + subOffset; 
     if(offset <  size)
       {
  uint16_t number = (0xff & data[offset]);
  out << hex << setfill('0') << setw(2) 
      << number;
       }
     else
       out << "  ";
     subOffset++;
     if((subOffset % spaceStep) == 0)
       out << " ";
   }

 out << " : ";
 //the text
 subOffset=0;
 while(subOffset < lineStep)
   {
     int offset = totOffset + subOffset; 
     if(offset < size)
       {
  if(
     (data[offset] >= 33 ) && 
     (data[offset] <= 126 )
     )
    out << data[offset];
  else
    out << " ";
       }
     else
       out << " ";
     subOffset++;
   }
     
 out << endl;
 totOffset += lineStep;
      }
    out << dec;
  }

  //*********** FILE IO *************//
  void writeToFile(iostream& file)
  { file.write(data, size);  }

  void readFromFile(iostream& file)
  { file.read(data, size); }

  void writeSizedToFile(iostream& file)
  {
    file.write(reinterpret_cast<char*>(&size), sizeof(uint32_t));
    file.write(data, size);  
  }

  void readSizedFromFile(iostream& file)
  { 
    file.read(reinterpret_cast<char*>(&size), sizeof(uint32_t));
    resize(size);
    file.read(data, size); 
  }

private:
  char*   data;
  uint32_t size;
};

ostream& operator<<(ostream& out, Blob& val)
{
    val.print(out);
    return out;
}

class BlobStream
{
public:
  BlobStream(uint32_t _size, bool _autoScale=true, uint32_t _autoScaleFactor=4) :
    blob(_size),
    offset(0),
    autoScaleEnabled(_autoScale),
    autoScaleFactor(_autoScaleFactor)
  {}

  //*********  ACCESSORS  ***********//

  uint32_t getOffset()
  { return offset; }

  Blob& getBlob()
  { return blob; }

  //*********  SIZERS  ***********//

  void resetOffset()
  { offset = 0; }

  void finaliseSize()
  { 
    blob.resize(offset); 
    autoScaleEnabled = false;
  }

  void autoScaleUp(uint32_t min = 0)
  {
    if( !autoScaleEnabled)
      throw runtime_error("Buffer Size locked!");

    uint32_t size = blob.getSize();
    if(size == 0) size = 1;
    blob.resize(std::max(autoScaleFactor*size, min));
  }
  //*********  STREAMERS  ***********//
  
  template<typename T>
  BlobStream& operator<<(T& src)
  {
    while( !blob.importObject(src, offset) )
      autoScaleUp(sizeof(T));
    offset += sizeof(T);
    return *this;
  }

  BlobStream& operator<<(string& src)
  {
    while( !blob.importZeroTermed(src, offset) )
      autoScaleUp(src.length());
    offset += src.length();
    return *this;
  }

  BlobStream& operator<<(char* src)
  {
    while( !blob.importZeroTermed(src, offset) )
      autoScaleUp(strlen(src));
    offset += strlen(src);
    return *this;
  }

  template<typename T>
  BlobStream& operator>>(T& src)
  {
    if( !blob.exportObject(src, offset) )
      throw runtime_error("Lack of Buffer Data");
    offset += sizeof(T);
    return *this;
  }

  BlobStream& operator>>(string& src)
  {
    if( !blob.exportZeroTermed(src, offset) )
      throw runtime_error("Lack of Buffer Data OR no termination");
    offset += src.length();
    return *this;
  }

private:
  bool     autoScaleEnabled;
  uint32_t autoScaleFactor;

  Blob blob;
  uint32_t offset;
};

//Test
struct A
{
  char a1;
  int a2;
};

struct B
{
  char b1[10];
  float b2;
};

int main()
{
  BlobStream bs(0);
  A a;
  B b;
  
  a.a1 = '#';
  a.a2 = 10;

  memcpy(b.b1, "here it is", 10); 
  b.b2 = 0.2;
  
  bs << a << b << " -- and then some";

  cout << "Before Finalisation" << endl;
  bs.getBlob().print(cout);
  bs.finaliseSize();
  bs.resetOffset();
  cout << endl << "After Finalisation" << endl;
  bs.getBlob().print(cout);

  A c;
  B d;
  string e;

  bs >> c >> d >> e;
  
  cout << endl
       << "Retrived Data:" << endl
       << " " << c.a1 << endl
       << " " << c.a2 << endl
       << " " << d.b1 << endl
       << " " << d.b2 << endl
       << " " << e    << endl;    
}

The result looks like this:
Before Finalisation
Size(in hex): 80
00000000: 231e1a66 0a000000 68657265 20697420  : #  f    here it
00000010: 69732200 cdcc4c3e 202d2d20 616e6420  : is"   L> -- and
00000020: 7468656e 20736f6d 65000000 00000000  : then some
00000030: 00000000 00000000 00000000 00000000  :
00000040: 00000000 00000000 00000000 00000000  :
00000050: 00000000 00000000 00000000 00000000  :
00000060: 00000000 00000000 00000000 00000000  :
00000070: 00000000 00000000 00000000 00000000  :

After Finalisation
Size(in hex): 2a
00000000: 231e1a66 0a000000 68657265 20697420  : #  f    here it
00000010: 69732200 cdcc4c3e 202d2d20 616e6420  : is"   L> -- and
00000020: 7468656e 20736f6d 6500               : then some

Retrived Data:
 #
 10
 here it is"
 0.2
  -- and then some

Wednesday, January 19, 2011

Autocleanup using the destructor Vs atexit and signal

Performing autocleanup using the destructor of a locally defined variable like a std::auto_ptr is a neat trick. However it has some serious drawbacks when considered against signals and functions such as std::exit. Many programmers don't realize that auto_ptrs DO NOT operate correctly when exit() is called.

Here is a table summarizing which function operates(O) and which doesnt(X) and in a certain situation.

Destructors
Auto Pointers
et al
atexit() signal()
Real signals X X O
Raised signals
(without signal handler)
X X X
Raised signals
(with signal handler)
O O O
Soft exceptions(divide by zero) O O X
throws O O X
Exit() et al O X X

Notes:
  • There is are several important differences between Raised signals and Real signals.
    • Real signals WILL forced the exit of the program.
    • Raised signals can continue if a signal handler is installed, and will allow for correct stack unwind after the fact. This can lead to a real sigv if you didn't ensure the exit but cleaned up the critical memory anyway.
  • When functions such as exit() and terminate() are called the stack is NOT unwound and objects within the local scope are NOT destroyed before the program terminates.
  • The atexit function is not called when the program dies from a crash. A signal handler is required.

My advice is to use a singleton class for any global controllers (like a database access handler that needs to open and close the database). This singleton MUST NULL OUT ITS SELF POINTERS and check for the NULL on both its initialize and destroy routines as it may be called multiple times, depending on how the program/threads are coming down/up.

Here is some code to test it out for yourself.
#include <csignal>
#include <iostream>
#include <stdlib.h>


using namespace std;

void bye_exit(void)
{
    cout << "AtExit Closed!" << endl;
}

void bye_sig(int param)
{
    cout << "Signal Closed!" << endl;
    //std::exit();  //<<-- this really needs to be here!
}

int main(int argc, char const * const *argv)
{
    try
    {
        if (atexit(bye_exit) != 0) 
        {
            cerr << "atexit implosion" << endl;
            return EXIT_FAILURE;
        }

        if (signal (SIGTERM,bye_sig)==SIG_ERR) 
        {
            cerr << "signal implosion" << endl;
            return EXIT_FAILURE;    
        }

        //uncomment to see the effects of signal on raise by runing mode 4
        //if (signal (SIGSEGV,bye_sig)==SIG_ERR) 
        //{
        //    cerr << "signal implosion" << endl;
        //    return EXIT_FAILURE;    
        //}
        
        struct AutoStuff
        {
            AutoStuff()
            {
                cout << "AutoStuff Open!" << endl;
            }

            ~AutoStuff()
            {
                cout << "AutoStuff Closed!" << endl;
            }
        } automatic;

        
        int trial = -1;
        if(argc == 2) trial = atoi(argv[1]);

        cout << "Trial: " << trial << endl;
    
        switch (trial)
        {
            case 0:
                std::exit(EXIT_SUCCESS);
            case 1:
                {
                    float  b = 0;
                    float  a = 1/b;
                }
            case 2:
                {
                    throw "ahhh!";
                }
            case 3:
                {
                    raise(SIGTERM);
                    cout << "Wow! Its still alive!" << endl;
                }                
            case 4:
                {
                    raise(SIGSEGV);
                    cout << "Wow! Its still alive!" << endl;
                }                
            case 5:
                return EXIT_SUCCESS;
        }

    }
    catch (exception const &e)
    {
        cout << "Unexpected exception: " <<  e.what() << endl;
    }
    catch (...)
    {
        cout << "Unexpected exception" << endl;
    }
    return  EXIT_FAILURE;
}