Saturday, November 23, 2013

Extracting formatted input using stringstream

Description: The following program shows how to extract formatted input from a stringstream object.


#include <iostream>
#include <fstream>
#include <sstream>

/*
  Extracting formatted input using stringstream >> operator.

  While extracting input, if there are any errors it could set eofbit, badbit or failbit in its internal error state falgs.

  Then it checks its exception mask to decide wheter to throw an exception or not.

  For example if failbit is set in exception mask and  failbit was set during extraction then >> operation would

  throw an ios_base::failure exception.
*/

using namespace std;
void getexceptionmask(const stringstream& ss)
{

ios_base::iostate exceptionmask = ss.exceptions();


if(exceptionmask & ifstream::badbit)
{
cout << "badbit is set. If an operation on sstream causes this bit to be set, an exception of type ios_base::failure would be thrown.\n" ;
}

if(exceptionmask & ifstream::failbit)
{
cout << "failbit is set. If an operation on sstream causes this bit to be set, an exception of type ios_base::failure would be thrown.\n" ;
}
}

void checkerrorstate(const stringstream& ss)
{

if(ss.bad())
{
cout << "Bad bit is set. We failed to read an integer" << endl;
}

if(ss.fail())
{
cout << "Fail bit or Bad bit is set. We failed to read an integer" << endl;
}
}

int main(int argc, char** argv)
{

stringstream ss;

cout << "Printing the default exception mask." << endl;

getexceptionmask(ss);

cout << "Printing after setting badbit and failbit exception mask." << endl;

ss.exceptions(ifstream::badbit | ifstream::failbit);

getexceptionmask(ss);

cout << "Printing after clearing the exception mask." << endl;

/*  
*if exception mask  has only goodbit (which is zero) streams  do not throw exceptions due to error state flags being set
*/
ss.exceptions(ifstream::goodbit);

getexceptionmask(ss);

int n;

cout << "Trying to read an integer when the stream is empty." << endl;

ss >> n;

cout << "Checking if any of the error bits were set." << endl;

checkerrorstate(ss);

/*
* clearing the errot state.
*/

ss.clear();

cout << "Printing exception mask after setting fail bit." << endl;

ss.exceptions(ifstream::failbit);

getexceptionmask(ss);

cout << "Now again trying to read an integer. We should get an exception now." << endl;

ss >> n;

}

Output:

Printing the default exception mask.
Printing after setting badbit and failbit exception mask.
badbit is set. If an operation on sstream causes this bit to be set, an exception of type ios_base::failure would be thrown.
failbit is set. If an operation on sstream causes this bit to be set, an exception of type ios_base::failure would be thrown.
Printing after clearing the exception mask.
Trying to read an integer when the stream is empty.
Checking if any of the error bits were set.
Fail bit or Bad bit is set. We failed to read an integer
Printing exception mask after setting fail bit.
failbit is set. If an operation on sstream causes this bit to be set, an exception of type ios_base::failure would be thrown.
Now again trying to read an integer. We should get an exception now.
terminate called after throwing an instance of 'std::ios_base::failure'
  what():  basic_ios::clear

Aborted

Saturday, October 19, 2013

A ReadWrite implementation with preference to waiting writers.

Description:  Below is an implementation of ReadWrite using Mutex and Condition Variables with preference to waiting writers. Before a read lock is given, we check if there are any writers waiting to get write lock. Similary, when a lock is released, if a writer is waiting to get the lock , preference is given to them over readers.

RwLock.h (Header File)

#include <pthread.h>


class RwLock
{
    //nreaders = 0 , indicates no. reader/writer exists.
    //nreaders > 0, indicates one or more read lock exists.
    //nreaders=-1, indicates a write lock exists.

    int nreaders;

    int nwaitwriters;
   
    pthread_mutex_t rw_mutex;

    pthread_cond_t rw_condreader;
   
    pthread_cond_t rw_condwriter;

    public:

    RwLock();

    void getReadLock();

    void getWriteLock();

    void unLock();

    ~RwLock();

       
};


RwLock.C (Implementation)

#include "RwLock.h"

RwLock :: RwLock()
{
    nreaders = 0;

    nwaitwriters = 0;

    pthread_mutex_init(&rw_mutex, NULL);   

    pthread_cond_init(&rw_condreader, NULL);

    pthread_cond_init(&rw_condwriter, NULL);
}

void RwLock :: getReadLock()
{
    //Obtain Lock.
    pthread_mutex_lock(&rw_mutex);

    //If  a WRITER exists(nreaders = -1)wait for signal from writer.
    while(-1 == nreaders || 0 < nwaitwriters)
    {
        pthread_cond_wait(&rw_condwriter, &rw_mutex);
    }

    //increment no. of readers
    nreaders++;

    pthread_mutex_unlock(&rw_mutex);       
}


void RwLock :: getWriteLock()
{
    //Obtain Lock
    pthread_mutex_lock(&rw_mutex);

    //if nreader is != 0 it means either a reader or writer is present. wait for signal from reader/writer (do it in a loop)
    while(0 != nreaders)
    {
        //Increment no. of waiting writers.
        nwaitwriters++;

        pthread_cond_wait(&rw_condreader, &rw_mutex);
       
        //Decrement no. of waiting writers.
        nwaitwriters--;
       
    }

    //set nreader = -1 indicating a writer is present.
    nreaders = -1;

    //unlock the mutex.
    pthread_mutex_unlock(&rw_mutex);
}

void RwLock :: unLock()
{
    //Obtain Lock
    pthread_mutex_lock(&rw_mutex);

    if(0 < nreaders)
    {
        //one of the readers is done. decrement readers count.
        nreaders--;

        if(0 == nreaders)
        {
            //last reader is done.

            if(0 < nwaitwriters)
            {
                //if a writer is waiting
                pthread_cond_signal(&rw_condreader);
            }
        }
    }
    else if(-1 == nreaders)
    {
        //a writer is done. set nreaders to 0 indicating no reader/writer exists.
        nreaders = 0;

        if(0 < nwaitwriters)
        {
            //if a writer is waiting.
            pthread_cond_signal(&rw_condreader);
        }
        else
        {           
            //broadcast to any waiting readers.
            pthread_cond_broadcast(&rw_condwriter);
        }
    }

    pthread_mutex_unlock(&rw_mutex);
}

RwLock :: ~RwLock()
{
    //Destroy condition variable and mutex.
    pthread_mutex_destroy(&rw_mutex);

    pthread_cond_destroy(&rw_condreader);

    pthread_cond_destroy(&rw_condwriter);
}

Sunday, October 6, 2013

Implementation of readwrite lock using mutex and condition variables.

Description: Below is an implementation of readwrite lock using mutex and condition variables. Note that, the implementation does not give any preference to waiting writers.


RwLock.h (Header File)

#include <pthread.h>
 
class RwLock
{
    //nreaders = 0 , indicates no. reader/writer exists.
    //nreaders > 0, indicates one or more read lock exists.
    //nreaders=-1, indicates a write lock exists.

    int nreaders;
   
    pthread_mutex_t rw_mutex;

    pthread_cond_t rw_cond;

    public:

    RwLock();

    void getReadLock();

    void getWriteLock();

    void unLock();

    ~RwLock();
       
};

RwLock.C (Implementation of our  ReadWrite Lock)
#include "RwLock.h"

RwLock :: RwLock()
{
    nreaders = 0;
   
    // Initialize mutex and condition variable.
    pthread_mutex_init(&rw_mutex, NULL);   

    pthread_cond_init(&rw_cond, NULL);
}

void RwLock :: getReadLock()
{
    //Obtain Lock.
    pthread_mutex_lock(&rw_mutex);

    // If  a WRITER exists(nreaders = -1)wait for signal from writer.
    while(-1 == nreaders)
    {
        pthread_cond_wait(&rw_cond, &rw_mutex);
    }

    // Increment no. of reader
    nreaders++;

    //Unlock the mutex.
    pthread_mutex_unlock(&rw_mutex);       
}


void RwLock :: getWriteLock()
{
    //Obtain Lock
    pthread_mutex_lock(&rw_mutex);

    // If nreader is != 0 it means either a reader or writer is present. wait for signal from reader/writer (do it in a loop)
    while(0 != nreaders)
    {
        pthread_cond_wait(&rw_cond, &rw_mutex);
    }

    // Set nreader = -1 indicating a writer is present.
    nreaders = -1;

    // Unlock the mutex.
    pthread_mutex_unlock(&rw_mutex);
}

void RwLock :: unLock()
{
    // Obtain Lock.
    pthread_mutex_lock(&rw_mutex);

    if(0 < nreaders)
    {
        // One of the readers is done. decrement readers count.
        nreaders--;

        if(0 == nreaders)
        {
            // Last reader is done.
            pthread_cond_broadcast(&rw_cond);
        }
    }
    else if(-1 == nreaders)
    {
        // A writer is done. set nreaders to 0 indicating no reader/writer exists.
        nreaders = 0;
        pthread_cond_broadcast(&rw_cond);
    }
    // Unlock the mutex.
    pthread_mutex_unlock(&rw_mutex);
}

RwLock :: ~RwLock()
{
    // Destroy condition variable and mutex.
    pthread_mutex_destroy(&rw_mutex);

    pthread_cond_destroy(&rw_cond);
}

Below is a sample program that uses this implementation and output obtained.


#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<iostream>

#include "RwLock.h"

using namespace std;

RwLock rwlock;

void* reader(void* arg)
{
    cout << "Obtaining read lock." << endl;

    rwlock.getReadLock();
   
    cout << "Obtained read lock." << endl;

    sleep(5);

    cout << "Releasing read lock." << endl;

    rwlock.unLock();

    cout << "Released read lock." << endl;   
}


void* writer(void* arg)
{
    cout << "Obtaining write lock." << endl;

    rwlock.getWriteLock();
   
    cout << "Obtained write lock." << endl;

    sleep(4);

    cout << "Releasing write lock." << endl;

    rwlock.unLock();

    cout << "Released write lock." << endl;   
}

int main(int argc, char** argv)
{
    pthread_t r1,r2,r3,w1,w2;

    int res;

    cout << endl;   

    res = pthread_create(&r1, NULL, reader, NULL);

    if(0 != res)
    {
        cout << "Failed to start thread." << endl;
        exit(1);
    }
           
    res = pthread_create(&r2, NULL, reader, NULL);

    if(0 != res)
    {
        cout << "Failed to start thread." << endl;
        exit(1);
    }           

    sleep(1);

    res = pthread_create(&w1, NULL, writer, NULL);

    if(0 != res)
    {
        cout << "Failed to start thread." << endl;
        exit(1);
    }   

    res = pthread_create(&w2, NULL, writer, NULL);

    if(0 != res)
    {
        cout << "Failed to start thread." << endl;
        exit(1);
    }   
    pthread_exit(NULL);       
}

Output:
Obtaining read lock.
Obtained read lock. 
Obtaining read lock.
Obtained read lock.            /*Two read locks obtained*/
Obtaining write lock.
Obtaining write lock.         /*Two threads waiting for write lock*/
Releasing read lock.
Released read lock.
Releasing read lock.
Released read lock.         /*Two read locks are released*/
Obtained write lock.       
Releasing write lock.
Released write lock.       /*A thread first gets write lock and releases it*/  
Obtained write lock.      /*Second thread gets the write lock*/
Releasing write lock.
Released write lock.

Saturday, September 28, 2013

MinHeap implementation.

Description:  The below program is an implementation of MinHeap. While creating the MinHeap, youneed to specify the max. no of elements it can hold. It provides two operations insert() and getMinimum().


HeaderFile:

#include <exception>

using namespace std;

#define HEAP_EMPTY 1

#define HEAP_FULL 2

class MinHeapException : public exception
{
    private:
    int code;

    public:
    MinHeapException(int n) : code(n)
    {

    }

    const char* what() const throw()
    {
        switch(code)
        {
            case HEAP_EMPTY:
                return "Heap is empty.";

            case HEAP_FULL:
                return "Heap is full.";
        }
    }   
};


class MinHeap
{
    private:
   
    const int capacity;
    int size;
    int* ptr;

    public:

    MinHeap(int n);
       
    void insert(int n) throw(MinHeapException);

    int getMinimum() throw(MinHeapException);

    void display();

    ~MinHeap();   
};

Implementation of our MinHeap:

#include "MinHeap.h"
#include <iostream>

using namespace std;

MinHeap :: MinHeap(int n) : capacity(n), size(0), ptr(new int[n+1])
{
       
}


void MinHeap :: insert(int n) throw(MinHeapException)
{
    /*
     * If the heap is already full, throw a exception.
     */   

    if(size == capacity)
    {
        throw MinHeapException(HEAP_FULL);
    }

    int hole;

    /*Increment the size of heap*/
    size++;

     /*The hole points  to the last position.
     *Move up the hole, still we get suitable position. i.e the parent of the hole
     *must be greater than the new no. that we want to insert in the hole.
     */
    for(hole = size ; hole > 1 && ptr[hole/2] > n; hole = hole/2)
    {
        ptr[hole] = ptr[hole/2];
    }

    ptr[hole] = n;
}


int MinHeap :: getMinimum() throw(MinHeapException)
{

    /*
     *If the heap is empty throw an exception.
     */   
    if(0 == size)
    {
        throw MinHeapException(HEAP_EMPTY);   
    }

    int firstelement = ptr[1];

    int lastelement = ptr[size];

    int hole;
    int smallelement;

    /*
     * Decrement the size of heap.
     */

    size--;

    /*
     * Intially the hole is created in the first element.
     * The hole is moved down till we get to a poistion where the childrens are greater than the last element.
     */ 
    for(hole = 1;  hole <= size/2; hole = smallelement)
    {
       
        if(2*hole+1 <= size)
        {
            /*Ther are two childs*/
            if(lastelement < ptr[2*hole] && lastelement < ptr[2*hole+1])
            {
                /*Bot the children are greater than the lastelement. So last element can be placed here*/                break;
            }
           
            /*Find to which subtree the hole should be moved*/
            smallelement = ptr[2*hole] < ptr[2*hole+1] ? 2*hole : 2*hole+1;

        }
        else
        {       
            /*There is one child*/
            if(lastelement < ptr[2*hole])
            {
                /*The child is greater than the lastelement*/
                break;
            }
            smallelement = 2*hole;
        }

        /*Move the samllest children into hole. hole is moved done to smallest children  posistion*/            ptr[hole] = ptr[smallelement];   
    }
   
    /*Replace the hole with the last element*/
    ptr[hole] = lastelement;

    /*Return the first element*/
    return firstelement;

}

void MinHeap :: display()
{
    int i;

    for(i=1; i <= size; i++)
    {
        cout << ptr[i] << " ";
    }
    cout << endl;   
}

MinHeap :: ~MinHeap()
{
    delete [] ptr;
}


int main(int argc, char** argv)
{

    try
    {

            MinHeap heap(11);

            heap.insert(13);
            heap.insert(14);
            heap.insert(16);
            heap.insert(19);
            heap.insert(21);
            heap.insert(19);
            heap.insert(68);
            heap.insert(65);
            heap.insert(26);
            heap.insert(32);
            heap.insert(31);
            heap.insert(41);

            cout << "1st Minimum:" << heap.getMinimum() << endl;

            heap.display();

            cout << "2nd Minimum:" << heap.getMinimum() << endl;

            heap.display();

            cout << "3rd Minimum:" << heap.getMinimum() << endl;

            heap.display();

            cout << "4th Minimum:" << heap.getMinimum() << endl;

            heap.display();

            cout << "5th Minimum:" << heap.getMinimum() << endl;
    }
    catch(MinHeapException& e)
    {
        cout << e.what();
    }
}

Wednesday, September 25, 2013

Converting string representation of time to unix epoch time.

#include <iostream>
#include <string>
#include <time.h>
#include <stdlib.h>

using namespace std;

int main(int argc, char** argv)
{
    string s_time = "Thu, 19 Oct 2006 11:52:22 +0200";

    struct tm tm;

    /*Convert from string representation to struct tm */

    char* ptr = strptime(s_time.c_str(), "%a, %d %b %Y %T %z", &tm);

    if('\0' != *ptr)
    {
        /*A part of the string was not  processed*/
        cout << "Following part of string not processed:" << ptr  << endl;
    }

    /*Convert from struct tm to time_t structure.*/

    time_t time = mktime(&tm);

    if(-1 == time)
    {
        cout << "Failed to convert from 'struct tm' to 'time_t'" << endl;
        exit(1);
    }
    else
    {
        cout << "Given time in unix time stamp:" << time << endl;
    }

    exit(0);
}

Output:
Given time in unix time stamp:1161238942

Saturday, September 7, 2013

Example Apache module for reading request body.

Description: 
An apache c module, that reads the request body from a PUT/POST request body, saves it on the disk  and returns HTTP 201 (Created) status code if successful and returns the URI which the user can use to retrieve back the contents in "Location" response header and the name of the file in which the contents were saved in the response body.



Generating template for the module using 'apxs' tool:

  Using the -g option of 'apxs' tool, we can generate a basic template of a module and add our logic to it.

    #> /usr/local/apache2/bin/apxs -g -n putfile
    Creating [DIR]  putfile
    Creating [FILE] putfile/Makefile
    Creating [FILE] putfile/modules.mk
    Creating [FILE] putfile/mod_putfile.c
    Creating [FILE] putfile/.deps

  The above command creates a template for a module named 'putfile' and a Makefile to compile.
 
Module source code:
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "http_log.h"
#include "ap_config.h"

#define BLOCKSIZE 4096

const char* documentRoot = "/usr/local/apache2/htdocs/";

int readAndWriteData(request_rec *r, int fd)
{
     int ret = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);

     if(OK == ret && ap_should_client_block(r))
     {
          char* buffer = (char*)apr_pcalloc(r->pool, BLOCKSIZE);

          int len;

          while((len=ap_get_client_block(r, buffer, BLOCKSIZE)) > 0)
          {
                if(-1 == write(fd, buffer, len))
                        return -1;
          }

          return (-1 == len ? -1 : 0);
     }

     return -1;

}


static int putfile_handler(request_rec *r)
{

    /*
    * For each request, apache decides based on the 'SetHanlder' and 'AddHandler'
   * directive, the module which would handle the request and populates the request_rec::handler
     * field with the name of the module.
     *
   * A well behaving mo1dule should check if the value of this field matches with its name and
     * process the request only if it does. 
     */
    if (strcmp(r->handler, "putfile")) {
        return DECLINED;
    }

    /*
     * This module supports only 'PUT'/'POST' requests.
     */
    if(M_PUT != r->method_number && M_POST != r->method_number)
    {
        return DECLINED;
    }


    char fileName[200] = {'\0'};

    struct timeval tv;

    gettimeofday(&tv, NULL);

    sprintf(fileName, "%sputfile/%ld.%ld", documentRoot, tv.tv_sec, tv.tv_usec);


    int fd = creat(fileName, 0644);

    if(-1 == fd)
    {
        return HTTP_INTERNAL_SERVER_ERROR;
    }
    close(fd);

    if(0 != ret)
    {
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    r->content_type = "text/plain";

    /* Set response HTTP status */
    r->status = HTTP_CREATED;

    apr_table_add(r->headers_out, "Location", fileName + strlen(documentRoot));

    ap_rputs(fileName + strlen(documentRoot), r);

    return OK;
}

static void putfile_register_hooks(apr_pool_t *p)
{
    ap_hook_handler(putfile_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA putfile_module = {
    STANDARD20_MODULE_STUFF,
    NULL,                  /* create per-dir    config structures */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    NULL,                  /* table of config file commands       */
    putfile_register_hooks  /* register hooks                      */
};

Compiling and Installing the module:
Running the below command would compile the module and copy the shared library created to the modules directory (/usr/local/apache2/modules)

#> /usr/local/apache2/bin/apxs -c -i  mod_putfile.c

Apache configuration:

LoadModule putfile_module     modules/mod_putfile.so

<Location /putfile>
  SetHandler putfile
</Location>


Testing the module:
i) Create a sample file to send in the request.

#> echo "Sample Module" > input_file
 
#> cat input_file
Sample Module

ii) Send a PUT request.
#> curl -T ./input_file  -D header http://127.0.0.1/putfile/
putfile/1378555086.385071

#> cat header
HTTP/1.1 100 Continue

HTTP/1.1 201 Created
Date: Sat, 07 Sep 2013 11:58:06 GMT
Server: Apache/2.2.22 (Unix) mod_ssl/2.2.22 OpenSSL/1.0.0e
Location: putfile/1378555086.385071
Content-Length: 25
Content-Type: text/plain

iii) Retrieve the file from the server.

#>wget http://127.0.0.1/putfile/1378555086.385071
--2013-09-07 17:29:19--  http://127.0.0.1/putfile/1378555086.385071
Connecting to 127.0.0.1:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14 [text/plain]
Saving to: `1378555086.385071'

100%[===========================================================================================================>] 14          --.-K/s   in 0s     

2013-09-07 17:29:19 (754 KB/s) - `1378555086.385071' saved [14/14]

#> cat 1378555086.385071
Sample Module

Sunday, August 25, 2013

TCP Echo Server using epoll, an example for Event Driven Server

Description: Implementation of tcp echo server using epoll. The server accepts connections from clients, reads data and echo's the same data back to the clients. All the operations accepting connections from clients, reading and writing data are done in a non-blocking manner.


server.h

/*
 * Contains definitions of constants and data structures used.
 */

#define SERVERPORT 8080

#define MAXCONN 200

#define MAXEVENTS 100

#define MAXLEN 255

struct EchoEvent
{
    int fd;
    uint32_t event;
    char data[MAXLEN];
    int length;
    int offset;

};

server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>
#include "server.h"

int epollfd;

void modifyEpollContext(int epollfd, int operation, int fd, uint32_t events, void* data)
{
    struct epoll_event server_listen_event;

    server_listen_event.events = events;

    server_listen_event.data.ptr = data;

    if(-1 == epoll_ctl(epollfd, operation, fd, &server_listen_event))
    {
        printf("Failed to add an event for socket%d Error:%s", fd, strerror(errno));
        exit(1);       
    }
   
}
void* handle(void* ptr)
{
    struct EchoEvent* echoEvent = ptr;

    if(EPOLLIN == echoEvent->event)
    {
        int n = read(echoEvent->fd, echoEvent->data, MAXLEN);
   
        if(0 == n)
        {
            /*
             * Client closed connection.
             */

            printf("\nClient closed connection.\n");
            close(echoEvent->fd);
            free(echoEvent);
        }
        else if(-1 == n)
        {
           
            close(echoEvent->fd);
            free(echoEvent);
        }
        else
        {
            echoEvent->length = n;
       
            printf("\nRead data:%s Length:%d", echoEvent->data , n);           
            printf("\nAdding write event.\n");
            /*
             * We have read the data. Add an write event so that we can
             * write data whenever the socket is ready to be written.
             */

            modifyEpollContext(epollfd, EPOLL_CTL_ADD, echoEvent->fd, EPOLLOUT, echoEvent);
        }       
   
    }
    else if(EPOLLOUT == echoEvent->event)
    {
        int ret;

         ret = write(echoEvent->fd, (echoEvent->data) + (echoEvent->offset), echoEvent->length);
       
        if( (-1 == ret && EINTR == errno) || ret < echoEvent->length)
        {
            /*
             * We either got EINTR or write only sent partial data.
             * Add an write event. We still need to write data.
             */           
   
           
            modifyEpollContext(epollfd, EPOLL_CTL_ADD, echoEvent->fd, EPOLLOUT, echoEvent);
           
            if(-1 != ret)
            {
               /*
               * The previous write wrote only partial data to the socket.
               */

                echoEvent->length = echoEvent->length - ret;
                echoEvent->offset = echoEvent->offset + ret;   
            }
           
        }
        else if(-1 == ret)
        {
           /*
            * Some other error occured.
            */
            close(echoEvent->fd);
            free(echoEvent);
        }
       
        else
        {   
       
          /*
           * The entire data was written. Add an read event,
           * to read more data from the socket.
           */
            printf("\nAdding Read Event.\n");   
            modifyEpollContext(epollfd, EPOLL_CTL_ADD, echoEvent->fd, EPOLLIN, echoEvent);
        }
    }

}


void makeSocketNonBlocking(int fd)
{
    int flags;
   
    flags = fcntl(fd, F_GETFL, NULL);

    if(-1 == flags)
    {
        printf("fcntl F_GETFL failed.%s", strerror(errno));
        exit(1);
    }

    flags |= O_NONBLOCK;

    if(-1 == fcntl(fd, F_SETFL, flags))   
    {
        printf("fcntl F_SETFL failed.%s", strerror(errno));
        exit(1);
    }       
}


int main(int argc, char** argv)
{
   
    int serverfd;

    struct sockaddr_in server_addr;

    struct sockaddr_in clientaddr;
    socklen_t clientlen = sizeof(clientaddr);

   /*
    * Create server socket. Specify the nonblocking socket option.
    *
    */   
    serverfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);

    if(-1 == serverfd)
    {
        printf("Failed to create socket.%s", strerror(errno));
        exit(1);
    }   
   
    bzero(&server_addr, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVERPORT);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
   
   /*
    * Bind the server socket to the required ip-address and port.
    *
    */

    if(-1 == bind(serverfd, (struct sockaddr*)&server_addr, sizeof(server_addr)))
    {
        printf("Failed to bind.%s", strerror(errno));
        exit(1);
    }

   /*
    * Mark the server socket has a socket that will be used to .
    * accept incoming connections.
    */
  
  if(-1 == listen(serverfd, MAXCONN))
    {
        printf("Failed to listen.%s", strerror(errno));
        exit(1);
    }

   /*
    * Create epoll context.
    */
  
 
    epollfd = epoll_create(MAXCONN);

    if(-1 == epollfd)
    {
        printf("Failed to create epoll context.%s", strerror(errno));
        exit(1);
    }

   /*
    * Create read event for server socket.
    */
  
modifyEpollContext(epollfd, EPOLL_CTL_ADD, serverfd, EPOLLIN, &serverfd);

   /*
    * Main loop that listens for event.
    */
    struct epoll_event *events = calloc(MAXEVENTS, sizeof(struct epoll_event));
    while(1)
    {
        int n = epoll_wait(epollfd, events, MAXEVENTS, -1);

        if(-1 == n)               
        {
            printf("Failed to wait.%s", strerror(errno));
            exit(1);
        }
       
        int i;
        for(i = 0; i < n; i++)
        {
            if(events[i].data.ptr == &serverfd)
            {
                if(events[i].events & EPOLLHUP || events[i].events & EPOLLERR)
                {
                  /*
                   * EPOLLHUP and EPOLLERR are always monitored.
                   */
   
                close(serverfd);
                     exit(1);
                }   

               /*
               * New client connection is available. Call accept.
               * Make connection socket non blocking.
               * Add read event for the connection socket.
               */
   
            int connfd = accept(serverfd, (struct sockaddr*)&clientaddr, &clientlen);

                if(-1 == connfd)
                {
                    printf("Accept failed.%s", strerror(errno));
                    exit(1);
                }
                else
                {
                    printf("Accepted connection.Sleeping for minute.\n");
                   
                    makeSocketNonBlocking(connfd);
               
                    sleep(60);
               
                    printf("Adding a read event\n");

                    struct EchoEvent* echoEvent = calloc(1, sizeof(struct EchoEvent));

                    echoEvent->fd = connfd;
                   
                  /*
                  * Add a read event.
                  */
      
              modifyEpollContext(epollfd, EPOLL_CTL_ADD, echoEvent->fd, EPOLLIN, echoEvent);
                }   
            }
            else
            {
                /*
                 *A event has happend for one of the connection sockets.
                 *Remove the connection socket from the epoll context.
                 * When the event is handled by handle() function ,
                 *it will add the required event to listen for this 
                 *connection socket again to epoll
                 *context
                 */   


                if(events[i].events & EPOLLHUP || events[i].events & EPOLLERR)
                {
                    struct EchoEvent* echoEvent = (struct EchoEvent*) events[i].data.ptr;
                    printf("\nClosing connection socket\n");
                    close(echoEvent->fd);
                    free(echoEvent);
                }
                else if(EPOLLIN == events[i].events)   
                {
                    struct EchoEvent* echoEvent = (struct EchoEvent*) events[i].data.ptr;
                   
                    echoEvent->event = EPOLLIN;
                  /*
                 * Delete the read event.
                 */   
          
          modifyEpollContext(epollfd, EPOLL_CTL_DEL, echoEvent->fd, 0, 0);

                    handle(echoEvent);
                }
                else if(EPOLLOUT == events[i].events)   
                {
                    struct EchoEvent* echoEvent = (struct EchoEvent*) events[i].data.ptr;
                   
                    echoEvent->event = EPOLLOUT;
                   
                    /*
                   * Delete the write event.
                   */       
               
    modifyEpollContext(epollfd, EPOLL_CTL_DEL, echoEvent->fd, 0, 0);

                    handle(echoEvent);
                }
            }
           
        }
    }

    free(events);
    exit(0);
}


/*
 *About Level Trigerred:
 * We have added an fd for event EPOLLIN and then data is available for read in fd. epoll_wait will continuously report EPOLLIN event still all data is read.
 *
 *About Edge Trigerred:
 * In the above case, epoll_wait will report only once. When it reports we have to read all data. If without reading all data if we call epoll_wait
 * it will not report again. Also lets say fd is already readable, you are adding an event EPOLLIN | EPOLLET and calling epoll_wait, it will report EP * OLLIN.
 *
 * Default behaviour is level trigerred. To enable EdgeTrigerred use EPOLLET option while adding events.
 */

Thursday, August 15, 2013

Example nginx module for reading request body.

Description:

    The module reads the contents  from PUT/POST request body, saves it on the disk  and returns HTTP 202 (Accepted) status code if successful and returns the URI which the user can use to retrieve back the contents in "Location" response header and the name of the file in which the contents were saved in the response body.


Module Source Code:

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <string.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

const char*  documentRoot = "/usr/local/nginx/html/";


static void ngx_http_sample_put_handler(ngx_http_request_t *r)
{
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "put handler called");

    char filename[200] = { '\0' };

    struct timeval tv;

    gettimeofday(&tv, NULL);

    sprintf(filename, "%s%ld.%ld", documentRoot, tv.tv_sec, tv.tv_usec);



    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "FileName:%s", filename);

    int fd = creat(filename, 0644);

    if(-1 == fd)
    {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to create mail file.%s", strerror(errno));
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;

    }

    if(NULL == r->request_body->temp_file)
    {
        /*
         * The entire request body is available in the list of buffers pointed by r->request_body->bufs.
         *
         * The list can have a maixmum of two buffers. One buffer contains the request body that was pre-read along with the request headers.
         * The other buffer contains the rest of the request body. The maximum size of the buffer is controlled by 'client_body_buffer_size' directive.
         * If the request body cannot be contained within these two buffers, the entire body  is writtin to the temp file and the buffers are cleared.
         */
        ngx_buf_t    *buf;

        ngx_chain_t  *cl;


        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Writing data from buffers.");
        cl = r->request_body->bufs;
        for( ;NULL != cl; cl = cl->next )
        {
            buf = cl->buf;
            if(write(fd, buf->pos, buf->last - buf->pos) < 0)
            {

                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                close(fd);
                return;
            }
        }
    }
    else
    {
        /**
         * The entire request body is available in the temporary file.
         *
         */
        size_t ret;
        size_t offset = 0;
        unsigned char data[4096];

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Writing data from temp file.");

        while(  (ret = ngx_read_file(&r->request_body->temp_file->file, data, 4096, offset)) > 0)
        {
            if(write(fd, data, ret) < 0)
            {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                close(fd);
                return;
            }
            offset = offset + ret;
        }
    }

    close(fd);

    unsigned char* data;

    data = ngx_pcalloc(r->pool, strlen(filename));
    if (data == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
    }

    ngx_memcpy(data, filename + strlen(documentRoot), strlen(filename) - strlen(documentRoot));

    r->headers_out.status = NGX_HTTP_ACCEPTED;

    r->headers_out.content_length_n = strlen(filename) - strlen(documentRoot);
    r->headers_out.content_type.len = sizeof("text/plain") - 1;
    r->headers_out.content_type.data = (u_char *) "text/plain";

    r->headers_out.location = ngx_list_push(&r->headers_out.headers);

    if (NULL == r->headers_out.location) {
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
    }
    r->headers_out.location->hash = 1;
    r->headers_out.location->key.len = sizeof("Location") - 1;
    r->headers_out.location->key.data = (u_char *) "Location";
    r->headers_out.location->value.len = strlen(filename) - strlen(documentRoot);
    r->headers_out.location->value.data = data;
    ngx_http_send_header(r);


    ngx_int_t rc;

    rc = ngx_http_send_header(r);

    if(rc == NGX_ERROR || rc > NGX_OK)
    {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Sending headers failed.");
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
    }

    ngx_buf_t *b;
    ngx_chain_t out;

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
    }


    b->pos = data;

    b->last = data + (strlen(filename));

    b->memory = 1;

    b->last_buf = 1;

    out.buf = b;

    out.next = NULL;

    ngx_http_finalize_request(r, ngx_http_output_filter(r, &out));

    return;

}



static ngx_int_t
ngx_http_sample_handler(ngx_http_request_t *r)
{
    ngx_int_t     rc;

   /**
    * Specify the handler function to be called after reading the request body.
    */
    rc = ngx_http_read_client_request_body(r, ngx_http_sample_put_handler);

    if (rc >= NGX_HTTP_SPECIAL_RESPONSE){
            return rc;
    }

   return NGX_DONE;
}

static char *
ngx_http_sample(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_loc_conf_t  *clcf;

    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

    /**
     * Get the location configuration and specify the function
     * that would hanlde requests for this location.
     */

    clcf->handler = ngx_http_sample_handler;


    return NGX_CONF_OK;
}

static ngx_command_t  ngx_http_sample_commands[] = {
    { ngx_string("sample"),
      NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
      ngx_http_sample,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

      ngx_null_command
};


static ngx_http_module_t  ngx_http_sample_module_ctx = {
    NULL,                          /* preconfiguration */
    NULL,                          /* postconfiguration */

    NULL,                          /* create main configuration */
    NULL,                          /* init main configuration */
    NULL,                          /* create server configuration */
    NULL,                          /* merge server configuration */

    NULL,  /* create location configuration */
    NULL /* merge location configuration */
};


ngx_module_t  ngx_http_sample_module = {
    NGX_MODULE_V1,
    &ngx_http_sample_module_ctx, /* module context */
    ngx_http_sample_commands,   /* module directives */
    NGX_HTTP_MODULE,               /* module type */
    NULL,                          /* init master */
    NULL,                          /* init module */
    NULL,                          /* init process */
    NULL,                          /* init thread */
    NULL,                          /* exit thread */
    NULL,                          /* exit process */
    NULL,                          /* exit master */
    NGX_MODULE_V1_PADDING
};

Module configuration:
http {

        location /samples {

            sample;
        }

}

Testing the module:

i) Create a sample file to send in the request.

# echo "Sample Module" > input_file
# cat input_file
Sample Module

ii) Send the http request.

# curl -T ./input_file  -D header http://192.168.1.3/samples
1376574012.497879

iii) The reqest and response headers received.
# cat header
HTTP/1.1 100 Continue

HTTP/1.1 202 Accepted
Server: nginx/1.4.2
Date: Thu, 15 Aug 2013 13:40:12 GMT
Content-Type: text/plain
Content-Length: 17
Connection: keep-alive
Location: 1376574012.497879

iv) Use the filename specified in the "Location" response header field / in the response body to retrieve it.

# wget http://192.168.1.3/1376574012.497879
--2013-08-15 19:11:55--  http://192.168.1.3/1376574012.497879
Connecting to 192.168.1.3:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14 [application/octet-stream]
Saving to: `1376574012.497879'

100%[==============================================================================================================================>] 14          --.-K/s   in 0s

2013-08-15 19:11:55 (66.4 KB/s) - `1376574012.497879' saved [14/14]

v) The retrieved file is the same as the contents sent in the first http request.
# cat 1376574012.497879
Sample Module


Reference:


Tuesday, August 13, 2013

Working with openssl utility.

Working with 'openssl' utility.

'openssl' utility provides various useful commands for performing different opertions on certificates and private key files. Using the 'req' command we can create self-signed certs and certificate requests.

Creating a selfsigned certificate using openssl.
The 'req' command of openssl utility can be used to create self signed certs.
 
 
root@bala-VirtualBox:/home/bala/# openssl req -new -x509 -days 365 -sha1 -newkey rsa:1024 -nodes -keyout server.key -out server.pem -subj '/O=Company/OU=Department/CN=www.example-ca.com'
Generating a 1024 bit RSA private key
.....................++++++
.........++++++
writing new private key to 'server.key'
 
Running the above commands creates two files the public certificate(server.pem) and private certificate / private key(server.key)
 
root@bala-VirtualBox:/home/bala/MyTrials/sslcerts# ls
server.key  server.pem
 
Let us look at  what the options used in the above command mean:
 
-x509 identifies that a certificate is required, rather than just a certificate request (see below). 
 
-days 365 sets the certificate to expire in a year. You may want to extend this period. Make a note of the expiry date so that you can renew it when necessary! 
 
-sha1 specifies that SHA1 encryption should be used. 
 
-newkey rsa:1024 sets the key as 1024 bit RSA. 
 
-nodes specifies no passphrase.  (Otherwise apache would ask for a password everytime it restarts).
 
-keyout and -out specify where to store the certificate and key. The key should be root-readable only; the certificate can be world-readable, and must be readable by the user that Apache runs as. 
 
-subj flag sets the company name, department name, and the web site address. If you leave these out, you'll be prompted for them. The CN must be the same as the address of your web site, otherwise the certificate won't match and users will receive a warning when connecting. Make sure you don't use a challenge password.
 
What does the public certificate and private key files look like.
 
The above command created the public certificate and private key's in PEM format which is a Base64 encoded version of the certificate and the key's content.
 
root@bala-VirtualBox:/home/bala/MyTrials/sslcerts# cat server.pem 
-----BEGIN CERTIFICATE-----
MIICVjCCAb+gAwIBAgIJAKK+9tt+i9P+MA0GCSqGSIb3DQEBBQUAMEQxEDAOBgNV
BAoMB0NvbXBhbnkxEzARBgNVBAsMCkRlcGFydG1lbnQxGzAZBgNVBAMMEnd3dy5l
eGFtcGxlLWNhLmNvbTAeFw0xMzA3MzExNDUwMTNaFw0xNDA3MzExNDUwMTNaMEQx
EDAOBgNVBAoMB0NvbXBhbnkxEzARBgNVBAsMCkRlcGFydG1lbnQxGzAZBgNVBAMM
End3dy5leGFtcGxlLWNhLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ro1wW5/+ID5OaJNbG/ecMWnHZgcDIJED2uTCIDbe5tIubPaMs2Tj1GJ3hiNrsC0Y
IY7SY5USoTeN0Q0exb0DRP4X3hh1Y3HLtF8yCh/aUhXqxcd8kSLKLdIX8vKcOLLF
mXWk2wqFPXkHatZBFZw4aBfmPA164cznGqI5ELNlkSsCAwEAAaNQME4wHQYDVR0O
BBYEFAu63UbEF+ea6/teGZGvtB8DqYtsMB8GA1UdIwQYMBaAFAu63UbEF+ea6/te
GZGvtB8DqYtsMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAe+tDrTNe
/oj77pI2o3k8u29HX/cxhxZpDzvvbVP+ezGL2KRweHsJg9J1d40dpoCZFaHDCHga
GLxI8ecC/lWZYOr/yJcCurF0+zAXsGRZ3d35xF/ITP1enKCb+XaDIoOP/LKNglwk
qeHouhABGWyTENS+X8rT5TqpyNy69IuFkZs=
-----END CERTIFICATE-----
 
root@bala-VirtualBox:/home/bala/MyTrials/sslcerts# cat server.key 
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK6NcFuf/iA+TmiT
Wxv3nDFpx2YHAyCRA9rkwiA23ubSLmz2jLNk49Rid4Yja7AtGCGO0mOVEqE3jdEN
HsW9A0T+F94YdWNxy7RfMgof2lIV6sXHfJEiyi3SF/LynDiyxZl1pNsKhT15B2rW
QRWcOGgX5jwNeuHM5xqiORCzZZErAgMBAAECgYEAni7hFreL9a5hIhX/5/1hl8oT
gJt0MwwX4UOTxNvU7nqkxew8n8obSXoedPoeeh6zkp26fbI3mtAcfcmVDH94uIqk
hOkq7AFWbkDmFCAwJB6CJWdaLdicP3Qrzpyz7emq0qsHtjxlFS4OHBuPtthTh8fJ
Ey0rsA+B2VTI056NIaECQQDefpHSIm1omTY1U8LQI1AnM76nihkgCl5y0xRNrSAb
07aVP604DdPRcsMFMJ9CZ46JtlR58YrwytDBfaVJfS3xAkEAyNamaUPZFyGFKYjx
83drQBt/7kNERywjoWBz98YHLnzDGuc4BSa6U+oLUMCoUSiskyl3CfPuPIxAm5RT
oI+E2wJAWwZ1Kf8ju7NS1iZagUSxOhiVW33IIa+cTGXG3LCDfl7zR8QxXclqazoE
R09JGKW9TuHlVa5YJYMUPNTmllY8QQJBAKjarza5cH/eEtME7EdCE83mUPzFWVZt
add3/IhI2ijfhDnORG8wTF/Y2oKeN+VkSRPBPPAFQjttv7QOVPEdORkCQGexGcqN
qVgmGIf9LGaumvJzEiNwKmRW/s1/ypqQNLr3LuPw9P96BlbFQCLFWbB1nfCfZ0q5
ObHpOPjys7zWy6M=
-----END PRIVATE KEY-----
 
To actually look at what information is contained in these files, we can use -text option of the openssl commands 'x509' and 'rsa' respectively.
 
 
root@bala-VirtualBox:/home/bala/MyTrials/sslcerts# openssl x509 -in server.pem -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            a2:be:f6:db:7e:8b:d3:fe
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: O=Company, OU=Department, CN=www.example-ca.com
        Validity
            Not Before: Jul 31 14:50:13 2013 GMT
            Not After : Jul 31 14:50:13 2014 GMT
        Subject: O=Company, OU=Department, CN=www.example-ca.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (1024 bit)
                Modulus:
                    00:ae:8d:70:5b:9f:fe:20:3e:4e:68:93:5b:1b:f7:
                    9c:31:69:c7:66:07:03:20:91:03:da:e4:c2:20:36:
                    de:e6:d2:2e:6c:f6:8c:b3:64:e3:d4:62:77:86:23:
                    6b:b0:2d:18:21:8e:d2:63:95:12:a1:37:8d:d1:0d:
                    1e:c5:bd:03:44:fe:17:de:18:75:63:71:cb:b4:5f:
                    32:0a:1f:da:52:15:ea:c5:c7:7c:91:22:ca:2d:d2:
                    17:f2:f2:9c:38:b2:c5:99:75:a4:db:0a:85:3d:79:
                    07:6a:d6:41:15:9c:38:68:17:e6:3c:0d:7a:e1:cc:
                    e7:1a:a2:39:10:b3:65:91:2b
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                0B:BA:DD:46:C4:17:E7:9A:EB:FB:5E:19:91:AF:B4:1F:03:A9:8B:6C
            X509v3 Authority Key Identifier: 
                keyid:0B:BA:DD:46:C4:17:E7:9A:EB:FB:5E:19:91:AF:B4:1F:03:A9:8B:6C
 
            X509v3 Basic Constraints: 
                CA:TRUE
    Signature Algorithm: sha1WithRSAEncryption
        7b:eb:43:ad:33:5e:fe:88:fb:ee:92:36:a3:79:3c:bb:6f:47:
        5f:f7:31:87:16:69:0f:3b:ef:6d:53:fe:7b:31:8b:d8:a4:70:
        78:7b:09:83:d2:75:77:8d:1d:a6:80:99:15:a1:c3:08:78:1a:
        18:bc:48:f1:e7:02:fe:55:99:60:ea:ff:c8:97:02:ba:b1:74:
        fb:30:17:b0:64:59:dd:dd:f9:c4:5f:c8:4c:fd:5e:9c:a0:9b:
        f9:76:83:22:83:8f:fc:b2:8d:82:5c:24:a9:e1:e8:ba:10:01:
        19:6c:93:10:d4:be:5f:ca:d3:e5:3a:a9:c8:dc:ba:f4:8b:85:
        91:9b
-----BEGIN CERTIFICATE-----
MIICVjCCAb+gAwIBAgIJAKK+9tt+i9P+MA0GCSqGSIb3DQEBBQUAMEQxEDAOBgNV
BAoMB0NvbXBhbnkxEzARBgNVBAsMCkRlcGFydG1lbnQxGzAZBgNVBAMMEnd3dy5l
eGFtcGxlLWNhLmNvbTAeFw0xMzA3MzExNDUwMTNaFw0xNDA3MzExNDUwMTNaMEQx
EDAOBgNVBAoMB0NvbXBhbnkxEzARBgNVBAsMCkRlcGFydG1lbnQxGzAZBgNVBAMM
End3dy5leGFtcGxlLWNhLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ro1wW5/+ID5OaJNbG/ecMWnHZgcDIJED2uTCIDbe5tIubPaMs2Tj1GJ3hiNrsC0Y
IY7SY5USoTeN0Q0exb0DRP4X3hh1Y3HLtF8yCh/aUhXqxcd8kSLKLdIX8vKcOLLF
mXWk2wqFPXkHatZBFZw4aBfmPA164cznGqI5ELNlkSsCAwEAAaNQME4wHQYDVR0O
BBYEFAu63UbEF+ea6/teGZGvtB8DqYtsMB8GA1UdIwQYMBaAFAu63UbEF+ea6/te
GZGvtB8DqYtsMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAe+tDrTNe
/oj77pI2o3k8u29HX/cxhxZpDzvvbVP+ezGL2KRweHsJg9J1d40dpoCZFaHDCHga
GLxI8ecC/lWZYOr/yJcCurF0+zAXsGRZ3d35xF/ITP1enKCb+XaDIoOP/LKNglwk
qeHouhABGWyTENS+X8rT5TqpyNy69IuFkZs=
-----END CERTIFICATE-----
 
 
root@bala-VirtualBox:/home/bala/MyTrials/sslcerts# openssl rsa -in server.key -text
Private-Key: (1024 bit)
modulus:
    00:ae:8d:70:5b:9f:fe:20:3e:4e:68:93:5b:1b:f7:
    9c:31:69:c7:66:07:03:20:91:03:da:e4:c2:20:36:
    de:e6:d2:2e:6c:f6:8c:b3:64:e3:d4:62:77:86:23:
    6b:b0:2d:18:21:8e:d2:63:95:12:a1:37:8d:d1:0d:
    1e:c5:bd:03:44:fe:17:de:18:75:63:71:cb:b4:5f:
    32:0a:1f:da:52:15:ea:c5:c7:7c:91:22:ca:2d:d2:
    17:f2:f2:9c:38:b2:c5:99:75:a4:db:0a:85:3d:79:
    07:6a:d6:41:15:9c:38:68:17:e6:3c:0d:7a:e1:cc:
    e7:1a:a2:39:10:b3:65:91:2b
publicExponent: 65537 (0x10001)
privateExponent:
    00:9e:2e:e1:16:b7:8b:f5:ae:61:22:15:ff:e7:fd:
    61:97:ca:13:80:9b:74:33:0c:17:e1:43:93:c4:db:
    d4:ee:7a:a4:c5:ec:3c:9f:ca:1b:49:7a:1e:74:fa:
    1e:7a:1e:b3:92:9d:ba:7d:b2:37:9a:d0:1c:7d:c9:
    95:0c:7f:78:b8:8a:a4:84:e9:2a:ec:01:56:6e:40:
    e6:14:20:30:24:1e:82:25:67:5a:2d:d8:9c:3f:74:
    2b:ce:9c:b3:ed:e9:aa:d2:ab:07:b6:3c:65:15:2e:
    0e:1c:1b:8f:b6:d8:53:87:c7:c9:13:2d:2b:b0:0f:
    81:d9:54:c8:d3:9e:8d:21:a1
prime1:
    00:de:7e:91:d2:22:6d:68:99:36:35:53:c2:d0:23:
    50:27:33:be:a7:8a:19:20:0a:5e:72:d3:14:4d:ad:
    20:1b:d3:b6:95:3f:ad:38:0d:d3:d1:72:c3:05:30:
    9f:42:67:8e:89:b6:54:79:f1:8a:f0:ca:d0:c1:7d:
    a5:49:7d:2d:f1
prime2:
    00:c8:d6:a6:69:43:d9:17:21:85:29:88:f1:f3:77:
    6b:40:1b:7f:ee:43:44:47:2c:23:a1:60:73:f7:c6:
    07:2e:7c:c3:1a:e7:38:05:26:ba:53:ea:0b:50:c0:
    a8:51:28:ac:93:29:77:09:f3:ee:3c:8c:40:9b:94:
    53:a0:8f:84:db
exponent1:
    5b:06:75:29:ff:23:bb:b3:52:d6:26:5a:81:44:b1:
    3a:18:95:5b:7d:c8:21:af:9c:4c:65:c6:dc:b0:83:
    7e:5e:f3:47:c4:31:5d:c9:6a:6b:3a:04:47:4f:49:
    18:a5:bd:4e:e1:e5:55:ae:58:25:83:14:3c:d4:e6:
    96:56:3c:41
exponent2:
    00:a8:da:af:36:b9:70:7f:de:12:d3:04:ec:47:42:
    13:cd:e6:50:fc:c5:59:56:6d:69:d7:77:fc:88:48:
    da:28:df:84:39:ce:44:6f:30:4c:5f:d8:da:82:9e:
    37:e5:64:49:13:c1:3c:f0:05:42:3b:6d:bf:b4:0e:
    54:f1:1d:39:19
coefficient:
    67:b1:19:ca:8d:a9:58:26:18:87:fd:2c:66:ae:9a:
    f2:73:12:23:70:2a:64:56:fe:cd:7f:ca:9a:90:34:
    ba:f7:2e:e3:f0:f4:ff:7a:06:56:c5:40:22:c5:59:
    b0:75:9d:f0:9f:67:4a:b9:39:b1:e9:38:f8:f2:b3:
    bc:d6:cb:a3
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCujXBbn/4gPk5ok1sb95wxacdmBwMgkQPa5MIgNt7m0i5s9oyz
ZOPUYneGI2uwLRghjtJjlRKhN43RDR7FvQNE/hfeGHVjccu0XzIKH9pSFerFx3yR
Isot0hfy8pw4ssWZdaTbCoU9eQdq1kEVnDhoF+Y8DXrhzOcaojkQs2WRKwIDAQAB
AoGBAJ4u4Ra3i/WuYSIV/+f9YZfKE4CbdDMMF+FDk8Tb1O56pMXsPJ/KG0l6HnT6
Hnoes5Kdun2yN5rQHH3JlQx/eLiKpITpKuwBVm5A5hQgMCQegiVnWi3YnD90K86c
s+3pqtKrB7Y8ZRUuDhwbj7bYU4fHyRMtK7APgdlUyNOejSGhAkEA3n6R0iJtaJk2
NVPC0CNQJzO+p4oZIApectMUTa0gG9O2lT+tOA3T0XLDBTCfQmeOibZUefGK8MrQ
wX2lSX0t8QJBAMjWpmlD2RchhSmI8fN3a0Abf+5DREcsI6Fgc/fGBy58wxrnOAUm
ulPqC1DAqFEorJMpdwnz7jyMQJuUU6CPhNsCQFsGdSn/I7uzUtYmWoFEsToYlVt9
yCGvnExlxtywg35e80fEMV3Jams6BEdPSRilvU7h5VWuWCWDFDzU5pZWPEECQQCo
2q82uXB/3hLTBOxHQhPN5lD8xVlWbWnXd/yISNoo34Q5zkRvMExf2NqCnjflZEkT
wTzwBUI7bb+0DlTxHTkZAkBnsRnKjalYJhiH/SxmrprycxIjcCpkVv7Nf8qakDS6
9y7j8PT/egZWxUAixVmwdZ3wn2dKuTmx6Tj48rO81suj
-----END RSA PRIVATE KEY-----
 
 
Creating certificate chains. 
We will use the above created self-signed certificate to create a certificate chain.
 
First create a certificate signing request (csr).
 
#> openssl req -new  -days 365 -sha1 -newkey rsa:1024 -nodes -keyout client.key -out client.csr -subj '/O=Company/OU=Department/CN=www.example-client.com'
Generating a 1024 bit RSA private key
......++++++
...............++++++
writing new private key to 'client.key'
-----
 
#> cat client.csr
-----BEGIN CERTIFICATE REQUEST-----
MIIBhzCB8QIBADBIMRAwDgYDVQQKDAdDb21wYW55MRMwEQYDVQQLDApEZXBhcnRt
ZW50MR8wHQYDVQQDDBZ3d3cuZXhhbXBsZS1jbGllbnQuY29tMIGfMA0GCSqGSIb3
DQEBAQUAA4GNADCBiQKBgQDO8uP/6oKzRaEJNdMCj/CbiJ0hcXq9WOGfp2lr1i5g
5IJmXiyiAbt2pKMWr/mU8+C0KoRd9ki+S5tVmTV9PHP0CwlKVdYGv6GWhw6/ZrUv
CUF/2GVtM2bQUPyXbloR+r/Y5o6oxHWbRdcPi+0fytz5SIglebjltmoUhP8UqUeG
yQIDAQABoAAwDQYJKoZIhvcNAQEFBQADgYEALLfrFNqbOfpY50RCR2aSRe5gi1Bf
Vj2RlvqkuWSbNV57MYZMn75bFMWerR3PJPmiFpbj2HnW+UWfKbYepVIqSWl6fio8
InXN379DWzJebqCvHiVHZRg/Fz4HG4WwqEAkfCSuq7UpSHVvQgPoqtnH1bylK9Zm
Ti0eDr8oqeuWxCg=
-----END CERTIFICATE REQUEST-----
 
Now we will use the self-signed  cert as the root cert to sign the above csr.
 
 
#> openssl x509 -req -CA server.pem -CAkey server.key -set_serial 1 -in client.csr -out client.pem -outform PEM
Signature ok
subject=/O=Company/OU=Department/CN=www.example-client.com
Getting CA Private Key
#> openssl x509 -in client.pem  -text
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 1 (0x1)
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: O=Company, OU=Department, CN=www.example-ca.com
        Validity
            Not Before: Aug 13 13:57:55 2013 GMT
            Not After : Sep 12 13:57:55 2013 GMT
        Subject: O=Company, OU=Department, CN=www.example-client.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (1024 bit)
 
 
 
Converting PEM format to DER format.
 
The following command converts the certificates and private key files from PEM format to DER format. DER format is just the binary version(Base64 decoded) of the PEM format.
 
#> openssl x509 -in server.pem -inform PEM -out server.der -outform DER
#> openssl rsa -in server.key -inform PEM -out server.key.der -outform DER
writing RSA key
#> ls
server.der  server.key  server.key.der  server.pem
 
If you open the .der file the contents will be in binary form, unlike the .pem files which contained Base64 encoded content.
 
Adding passphrase to the private key.
The private key files created so far were not password protected. We can add passphrase to existing private key files. For example, the following command createa new private key file "server.key.2" with the passphrase "changeit" from the existing file "server.key"
 
#> openssl rsa -des3 -in server.key -inform PEM -out server.key.2 -outform PEM -passout pass:changeit
writing RSA key
#> openssl rsa -in server.key.2 -text
Enter pass phrase for server.key.2:
 
 
Creating PKCS12 file.
A "pkcs12" file format allows you to have both the public certificate and the private key within a single file. 'pkcs12' command allows you to create pkcs12 files from existing certs and private keys.
 
# > openssl pkcs12 -export -in server.pem -inkey server.key -out server.pkcs12
Enter Export Password:
Verifying - Enter Export Password:
#> ls
server.der  server.key  server.key.2  server.key.der  server.pem  server.pkcs12
 
Separating public certificates from pkcs12 file.
 
#> openssl pkcs12 -in server.pkcs12 -clcerts -nokeys -out server_cert_from_pkcs12_file
Enter Import Password:
MAC verified OK
# >ls
server_cert_from_pkcs12_file    server_key_from_pkcs12_file  server.pem  server.pkcs12
 
 
When prompted for password enter the same passphrase given during the creation of pkcs12 file. -clcerts option tells to output only client certificates. -nokeys option tells not to output any private keys. By default the certficate will be created in PEM format.
 
Separating private key from pkcs12 file.
 
#> openssl pkcs12 -in server.pkcs12 -nocerts -out server_key_from_pkcs12_file -nodes
Enter Import Password:
MAC verified OK
 
# >ls
server_cert_from_pkcs12_file    server_key_from_pkcs12_file  server.pem  server.pkcs12