Saturday, September 22, 2012

Message-based Client-Server



Server


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/msg.h>
#include "msgdefs.h"


#define OK      0
#define LOG_ERROR(msg) { printf("%s:%u: %s %s\n", \
                __FUNCTION__, __LINE__, msg, \
                strerror(errno)); }
int msgQueue; 


int CreateMsgQueue(long id)
{
    int msgId;
    key_t key;
    struct msqid_ds ds;

    key = ftok("msgserv.c", id);
    msgId = msgget(key, 0644 | IPC_CREAT);
    if (msgId < 0)
    {
        LOG_ERROR("msgget");
    }
    if (EEXIST == errno)
    {
        // reuse
        msgctl(msgId, IPC_STAT, &ds);
        key = ftok("msgserv.key", id);
        msgId = msgget(key, 0777 | IPC_SET);
    }
    return msgId;
}


int SendMsg(void *msg, size_t msgsz, int msgflg)
{
    Msg_t *pMsg;
    char *pData;
    int retval = 0;
    
    pMsg = malloc(sizeof(Msg_t) + msgsz);
    pMsg->hdr.msgType = 1;
    pMsg->hdr.dataSize = msgsz;
    pData = (char*)(&pMsg->data[0]);
    memcpy(pData, msg, msgsz);
    retval = msgsnd(msgQueue, pMsg, msgsz, msgflg);
    free(pMsg);
  
    return retval;
}


void *SendMsgTask(void *arg)
{
    Msg_t msg;
    long tick = 0;

    if (arg)
   printf("This is task %d\n", *(int *) arg);
    else
    printf("This is task\n");
#if 1
    do {
        // send msg
        printf("Sending tick=%lu\n", tick);
        if (OK != SendMsg(&tick, sizeof(tick), 0))
        {
            LOG_ERROR("SendMsg failed");
        }
        tick++;
        usleep(500000);
        //sleep(1);
    } while (tick < 50);
    //send quit
    msg.hdr.msgType = 2;
    msgsnd(msgQueue, &msg, sizeof(msg), 0);
    return NULL;
#endif
}




int main()
{
    int retval;
    pthread_t SendMsgTaskId;
    pthread_attr_t attr;

    pthread_attr_init(&attr);
    msgQueue = CreateMsgQueue(MESSAGE1);
    if (msgQueue > 0) {
        printf("Start the thread..\n");
        retval = pthread_create(&SendMsgTaskId, &attr, SendMsgTask, NULL);
        if (OK == retval)
            pthread_join(SendMsgTaskId, NULL);
    }
    else {
        LOG_ERROR("CreateMsgQueue");
    }
    if (OK != msgctl(msgQueue, IPC_RMID, NULL))
    {
        LOG_ERROR("msgctl");
        exit(1);
    }
    pthread_attr_destroy(&attr);
    return 0;
}




Client



#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/msg.h>
#include "msgdefs.h"


#define OK      0
#define LOG_ERROR(msg) { printf("%s:%u: %s %s\n", \
                __FUNCTION__, __LINE__, msg, \
                strerror(errno)); }
int msgQueue; 


int InitMsgQueue(long id)
{
    int msgId;
    key_t key;

    key = ftok("msgserv.c", id);
    msgId = msgget(key, 0644);
    if (OK != msgId)
    {
        LOG_ERROR("msgget");
    }
    return msgId;
}


int ReceiveMsg(Msg_t **pMsg, size_t *msgsz)
{
    int sz;

    int retval = 0;
    
    sz = 256;
    *pMsg = malloc(sizeof(Msg_t) + sz);
    retval = msgrcv(msgQueue, *pMsg, sz, 0, 0);
    *msgsz = sz;
    return retval;
}


void *ReceiveMsgTask(void *arg)
{
    Msg_t *pMsg;
    size_t sz;

    if (arg)
   printf("This is task %d\n", *(int *) arg);
    else
    printf("This is task\n");

    for(;;) {
        // rcv msg
        if (ReceiveMsg(&pMsg, &sz) < 0)
        {
            LOG_ERROR("ReceiveMsg");
            return NULL;
        } 
        else {
            printf("MsgType = %lu\n", pMsg->hdr.msgType);
            switch (pMsg->hdr.msgType) {
                case 1:
                    printf("Received sz=%u, tick=%lu\n", 
                            pMsg->hdr.dataSize,
                            *(long*)(&pMsg->data[0]));
                    break;
                default:
                    printf("End of task\n");
                    free(pMsg);
                    return NULL;
            }

        }
        // msg must be freed
        free(pMsg);
    } 
    return NULL;
}




int main()
{
    int retval;
    pthread_t ReceiveMsgTaskId;
    pthread_attr_t attr;

    pthread_attr_init(&attr);
    msgQueue = InitMsgQueue(MESSAGE1);
    if (msgQueue > 0) {
        printf("Start the thread..\n");
        retval = pthread_create(&ReceiveMsgTaskId, &attr, ReceiveMsgTask, NULL);
        if (OK == retval)
            pthread_join(ReceiveMsgTaskId, NULL);
    }
    else {
        LOG_ERROR("InitMsgQueue");
    }
    pthread_attr_destroy(&attr);
    return 0;
}



msgdefs.h

#ifndef __MSGDEFS_H__
#define __MSGDEFS_H__


enum {
    MESSAGE1 = 0x10000000
};

#define MSG_DATA_SIZE       1024

typedef struct {
    long msgType;
    unsigned int dataSize;
} MsgHdr_t;

typedef struct {
    MsgHdr_t hdr; /* our header */
    char data[0];   // just a place holder
} Msg_t;


#endif


Sunday, September 16, 2012

Ripping VCD to Various Formats


Using VCDXRIP

To convert to MPEG:

$ vcdxrip


USING MENCODER

mencoder [options] file [file|URL|-] [-o file | file://file | smb://[user:pass@]host/filepath]

mencoder vcd//:2 -oac lavc -ovc lavc -o filename.avi 

($ sign is the terminal prompt)


                 -oac lavc
                      Encode with a libavcodec codec

                 -ovc lavc
                      Encode with a libavcodec codec.




Using CDFS

The source can be downloaded here:

http://users.elis.ugent.be/~mronsse/cdfs/download/

(Unfortunately, the driver doesn't yet support later Linux versions).

$ mount -t cdfs -o ro /dev/cdrom /mnt/video

And copy the *.DAT files



FFMPEG

FFMPEG is a very powerful tool (command-line) to transcode media file.

For example, to extract audio from an AVI file:

$ ffmeg -i source_video.avi -vn -ar 44100 -ac 2 192 -f mp3 sound.mp3

To convert MPG to AVI (or vise-versa):

$ ffmeg -i video_original.mpg output.avi

To encode WAV to mp3:

$ ffmpeg -i video.wav -vn -ar 44100 -ac 2 -ab 192 -f mp3 song.mp3


To mix a WAV file with a video file:

$ ffmpeg -i audio.wav -i video.avi audio_video.avi

To convert AVI to MPEG suitable for DVD:

ffmpeg -i source_video.avi -target pal-dvd -ps 2000000000 -aspect 16:9 finale_video.mpeg 


AVI to VCD:

$ ffmpeg -i video.avi -target ntsc-vcd video_out.mpg

To use 2-pass encoding, pass "-pass 2 -passlogfile somefile" before output file.

HandBrake


We then can use Handbrake to transcode video from CD/DVD to various formats, especially for Apple products.
There are two versions of HandBrake, one is the GUI front-end, and the CLI version.


To list the built-in presets:

$ HandBrakeCLI -z

To use the preset, use capital "-Z"
For example:

$HandBrakeCLI -Z "iPhone 4" -i avseq0.avi -o output.mp4



Tuesday, September 11, 2012

Script to convert series of WAV files

Assume there are wav files named as "disc_1.wav", "disc_2.wav" so on.
There is also a cover file (a JPEG format file) to be used as cover album embedded into each encoded MP3 file.

If we want to convert them all into MP3:



#!/bin/sh

ARTIST="Hamza Yusuf"
ALB="The Rights and Responsibilities of Marriage"
TY="2002"
GENRE="Vocal"
for i in `ls disc_*.wav | sort -V` ;
do
    TN=`echo $i | awk 'BEGIN { FPAT="[[:digit:]]+"} ; {  print $1 }'`
    lame --ti "./the_rights_and_responsibilities_of_marriage.jpg" --tt "$ALB cd$TN" --ta "$ARTIST" --tl i"$ALB" --ty "$TY" --tn "$TN/13" --tg "$GENRE" $i "$ALB cd${TN}.mp3"

done

Sunday, September 9, 2012

Youtube Video to MP3


  1. Download script youtube-dl from  http://rg3.github.com/youtube-dl/
  2. Make sure we have ffmpeg installed
  3. Write a small script with content as below:

youtube-dl --extract-audio --audio-format mp3 -v -t "$1"

For example, to download and extract the audio and save it as MP3 (assuming the small script above has been saved as utube":

utube http://www.youtube.com/watch?v=RoqRbe3dgwU&feature=g-vrec

Post-processing:

concatenate multiple MP3 files to become one mp3:

mp3wrap <file1> <file2> ... <output>

To downmix the result file to a mono-aural:

lame -m s -a <file> <downmix.mp3>


to copy the ID3 data from the original file to the output file

id3cp <mp3 source> <mp3 dest>





Saturday, June 23, 2012

How to set root password on ReadyNAS

Recently I had forgotten my ReadyNAS password.  Even worse, I couldn't login at all due reckless upgrade I did on the box.  I was able to undo the upgrade by letting the box recopy the Linux from its firmware to the drive (see ReadyNAS forum/documentation on how to make the ReadyNAS box recopy the firmware), but still I forgot what my root password was.

Various steps I had tried as I found on the Internet as well as on the ReadyNAS website, but none of them work. Finally, I had an idea to just access the drive directly thru SATA-to-USB cable and reset the password manually.

Basically what I did was to set the root password stored in the file /etc/passwd (fortunately the authententication is still the old-fashioned one, where the MD5 encrypted password stored directly in the file instead in shadow file).

You might ask, "How the hell I access the drive?".  Well, first you need remove the drive from the ReadyNAS bay (make sure it is turned off!!) then  attach the SATA-to-USB cable to the drive.  Connect the usb end to our PC.

We cannot mount directly to the drive, because some other issues.  To mount, see my previous post ("How to mount disk used by ReadyNAS").  Once it is  mounted (just mount the ext3 partition [first partition], no need to mount the LVM), we can now modify the file /etc/passwd.

First, save the following script (thanks to somebody who posted it on the Internet), say, as /home/<yourloginname>/bin/setpasswd:


#!/usr/bin/perl
################################################################################
# Generate an MD5 hash for a string.
# Created to allow me to set a blank Linux password. Required this to create
# multiple VsFTP accounts with anonymous style credientials.
#
# If all you want is the MD5 Hash for NULL (blank password) here's one...
# $1$VNMbpxGH$sew7cnwH9ixU.x27UbFNn.
#
# Advice: If replacing a Linux password with a blank string, ensure you give 
# the user a shell of /sbin/nologin as you wouldn't want them to login!
################################################################################
# Load dependancies...
# perl -MCPAN -e 'install Crypt::PasswdMD5'
################################################################################

use strict;
use Crypt::PasswdMD5 qw(unix_md5_crypt);
my @salt = ( '.', '/', 0 .. 9, 'A' .. 'Z', 'a' .. 'z' );
my %encrypted;


sub abort {
print "ABORT: $_[0]\n";
exit 1
}


sub gensalt { #------------------------------------------------------------
# uses global @salt to construct salt string of requested length
my $count = shift;

my $salt;
for (1..$count) {
$salt .= (@salt)[rand @salt];
}

return $salt;
} # end gensalt


sub get_encryptedpw { #--------------------------------------------------
my $unencrypted="$_[0]";

# generate traditional (weak!) DES password, and more modern md5
$encrypted{des} = crypt( $unencrypted, gensalt(2) );
$encrypted{md5} = unix_md5_crypt( $unencrypted, gensalt(8) );

return %encrypted;
}

################################################################################
print "Enter password string to encrypt (can be blank) : ";
my $password = <STDIN>;
chomp $password;

get_encryptedpw($password);

print "Plaintext \"$password\" = MD5 Hash: $encrypted{md5}\n";
print "\nReplace the /etc/shadow password string with the above to force pass change\n";


(Don't forget to make it executable by doing "chmod +x ./setpasswd)
Run the script.  It will ask you to enter a password.  An example of the output (with blank password):


$ setpasswd
Enter password string to encrypt (can be blank) : 
Plaintext "" = MD5 Hash: $1$udf2EDLY$a/cLQQ4h25rwZQc9VKmG6/

Replace the /etc/shadow password string with the above to force pass change

Copy the portion after the string "MD5 Hash: " above and paste it in the <READYNAS MOUNTPOINT>/etc/passwd.  To be precise, it should be pasted in line where "root:...". Paste it right after "root:", and let the rest of the existing text still intact.

Save the file, unmount (just use the regular umount for this one), reinsert the drive into the ReadyNAS bay and turn it on.  Once it is running, try to SSH to the box as root and enter the new password.  It should work!


Sunday, March 25, 2012

Undirected Graph

The following small program illustrate how to implement a undirected graph with costs to neighbor nodes.


#ifndef _GRAPH_HPP_
#define _GRAPH_HPP_

#include <iostream>
#include <map>
#include <list>

using namespace std;

/*
 * Undirected graph class
 */
class Graph {
public:
 Graph(unsigned int id=0) { m_id = id; m_Ecount = 0; }
 virtual ~Graph();
 void SetId(unsigned int id) { m_id = id; }
 bool Match(Graph& g);
 bool AddAdjacent(Graph* g, int cost=0);
 bool AddAdjacentOne(Graph *g);
 list GetAdjacents() { return m_Adjacents; }
 
 int GetVCount() { return m_Adjacents.size(); }
 int GetECount() { return m_Ecount; }
 unsigned int GetId() { return m_id; }
 void SetCostTo(Graph *g, int cost);
 int GetCostTo(Graph* g);
 
 private:
 unsigned int m_id;
 int m_Ecount;
 map<Graph*,int> m_cost;
 list<Graph*> m_Adjacents;
};


#endif




graph.pp:

#include "graph.hpp"

using namespace std;

Graph::~Graph()
{
 // TODO:
 m_Adjacents.clear();
}


bool Graph::Match(Graph& g)
{
 cout << "this=" << this << endl;
 cout << "&g =" << &g << endl;
 if ((this == &g) || (g.GetId() == this->GetId()) &&
  (g.GetECount() == this->GetECount()) &&
  (g.GetVCount() == this->GetVCount()) )
  return true;
 return false;
}

bool Graph::AddAdjacentOne(Graph *g)
{
 m_Adjacents.push_back(g);
 //TODO: we need to tell g to add also edge to this object
 m_Ecount++;
 return true;
}


void Graph::SetCostTo(Graph *g, int cost)
{
 if (g == NULL)
  return;
 // Use hash-table to set the cost from this node to g
 m_cost[g] = cost;
}

int Graph::GetCostTo(Graph *g)
{
 if (g == NULL)
  return -1;
 // use hash-table to get the cost from this node to g
 return m_cost[g];
}

bool Graph::AddAdjacent(Graph* g, int cost)
{
 if (!g) return false;

 if (Match(*g))
 {
  cout << "ERROR: Tried to add itself" << endl;
  return false;
 }
 else {
  AddAdjacentOne(g);
  // tell other node to set its adjacent to this node too
  g->AddAdjacentOne(this);
  // add cost from this object to g
  g->SetCostTo(this, cost);
  SetCostTo(g, cost);
  return true;
 }
}



int main()
{
 Graph g[10];
 int i;
 int numOfVertices = 4;

 for(i=0; i<numOfVertices; i++)
  g[i].SetId(i);

 // g0 --- g1
 g[0].AddAdjacent(&g[1]);
 //g1 --- g2
 g[1].AddAdjacent(&g[2]);
 // g2 --- g3
 g[2].AddAdjacent(&g[3]);
 // g3 --- g0
 g[3].AddAdjacent(&g[0]);
 // g0 -- g2
 g[0].AddAdjacent(&g[2], 5);

 list<Graph*>::iterator it;
 list<Graph*> adjacents;

 for(i=0; i<numOfVertices; i++)
 {
  cout << "NODE g[" << i << "]" << endl;
  cout << "\tNumber of Edges in G[" << i << "] = " << g[i].GetECount() << endl;

  adjacents = g[i].GetAdjacents();
  cout << "\tNeighbors:" << endl;
  for ( it=adjacents.begin() ; it != adjacents.end(); it++ )
   cout << "\t\tNode=" << *it << ", g[" << (*it)->GetId() << "], cost="
     << g[i].GetCostTo(*it) << endl;
 }
}