Saturday, January 28, 2012

My ISP finally happy with Ubuntu box


I was struggling to make my Ubuntu box work with login server of ISP. It was not getting better at all. Sometimes after 50 attempts, ISP used to say yes and login window appeared. However I was totally annoyed by this. When I switch back to Windows, everything was fine. I started digging to the problem myself rather than asking ISP itself (just for fun and learning).

1)      ISP provides a cable modem and recognizes the packets by MAC address of cable modem.
2)      I have a wireless router attached to my laptop.
3)      The WAN cable of modem is connected to wireless router.
4)      All my connections go via wireless router to cable modem to ISP Internet gateway.
5)      Wireless router has DHCP server to provide IP address to locally connected hosts.
6)      Of-course it acts like a NAT and router, in the sense you can have multiple hosts connecting to wireless router (not sure about limit).

The network setup is something like this:

NETWORK-SETUP
Let me come back to the problem of login server not responding. I struggled a lot. I thought the problem with wireless router and ISP may not be accepting the MAC other than my PC. No I was wrong, in windows everything was clean. Next, I pulled out wireless router and directly cabled modem to my PC. Again did not work out. I used to login from windows and work with Ubuntu for my net access. This was successful since login information was maintained in ISP side than locally in the system.

After so much of struggle, I decided to take packet captures of both windows and Ubuntu. I observed Ethernet packets and IP packets and they looked similar. Finally I gazed through TCP packets.

Aha here you are! Linux adds all TCP options to TCP packet while windows adds few. I knew this was problem but which options? I started disabling one by one

sudo sysctl net.ipv4.tcp_sack=0

This did not work

sudo sysctl net.ipv4.tcp_window_scaling=0

Na this did not work. I thought my assumption was wrong. I decided to give final try

sudo sysctl net.ipv4.tcp_timestamps=0

Hurrah!!! It worked out. I was really delighted. I updated the /etc/sysctl.conf and never faced the problem again.

So it is basically problem with tcp timestamp option which linux kernel includes by default. I really did not understand why this would give a problem. TCP timestamp just sends current clock of the system to avoid packets being recognized as duplicate during sequence number overflow. However they need not even synchronize with system clock. I raised this issue with ISP and let me see what happens further.

At the end of day, one more piece of learning and one more topic to write about ;). I just loved the investigations I carried out. It may be very silly problem to experts however for me it was seamless learning.

Here is the TCP packet capture of windows and linux. It shows Windows does not add TCP timestamp field in TCP packet during SYN state.



Courtesy: wireshark

Tuesday, January 24, 2012

A simple player simulation using pthreads

When I was playing VLC, just wondering how pause, play and resume works. I decided to simulate one using pthreads. This is just done for fun nothing official. So I used the wait and resume calls of pthreads.

1) pthread_cond_wait()
2) pthread_cond_signal()

Using above two POSIX calls I did a simulation of player pause and resume. It worked as expected. So it was done as below

1) Player is executed as a separate thread
2) Button simulation done using command line in main thread.
3) When pause is opted, pthread_cond_wait() is called to make thread wait.
4) When resume is opted, pthread_cond_signal() is called to wake up the waiting thread.

As far as wake up is concerned, there is one more variant pthread_cond_broadcast() which wakes up all threads waiting on condition variable. Please refer man pages to know detailed usage of pthread calls. Not sure about internals may be the futex is released atomically and wakeup** is called for this task (again not sure)

Here is C code, not completely tested however giving what is required. Suggestions and further improvements are always welcome.

#include<stdio.h>
#include<unistd.h>
#include<termios.h>
#include<stdlib.h>
#include<pthread.h>

typedef enum {
    PLAY,
    PAUSE,
    STOP,
}player_state;

struct player {
    pthread_mutex_t player_mutex;
    pthread_cond_t player_cond;
    pthread_t player_tid;
    player_state player_s;
};

static void init_player(struct player *__arg);
static void print_player_menu(void);
static int start_player(struct player *__arg);
static int pause_player(struct player *__arg);
static int resume_player(struct player * __arg, const player_state player_s);
static int stop_player(struct player *__arg);
static char read_char(void);
void* start_player_thread(void *__arg);

int main()
{
    struct player bazooka_player;
    init_player(&bazooka_player);
    print_player_menu();

    while (1) {
        char c = read_char();

        switch (c) {
            case 'S':
            case 's':
                if (bazooka_player.player_s == STOP) {
                    start_player(&bazooka_player);
                } else {
                    printf("Invalid State to call player start\n");
                }
                break;

            case 'P':
            case 'p':
                if (bazooka_player.player_s == PLAY) {
                    pause_player(&bazooka_player);
                } else {
                    printf("Invalid State to call player pause\n");
                }
                break;

            case 'R':
            case 'r':
                if (bazooka_player.player_s == PAUSE) {
                    resume_player(&bazooka_player, PLAY);
                } else {
                    printf("Invalid State to call player resume\n");
                }
                break;

            case 'Q':
            case 'q':
                stop_player(&bazooka_player);
                exit(EXIT_SUCCESS); //Any better way?
                break;

            default:
                printf("Invalid player option\n");
                break;
        }
    }
}

static void init_player(struct player *__arg)
{
    /*
     * Make sure you do proper initialization
     * Otherwise pthread_cond_signal() would result in deadlock
     */
    __arg->player_s = STOP;
    __arg->player_tid = -1;
    pthread_cond_init(&__arg->player_cond, NULL);
    pthread_mutex_init(&__arg->player_mutex, NULL);
}

static char read_char(void)
{
    /*
     * This is taken from net.
     * It basically turns of echo for the current terminal.
     * Takes single character without expecting new line.
     * Restores old tty settings.
     * returns character.
     */
    char c;
    struct termios old_term, new_term;
    tcgetattr(STDIN_FILENO, &old_term);
    new_term = old_term;
    new_term.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &new_term);
    c = getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &old_term);
    return c;
}

static void print_player_menu(void)
{
    printf("PLAYER OPTIONS\n");
    printf("S or s: Start play\n");
    printf("P or p: Pause play\n");
    printf("R or r: Resume play\n");
    printf("Q or q: Stop play\n");
}

static int start_player(struct player *__arg)
{
    /*
     * This could get racy if we set state to PLAY after pthread_create().
     * Do we need explicit memory barrier in multi-core platform?
     * smp_wmb()? Not sure :-)
     */
    __arg->player_s = PLAY;
    return pthread_create(&__arg->player_tid, NULL, start_player_thread, __arg);
}

static int pause_player(struct player *__arg)
{
    __arg->player_s = PAUSE;
}

static int resume_player(struct player *__arg, const player_state player_s)
{
    printf("Preparing to resume\n");
    __arg->player_s = player_s;
    /*
     * Again Do we need smp_wmb()?
     */
    return pthread_cond_signal(&__arg->player_cond);
}

static int stop_player(struct player *__arg)
{
    /*
     * This may hang the thread if the player is paused.
     * We will have to explicitly do signal in case, player is paused
    */

    if (__arg->player_s == PAUSE) {
        resume_player(__arg, STOP);
    } else {
        __arg->player_s = STOP;
    }

    return ((__arg->player_tid == -1)?0:pthread_join(__arg->player_tid, NULL));
}

void* start_player_thread(void* __arg)
{
    struct player* pl_s = (struct player*) __arg;
    while (1) {
        switch (pl_s->player_s) {
            case PLAY:
                printf("playing the song :-)\n");
                sleep(1); //Not sure how much safe to call this inside a thread
            break;

            case PAUSE:
                printf("preparing to pause :-)\n");
                pthread_mutex_lock(&pl_s->player_mutex);
                pthread_cond_wait(&pl_s->player_cond, &pl_s->player_mutex);
                pthread_mutex_unlock(&pl_s->player_mutex);
            break;

            case STOP:
                printf("good bye! Hope you enjoyed it :-)\n");
                pthread_exit(NULL);
            break;   
        }
    }
}


Compile with: gcc -o <binary_name> <saved_c_file> -lpthread
Execute with: ./<binary_name> and test output

Monday, January 16, 2012

The VirtualBox 4.1.8

The new version of virtual box seems to have improvements on the native graphic resolution. My guest OS screen now fits into entire screen of host OS rather than it was limited to a specific area in earlier versions. This was happening even if  guest add-ons were installed. The problem seems to have gone by now. Now I am getting real feeling of linux box on vista without installation of guest additions. I recently installed OpenSUSE 12.1 32 bit edition with XFCE desktop as guest on top of Vista and looks magnificent. Here are some screen shots

FULL SCREEN OPENSUSE 12.1

OPENSUSE 12.1 ON WINDOWS VISTA
That really looks nice. Of-course this was only for experiment. Personally I use linux installed onto the hardware system :-).

Saturday, December 10, 2011

Use of '!!' (double negation) in C programming

In some of the 'C' codes, I saw use of '!!' in expressions. I was just wondering about use of such a redundant operation (since '!!' negated the negation).
In one of the mails in LKML (Linux Kernel Mailing List), I came to know about its significance. The '!!' is used to convert an expression to authentic boolean value.

For example:

int a = 0xFF;
if (!!(a & 0x0F))
    //do something
else
    //do some other thing

Here (a & 0x0F) resolves to '0x0F' while !!(a & 0x0F) resolves to '1'.
That means use of '!!' results in authentic boolean value i.e. either '0' or '1'.

We can see the same kind of expressions in linux kernel code.

#define likely(exp) __builtin_expect(!!(exp), 1)
#define unlikely(exp) __builtin_expect(!!(exp), 0)

In the first case, the expression has to evaluate to any value other than '0' for likely condition to happen. However, may be to reduce side effects or maintain consistency, the precaution would have been taken and expression is converted to authentic boolean value.

It seems redundant for the unlikely condition though.

Please share if you have any alternate thoughts.

Tuesday, December 6, 2011

Setting up wireless router in opensuse linux 12.1 box

It is just continuation of what I scribbled sometimes back regarding 11.4. The steps and interfaces are still the same.

However there is good news. You need not add routes manually. Everything is automated now. Good work by SUSE team. I tried with openSUSE 12.1 x86_64. When the wlan interface comes up, the routes get automatically added with wireless router IP as default gateway. May be I feel it was bug in openSUSE 11.4 however everything is fine now.

Monday, October 17, 2011

Importance of 'typedef'ing

Some people ask me why do we need to typedef some datatypes. This is basically to maintain portability across compilers.

We put all typedefs in a single header file. When porting across compilers if any datatype related problem arrives, it is required to change only the header file. So we have single place changes rather than refactoring the entire code which would have been cumbersome.

For ex:

Assume a legacy code like this. In "C" we did not have bool until C99. The older code may look like this

typedef enum __BOOL__ { FALSE, TRUE }BOOL;

and wherever we need to use it we apply as "BOOL var = TRUE" etc..

gcc allows _Bool by default nowadays. So above code can be easily ported to _Bool. Here it goes.

typedef _Bool BOOL;
#define FALSE 0
#define TRUE 1

Bingo!! In a single place we did the modification and entire modification has same effect as earlier. The modification applies to all places without any changes to existing BOOL types.

Note that without 'typedef'ing enum __BOOL__ to BOOL, it would have been difficult to make changes at one shot (because of enum __BOOL__ declaration).

There may be lot other advantages. If someone reading the blog, comment on the same if you have more suggestions.

Friday, September 23, 2011

Setting up wireless router in opensuse linux 11.4 box

I have a DELL inspiron Laptop with default Windows-Vista as OS. I installed OpenSUSE 11.4 on a different partition. It is easy to setup anything in Win-Vista. However its quite challenging to setup in Linux box. It is very interesting and helpful if you are learning linux.

I have broadband cable connection whose ethernet cable pin was broken. Even I wanted to browse from anywhere in house. So one of my friend suggested to buy a wireless router through which I can achieve flexibility in Internet browsing.

I bought a wireless router from ebay site costing around 1k. It arrived 2 days after the order was placed. Initially we need to connect the output of cable modem to the Internet port of Wireless router. We can connect upto 4 ethernet cables (standalone; however can be increased using switch or hub). Once booted various LED indicators are present to show progress of router. The router is also linux based. It has embedded HTTP, DNS and SCCP server. The nmap output says it.

nandakumar@linux:~> sudo nmap -sT -O 192.168.11.0/24

root's password:

Starting Nmap 5.21 ( http://nmap.org ) at 2011-09-04 15:39 IST

Nmap scan report for 192.168.11.1

Host is up (0.0071s latency).

Not shown: 996 closed ports

PORT STATE SERVICE

53/tcp open domain

80/tcp open http

2000/tcp open cisco-sccp

49152/tcp open unknown

MAC Address: 4C:E6:76:4D:F6:90 (Unknown)

Device type: general purpose

Running: Linux 2.6.X

OS details: Linux 2.6.15 - 2.6.27

Network Distance: 1 hop

By default router has static IP of 192.168.11.1. It assigns the LAN members with IP with network-id 192.168.11.0.

(Caution: Please do not use nmap scan in WAN/(organisation LAN) environment. It is not legal in INDIA. I ran the command since it was in my own LAN environment.)

Setting up Wireless:

Before nmap or any other things can be done, we need to setup wireless network in the linux-box. The default wireless modules do not work properly or do not work. We need to obtain the vendor specific driver of our system and compile the code against native kernel and deploy it. In my case the wireless hardware was from broadcom corporation.

nandakumar@linux:~> /sbin/lspci

00:00.0 Host bridge: Intel Corporation Mobile 4 Series Chipset Memory Controller Hub (rev 07)

00:02.0 VGA compatible controller: Intel Corporation Mobile 4 Series Chipset Integrated Graphics Controller (rev 07)

00:02.1 Display controller: Intel Corporation Mobile 4 Series Chipset Integrated Graphics Controller (rev 07)

00:1a.0 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #4 (rev 03)

00:1a.1 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #5 (rev 03)

00:1a.2 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #6 (rev 03)

00:1a.7 USB Controller: Intel Corporation 82801I (ICH9 Family) USB2 EHCI Controller #2 (rev 03)

00:1b.0 Audio device: Intel Corporation 82801I (ICH9 Family) HD Audio Controller (rev 03)

00:1c.0 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 1 (rev 03)

00:1c.1 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 2 (rev 03)

00:1c.2 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 3 (rev 03)

00:1c.4 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 5 (rev 03)

00:1d.0 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #1 (rev 03)

00:1d.1 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #2 (rev 03)

00:1d.2 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #3 (rev 03)

00:1d.7 USB Controller: Intel Corporation 82801I (ICH9 Family) USB2 EHCI Controller #1 (rev 03)

00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev 93)

00:1f.0 ISA bridge: Intel Corporation ICH9M LPC Interface Controller (rev 03)

00:1f.2 SATA controller: Intel Corporation ICH9M/M-E SATA AHCI Controller (rev 03)

00:1f.3 SMBus: Intel Corporation 82801I (ICH9 Family) SMBus Controller (rev 03)

09:00.0 Ethernet controller: Marvell Technology Group Ltd. 88E8040 PCI-E Fast Ethernet Controller (rev 13)

0c:00.0 Network controller: Broadcom Corporation BCM4312 802.11b/g LP-PHY (rev 01)

In my case it is BCM4312. Visit broadcom site and download the appropriate driver (32 or 64 bit depending on OS build version) for BCM4312 and compile against kernel. The README gives complete steps on how to patch, compile and deploy wireless module.

Once the wireless module successfully deployed, the NetworkManager shows up the new interface that is detected. I have disabled NetworkManager and used traditional ifup method. Once setup, goto

Yast->Network Devices->Network Settings

In the Overview Tab, select the interface which is wireless and click Edit.

Under Address TAB, configure interface to obtain address from DHCP. This option provides IP for the interface from wireless router. Once this is done, the wireless interface gets IP from router. Then connect to the router with router IP (in my case 192.168.11.1) and configure router. For increased security, disable SSID broadcast and enable WPA encryption with AES algorithm and provide strong password. Make sure you change password at-least once in a month. Disabling SSID broadcast ensures that your router is not visible outside including to your laptop.

(Note: initially router will not have any security enabled and you can configure as it is i.e. system will be able to scan the wireless network successfully. However, the configuration of router is for tight security. You may skip the configuration section if you do not wish to have security however it is not recommended)

Once router setup is done, we need to get into the network device setup in YAST. Now after the DHCP settings which was done earlier, click next to setup the wireless Network. Here enter the SSID of your router (It will be either MAC or custom as configured by you in router web page). Enter security type of your router and the password for the router and click Next and then OK. Now the setup is done for your router and you are ready to connect to internet.

Now there is a problem. The Internet is in WAN environment and we are in LAN environment. The wireless router does everything for us to connect to internet. But how will linux machine identify that whatever is IP has to connect? For name resolution, router has DNS server however, once IP is obtained, the linux box will not have any idea where to connect for that IP.

To resolve the problem, we need to manually add route to the linux routing table. This is one of the drawback of linux system. We can do this by adding routing table entry manually to connect to internet.

sudo route add -net 0.0.0.0 netmask 0.0.0.0 gw 192.168.11.1 dev eth1

The above command adds roue entry to the kernel saying that any IP must be routed to the wireless router (which is 192.168.11.1 in my case).

If you follow above method, you will have to add the route every time system starts up. If you need to add the route permanently, you can configure the routing under Network Settings as mentioned in previous sections.

Hope this helps. Comments are always welcome