Sunday, September 20, 2015

Redirection of IO stream of C++

Sometimes, for programs written in C++, at the development stage, it's probably convenient to output the diagnosis information directly to console. And upon release, by the virtue of Macro, the diagnosis information can be eliminated. However for some daemon program, probably it still needs to output something if something wrong occurs. However simply turning on the Macro might not work since the TTY has been detached from standard output terminal or stand error terminal. The following are piece of work which can direct the IO stream from terminal to files. Hope it will be helpful under some occasion.


#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <string>
#include <sstream>
#include <iostream>

using namespace std;

class MyLog
{
public:
    MyLog(char* path)
    {
        m_fp = fopen(path, "w");
    }
    ~MyLog()
    {        
        if (m_fp)
        {
            fclose(m_fp);
        }
    }

    void operator() (const string& s)
    {
        if (m_fp)
        {
            fprintf(m_fp, "%s\n", s.c_str());
            fflush(m_fp);
        }
    }

    void operator() (const char* fmt, ...)
    {
        if (m_fp)
        {
            char buf[256];
            va_list ap;

            memset(buf, 0, sizeof(buf));

            va_start(ap, fmt);
            buf[vsnprintf(buf, sizeof(buf), fmt, ap)] = '\0';
            va_end(ap);

            fputs(buf, m_fp);
            fflush(m_fp);
        }
    }
    
private:
    FILE* m_fp;
};

MyLog myLog("/opt/test.txt");

class Redirect
{
public:
    Redirect(MyLog& log) : m_log(log), m_oldCoutStreamBuf(cout.rdbuf())
    {
        cout.rdbuf(m_strCout.rdbuf());
    }
    ~Redirect()
    {
        m_log(m_strCout.str());
        cout.rdbuf(m_oldCoutStreamBuf);    
    }

private:
    MyLog& m_log;
    streambuf* m_oldCoutStreamBuf;
    ostringstream m_strCout;
};

void func1()
{
    Redirect r(myLog);
    cout << "in func1!" << endl;
}

void func2()
{
    Redirect r(myLog);
    cout << "in func2!" << endl;
    func1();
}

int main(int argc, char* argv[])
{
    Redirect* p = new Redirect(myLog);
    cout << "in main!" << endl;
    func2();
    delete p;
    cout << "You should see this!" << endl;
    return 0;
}

  

Utilize Python to control GDB

There's a good article details how to control GDB via Python instead of GDB script, please refer: http://www.linuxjournal.com/article/11027.

However due to time evolves, the Python scripts seems to stop working. The following is a modified one to compatible with the example giving in the article.


#!/usr/local/bin/python
from collections import defaultdict
# A dictionary of mutex:owner
mutexOwners = {}
# A dictionary of blocking mutex:(threads..)
threadBlockers = defaultdict(list)
# Print the threads
#print "Process threads : "
#gdb.execute("info threads")
print "Analysing mutexes..."
# Step through processes running under gdb
def get_frame(hint):
    
    frame = gdb.selected_frame()

    if hint == None:
        return frame
    elif type(hint) == int:
        i = 0
        while i < hint and frame != None:
            pre_frame = frame.older()
            if frame == pre_frame and frame < hint - 1:
                frame = None
                break
            else:
                frame = new_frame
            i += 1
    elif type(hint) == str:
        while frame != None:
            pre_frame = frame.older()
            if frame.name() == hint or pre_frame == frame:
                break
            else:
                frame = pre_frame
    return frame

for process in gdb.inferiors():

    # Step through each thread in the process
    for thread in process.threads():

        # Examine the thread -- is it blocking on a mutex?
        thread.switch()
        frame = get_frame("pthread_mutex_lock")
        
        if frame != None:
            frame.select()

            # Make a note of which thread blocks on which mutex
            mutex = int(gdb.parse_and_eval("$r8"))
            threadBlockers[mutex].append(thread.ptid[0])

            # Make a note of which thread owns this mutex
            if not mutex in mutexOwners:
                v = gdb.parse_and_eval("*$r8").cast(gdb.lookup_type("pthread_mutex_t"))
                mutexOwners[mutex] = v['__data']['__owner']

    # Print the results of the analysis
    for mutex in mutexOwners:
        print "  Mutex 0x%x :" % mutex
        print "     -> held by thread : %d" % mutexOwners[mutex]
        s = ["%d" % t for t in threadBlockers[mutex]]
        print "     -> blocks threads : %s" % ' '.join(s)

Wednesday, July 29, 2015

How to generate certificate on Fedora



One should have a basic understanding of asymmetric encryption, and PKI based on it.

So the first step is to generate a private key:
openssl genrsa -out fd.key 2048
One can examine the content by cat command

One can generate the corresponding public key for playing:
openssl rsa -in fd.key -pubout -out fd-public.key

Now we want create a self-signed certificate, so first we create the request:
openssl req -new -key fd.key -out fd.csr
Now let’s check the content of the file:
openssl req -text -in fd.csr –noout

Since we want to use the self-signed certificate to sign other certificate, so we add more attribute:
echo “basicConstraints = CA:true” > fd.ext

Now let’s sign the certificate:
openssl x509 -req -days 365 -in fd.csr -signkey fd.key -out fd.crt -extfile fd.ext
Now let’s examine the certificate:
openssl x509 -text -in fd.crt –noout

Up to now, we have a working certificate: fd.crt

We will treat it as a root CA, avoiding directly use it. So let’s advance to create extra certificate, well, for some service.

The first step is obviously to create the key:
openssl genrsa -out test.key 2048

Now generate the request:
openssl req -new -key test.key -out test.csr

For signing with the previous certificate fd.crt to work, we need another file:
echo 00 > fd.srl

Now to sign it:
openssl x509 -req -days 365 -in test.csr -CA fd.crt -CAkey fd.key -out test.crt

We can examine the content of the new generate certificate test.crt:
openssl x509 -text -in test.crt –noout
End of the story.