Monitoring your monthly bandwidth usage

After getting my new USB modem and struggling to make it work on Ubuntu 10.04 beta (at that time), I wanted to monitor my monthly bandwidth usage. I was thinking at first to create my own shell script, but I was lucky enough to know about vnstat. it’s a simple package you can install simply using

sudo aptitude install vnstat

you can use vnstat to monitor any network interface you want using the following steps except that you will have to use the name of the network interface you want to monitor.

Now I will tell vnstat to watch my USB modems bandwidth usage by making it watch the ppp0 interface.

sudo vnstat -u -i ppp0

this will create a file in /var/lib/vnstat with the name of your interface, so this will create a file named ppp0.

Now, just start the vnstat service. you will do it this time manually, but It will start automatically every time you start your machine.

sudo service vnstat start

Your ppp0 interface is being monitored now and you will be able to see its statistics by running

sudo vnstat -i ppp0

The output will be something like that

Database updated: Fri Aug 13 01:08:03 2010

          rx:  17.36 MiB      tx:  2.79 MiB      total:  20.15 MiB

   monthly
                     rx      |     tx      |    total    |   avg. rate
     ------------------------+-------------+-------------+---------------
       Aug '10     17.36 MiB |    2.79 MiB |   20.15 MiB |    0.16 kbit/s
     ------------------------+-------------+-------------+---------------
     estimated        43 MiB |       5 MiB |      48 MiB |

   daily
                     rx      |     tx      |    total    |   avg. rate
     ------------------------+-------------+-------------+---------------
     yesterday      8.54 MiB |    1.73 MiB |   10.27 MiB |    0.97 kbit/s
         today      8.82 MiB |    1.06 MiB |    9.88 MiB |   19.82 kbit/s
     ------------------------+-------------+-------------+---------------
     estimated       169 MiB |      21 MiB |     190 MiB |

rx is your received data, while tx is your sent data, or you can just view the total.

iconv misunderstands UTF-16 strings with no BOM

I had a problem last week with converting UTF-16 encoded strings to UTF-8 using PHP’s iconv library on a Linux server. my code worked fine on my machine but the same code resulted in a rubbish unreadable characters on our production server.

Let me take you to the beginning of the problem. I had a Hexadecimal representation of a UTF-16 string like that

0635 0628 0627 062D 0020 0627 0644 062E 064A 0631

this is the equivalent of “Good morning” in Arabic “صباح الخير” . I had some lines of code that will convert this into a normal stream of UTF-16 bytes so I can be able to use iconv to convert the string to UTF-8. maybe you noticed that there is no BOM at the beginning of Hexadecimal representation of the string. so let me quote what is written on Unicode’s BOM FAQ page about this.

Q: Why do some of the UTFs have a BE or LE in their label, such as UTF-16LE?

A: UTF-16 and UTF-32 use code units that are two and four bytes long respectively. For these UTFs, there are three sub-flavors: BE, LE and unmarked. The BE form uses big-endian byte serialization (most significant byte first), the LE form uses little-endian byte serialization (least significant byte first) and the unmarked form uses big-endian byte serialization by default, but may include a byte order mark at the beginning to indicate the actual byte serialization used.

so when there is no BOM, the string should be treated as big-endian. libiconv has a different opinion about this and will try to guess if it should use big-endian or little-endian depending on the operating system. so you will get different results on different machines.

The simple solution to this problem (after a long time trying to identify it), is to just tell iconv that I’m converting from UTF-16BE (big-endian) so it won’t try to guess the endianess of the bytes. so in php it will be like that

$result = iconv('UTF-16BE', 'UTF-8', $str);

or better, I can check the BOM before converting the Hexadecimal codes to a stream of bytes and taking the decision of converting from UTF-16BE or UTF-16LE depending on if it begins with FEFF or FFFE.