[技術] Hexspeak

Written on 2:01 上午 by Yu Lai

我相信在程式設計師心理,都有想惡搞的一面,
這也大概就是HexSpeak會出現的原因吧。XD
PS: 這篇就當做用來設計Protocol與Magic Number參考用吧。

Ref: Wikipedia Hexspeak

Hexspeak, like leetspeak, is a novelty form of variant English spelling.

Hexspeak was created by programmers who wanted a magic number, a clear and unique identifier with which to mark memory or data. Using hexadecimal notation, which includes the digits 0123456789ABCDEF, it is possible to create small words with the digit "0" representing the letter "O", "1" representing the letter "I", "5" representing "S", and "6" or "9" representing "G" or "g" respectively.

Notable magic numbers

Many computer processors, operating systems, and debuggers make use of magic numbers, especially as a magic debug value.

* 0xABADBABE ("a bad babe") is used by Apple as the "Boot Zero Block" magic number.[citation needed]
* 0xBAADF00D ("bad food") is used by Microsoft's LocalAlloc(LMEM_FIXED) to indicate uninitialised allocated heap memory.[citation needed]
* 0xBADCAB1E ("bad cable") Error Code returned to the Microsoft eVC debugger when connection is severed to the debugger.[citation needed]
* 0xBADDCAFE ("bad cafe") is used by 'watchmalloc' in OpenSolaris to mark allocated but uninitialized memory.[citation needed]
* 0xBEADFACE ("bead face, or face bead") Is the pattern that fills all unused memory locations in the Motorola 68HCS12DP256 micro-controller simulator, SimHC12.[citation needed]
* 0xCAFEBABE ("cafe babe") is used by Mach-O ("Fat binary" in both 68k and PowerPC) to identify object files, and by the Java programming language to identify Java bytecode class files.[1]
* 0xCAFED00D ("Cafe Dude") is used by Sun JAVA as a magic number for their pack200 compression.[citation needed]
* 0xD15EA5E ("disease") opens a game disc partition on the Wii video game console. (Also of note, it was 0xDEADBEEF on the Nintendo GameCube.)[citation needed]
* 0xDEADBABE ("Dead Babe") is used by IBM Jikes RVM as a sanity check of the stack of the primary thread [2]
* 0xDEADBEEF ("dead beef") is used by IBM RS/6000 systems, Mac OS on 32-bit PowerPC processors and the Commodore Amiga as a magic debug value. On Sun Microsystems' Solaris, it marks freed kernel memory. On OpenVMS running on Alpha processors, DEAD_BEEF can be seen by pressing CTRL-T.[3]
* 0xDEADDEAD ("dead dead") is the bug check (STOP) code displayed when invoking a Blue Screen of Death either by telling the kernel via the attached debugger, or by using a special keystroke combination[4]. This is usually seen by driver developers, as it is used to get a memory dump on Windows NT based systems. An alternative to 0xDEADDEAD is the bug check code 0x000000E2[5], as they are both called MANUALLY_INITIATED_CRASH as seen on the Microsoft Developer Network.
* 0xDEFEC8ED ("defecated") is the magic number for OpenSolaris core dumps.[6]
* 0xFACEFEED ("face feed") is used by Alpha servers running Windows NT. The Alpha Hardware Abstraction Layer (HAL) generates this error when it encounters a hardware failure.[7]
* 0xFEE1DEAD ("feel dead") is used as a magic number in the Linux reboot system call.[8]
* 0xFEEDFACE ("feed face") is used as a header for Mach-O binaries, and as an invalid pointer value for 'watchmalloc' in OpenSolaris.[citation needed]

[edit] Designing magic numbers

Given there are at least a few hundred words in English consisting of only the letters "a", "b", "c", "d", "e", "f", "o", "i" and "s", it is easy for programmers to devise their own, such as 0xD15EA5ED or 0xBED51DE5. As such, it is useful to observe a few patterns in the classic hexspeak constants given above. These constants all use the full width of the word (in this case 32-bit), and none begin with "1" or "5". This choice means that if the word is interpreted as an integer, it is a (usually large) negative integer. For example, 0xBAADF00D is -1163005939, a large negative integer that is unlikely to arise in many programs. Microsoft's 0xBAADF00D is also a good value to catch access to uninitialised memory for another reason—ending the word with the "1", "5", "b", "d", or "f" ensures that the constant is an odd number, which generates an unaligned pointer exception on many processor architectures if the constant is interpreted as a pointer value.
[edit] Alternative letters

* In the Ada programming language, hexadecimal numbers are enclosed by "16#" and "#". For example, "16#Ada_Ada_Ada_Ada#".
* The C programming language notation uses the "0x" prefix to indicate a hexadecimal number; the "0x" is usually ignored when reading the letters or numbers.
* In the Intel assembly language, hexadecimal numbers are denoted by a "h" suffix. For example: FEEDADEADF15h ("feed a dead fish"). Note that numbers in this notation that begin with a letter have to start with a zero to distinguish them from variable names. "FEEDADEADF15h" would then be "0FEEDADEADF15h".
* In 6502 assembly language , hexadecimal numbers are denoted by a "$" prefix. This allows for words starting with the letter "S", for example $EED ("seed").

[技術] 在Makefile中加入Check file size的機制

Written on 9:11 下午 by Yu Lai

今天在porting新板子的loader,
因為flash memory layout的關係,
整個loader大小才128kb。
而我沒注意到Image Size己經暴了一點,
沒想到flash還是寫成功了,
結果reboot後跑起來果然怪怪的。
連基本的printf都怪怪的,囧~
只能拿JTAG來救了,唉。

於是我想到要在Makefile裡加入檢查檔案大小的機制,
讓make時適時的提醒我檔案大小是否ok?

結果讓我搞了一個快下午還搞不定 @_@,
我試了老半天還是不知該怎麼把bash的if加到Makefile裡。
最後到GNU Makefile仔細的找了找才發現原來是我想錯了,
Makefile裡的command部份其實是呼叫sub shell執行命令,
然後判斷其return value。
所以要加入檢查檔案大小的機制連if都不必用到,
直接用test就可以了。

e.g.

check:
@echo -e "\nCheck redboot.img file size ....."
@test `stat -c %s boot/install/bin/redboot.img` -lt 129792
@echo "Ok."

[技術] 在Wine中存取Serial COM Port

Written on 2:03 上午 by Yu Lai

Wine是一種在類Unix系統上執行Windows程式的軟體,
它可以在Ubuntu上跑一些Windows的程式。

會使用這功能主要是要跑Holux M-1000C附的ezTour,
雖然己成功將GPS配合Google Earth來使用,
但我仍未找出怎麼讀出M-1000C內路徑的方法,
現階段只好先透過Wine來跑囉。

不過ezTour要使用COM Port來存取GPS的資料,
在使用前要先將Wine設定好mapping COM Port,
設定方式是先在 ~/.wine/dosdevices 目錄下建立一個link,
e.g.

# ln -s /dev/rfcomm0 com1

這樣透過Wine開啟的ezTour就可以指定COM1來讀出rfcomm0內的資料啦。

[技術] 在Ubuntu使用Holux M-1000C GPS配合Google Earth

Written on 12:10 下午 by Yu Lai

本篇介紹為了這次出差買的Holux M-1000C GPS在Ubuntu
下配合Google Earth來達到即時定位.

1. 首先當然是要先讓Ubuntu與Holux M-1000C連線
Holux M-1000C本身主要是用藍芽的方式與NB或手機連線,
它也有提供特殊的USB線可以直接轉成RS-232的方式連結,
但這條線我沒買,有機會下次再介紹這條特別的線。

在Ubuntu下用GUI的藍芽只能完成初步的連線,至於GPS常用
的SPP只能在Terminal下指令了,方式如下:
先scan藍芽,把M-1000C的MAC記下來。

# hcitool scan
Scanning ...
00:1B:C1:05:9C:64 Holux M-1000C

接著查看GPS使用的RFCOMM的channel。
# sdptool browser 00:1B:C1:05:9C:64
Browsing 00:1B:C1:05:9C:64 ...
Service Name: SPP slave
Service RecHandle: 0x10000
Service Class ID List:
"Serial Port" (0x1101)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 1
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100

最後編輯/etc/bluetooth/rfcomm.conf建立rfcomm介面:
rfcomm0 {
bind yes;
device 00:1B:C1:05:9C:64;
channel 1;
comment “Holux M-1000C”;
}

重啟Bluetooth services
/etc/init.d/bluetooth stop
(wait a while)
/etc/init.d/bluetooth start


2. 安裝與設定Google Earth
Google Earth自行到Google網頁上抓就有了,我是抓5.1beta版本。
接下來我們要利用了Google Earth的KML以及KML可以refresh的功能,
來達到即時定位的目的。

預設Google Earth會安裝在/opt/google-earth目錄下,
在該目錄下建立一個Realtime GPS.kml,內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<NetworkLink>
<name>Realtime GPS</name>
<open>1</open>
<Link>
<href>./realtime/Realtime GPS.kml</href>
<refreshMode>onInterval</refreshMode>
</Link>
</NetworkLink>
</kml>

接著把相關目錄realtime建立出來:
# mkdir /opt/google-earth/realtime

接著打開Google Earth,它建好的KML開啟放在Places下(檔案 -> 開啟...)。

3. 從M-1000C取出NMEA定位資料
我們剛才己經將RFCOMM介面設定好了,接著只要下
# rfcomm connect 0
syntax error line 23
Connected /dev/rfcomm0 to 00:1B:C1:05:9C:64 on channel 1
Press CTRL-C for hangup

然後另外開一個Terminal就可以從/dev/rfcomm0內取到M-1000C回報的定位資料了。
e.g.
# cat /dev/rfcomm0 
$GPGGA,044423.000,0910.5038,N,09916.9805,E,1,9,0.89,8.6,M,-24.3,M,,*72
$GPRMC,044423.000,A,0910.5038,N,09916.9805,E,0.03,0.00,311009,,,A*67
$GPVTG,0.00,T,,M,0.03,N,0.06,K,A*38
$GPGGA,044424.000,0910.5038,N,09916.9805,E,1,9,0.89,8.6,M,-24.3,M,,*75
$GPRMC,044424.000,A,0910.5038,N,09916.9805,E,0.06,0.00,311009,,,A*65
$GPVTG,0.00,T,,M,0.06,N,0.10,K,A*3A
...

所以接下來就是要拆NMEA的format將它轉成剛才在Google Earth設定realtime的KML檔,
提供給Google Earth讀取並顥示即時位置了。
(PS:NMEA格式可以到GPS - NMEA sentence information參考。)
以下是我自己寫的C Code,是將NMEA中的GPRMC格式轉成KML,
當然可以依照自喜歡的格式和語言自己改寫。
/*
* filename: gps2kml.c
* author: lazyf (lazyflai (at) gmail.com)
* date: 2009/10/31
* copyright: http://creativecommons.org/licenses/by-nc-nd/2.5/tw/
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#define DEV_FILE "/dev/rfcomm0"
#define KML_FILE "/opt/google-earth/realtime/Realtime GPS.kml"


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

char strbuf[256];
char *strp;
FILE *fp, *fp2;
float latitude, latitude_in, latitude_degrees, latitude_minutes;
float longitude, longitude_in, longitude_degrees, longitude_minutes;
float altitude, speed;

/* Call rfcomm connect */
system("rfcomm release 0");
sleep(3);
system("rfcomm connect 0 &");
sleep(5);

/* Open device file */
if((fp = fopen(DEV_FILE, "r"))) {
/* Call Google Earth up */
system("/opt/google-earth/googleearth &");
while(1) {
/* Read text */
memset(strbuf, 0, sizeof(strbuf));
fscanf(fp, "%s\n", strbuf);
if(strlen(strbuf) < 58)
continue;

/* Parse GPRMC format */
if(memcmp(strbuf, "$GPRMC", 6)==0) {
strp = (char *)strtok(strbuf, ","); /* $GPRMC */
strp = (char *)strtok(0, ","); /* Time */
strp = (char *)strtok(0, ","); /* Avalible or Void */

strp = (char *)strtok(0, ","); /* Latitude */
latitude_in = atof(strp);
strp = (char *)strtok(0, ","); /* N or S */
if(strcmp(strp, "S") == 0)
latitude_in = -latitude_in;
latitude_degrees = (int)(latitude_in/100);
latitude_minutes = latitude_in - latitude_degrees*100;
latitude = latitude_degrees + (latitude_minutes/60);

strp = (char *)strtok(0, ","); /* Longitude */
longitude_in = atof(strp);
strp = (char *)strtok(0, ","); /* E or W */
if(strcmp(strp, "W") == 0)
longitude_in = -longitude_in;
longitude_degrees = (int)(longitude_in/100);
longitude_minutes = longitude_in - longitude_degrees*100;
longitude = longitude_degrees + (longitude_minutes/60);

strp = (char *)strtok(0, ","); /* Speed */
speed = atof(strp) * 1.852;
if(speed < 3)
speed = 0;

strp = (char *)strtok(0, ","); /* Altitude */
altitude = atof(strp);

/* Output KML file */
if((fp2 = fopen(KML_FILE, "w"))) {
fprintf(fp2,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<kml xmlns=\"http://earth.google.com/kml/2.0\">\n"
"\t<Placemark>\n"
"\t\t<name>GPS %d.%d km/h</name>\n"
"\t\t<description></description>\n"
"\t\t<Point>\n\t\t\t<coordinates>%f,%f,%f</coordinates>\n\t\t</Point>\n"
"\t</Placemark>\n"
"</kml>\n",
(int)speed, ((int)(speed*10))%10, longitude, latitude, altitude);
fflush(fp2);
fclose(fp2);
}
}
}
fclose(fp);
}

return 0;

}

最後把它compile出來執行,就會自動建好rfcomm0和開啟Google Earth啦。

[技術] 在Ubuntu安裝SCM SCR-243 PCMCIA Card Reader

Written on 2:55 上午 by Yu Lai

之前買的pcmcia介面的SmartCard Reader,沒想到裝在Linux上有點麻煩。
首先到官網上 http://www.scm-pc-card.eu/ 抓Driver回來。
安裝前請先透過apt-get安裝以下套件:

apt-get install libusb-0.1-4 libpcsclite1 libpcsclite-dev pcscd pcsc-tools build-essential autoconf libccid

接著把Driver解開,執行它的install檔,不過我抓的v4.2.6好像在判斷pcsclite有問題,
手動將install內的判斷式修改一下即可。
./install

接著到 /dev 下手動將device node建立出來
cd /dev
mknod SCR24x0 c 251 0

udev也要
cd /lib/udev/devices
mknod SCR24x0 c 251 0

然後重新啟動電腦,讓剛才編好的driver與pcscd載入,
可用以下指令來判斷是否載作成功:
# lspcmcia -v
Socket 0 Bridge: [yenta_cardbus] (bus ID: 0000:06:09.0)
Configuration: state: on ready: unknown
Voltage: 5.0V Vcc: 5.0V Vpp: 0.0V
Socket 0 Device 0: [scr24x_cs] (bus ID: 0.0)
Configuration: state: on
Product Name: SCR243 PCMCIA Smart Card Reader
Identification: manf_id: 0xffff card_id: 0x0001
prod_id(1): "SCR243 PCMCIA" (0x2054e8de)
prod_id(2): "Smart Card Reader" (0xf5a90d5d)
prod_id(3): --- (---)
prod_id(4): --- (---)

# lsmod |grep pcmcia
pcmcia 43052 1 SCR24x
pcmcia_core 43412 4 SCR24x,pcmcia,yenta_socket,rsrc_nonstatic

使用讀卡機前可以用 pcsc_scan 指令來檢查,
不過我在使用上需先重插卡片再重啟pcscd才能正常使用,
算了,能用就好。最後就是上玉山的WebATM使用囉。

[技術] 在Thinkpad T60上安裝Ubuntu一些Note

Written on 2:31 上午 by Yu Lai

最近出差到泰國,真的被XP當到快發瘋了,
待出差回去後,把T60整個format掉裝起Ubuntu。
期間有一些安裝上的Note,就記錄在這裡囉。
(PS: 本篇會持續修改與增加內容。)

1. Track-Point的中鍵scroll功能
(Updated on 2010/07/05)
原本的方法在Ubuntu 10.04後就失效了QQ,
還好有人把該設定打包成套件直接使用。
先安裝gpointing-device-settings,
裝好執行後把Use wheel emulation打勾,
Button選2按Ok即可正常運作。

2. 把該死的dash拿掉
這個之前就有一篇在說明了,這裡再補記一下= =。
cd /bin
ln -sf bash sh

3. 使用root登入
這點很不建議,不過由於工作上的關係,常常需要compile到Linux Kernel,
加上又是NB,所以只好偷雞一下啦。
到/etc/gdm/gdm.conf內加入 AllowRoot=true 即可。

4. 安裝SCM SCR-243 PCMCIA Card Reader
這篇內容太多了,所以獨立出來。
Link: [技術]在Ubuntu安裝SCM SCR-243 PCMCIA Card Reader

5. 使用GPS配合Google Earth
Link: [技術] 在Ubuntu使用Holux M-1000C GPS配合Google Earth

6. 使用Wine存取Serial COM Port
Link: [技術] 在Wine中存取Serial COM Port

7. 取消udisks-daemon去polling光碟機
就算光碟機裡沒放光碟片,它還是偶爾會去讀取,一整個超怪。
# sudo hal-disable-polling --device /dev/sr0

8. 永久取消Pointer can be controlled using the keypad
修改/usr/share/X11/xkb/compat/complete檔,把augment "mousekeys"和augment "accessx(full)"取消掉。
如下:

// $XKeyboardConfig$
// $Xorg: complete,v 1.3 2000/08/17 19:54:34 cpqbld Exp $
default xkb_compatibility "complete"  {
include "basic"
augment "iso9995"
//    augment "mousekeys"
//    augment "accessx(full)"
augment "misc"
augment "xfree86"
augment "level5"
};

9. 永久取消NumLock
使用gconf-editor,使用Ctrl+F,勾選"Search also in key names",找"numlock"。
然後Turn off "remember_numlock_state"和Turn off numlock "numlock_on"。

[技術] coLinux安裝步驟

Written on 6:56 下午 by Yu Lai

之前就裝過coLinux來玩過了,但後來公司配了workstation裝了Linux,
工作上的使用也都移到那台去run,於是就把coLinux給移掉了,沒辦法,佔空間啊。
最近要出差到國外做function verify,需要邊改邊測,總不能叫我還帶台
workstation出國吧,所以又把coLinux給裝起來了。不過隨著新版本coLinux,
安裝和設定上有些微的不同,以下就是這次安裝的步驟,就當做筆記吧。


1. 下載coLinux
首先,到coLinux的官網 http://www.colinux.org/ 下載最新的 coLinux,
點選download後它會幫你導向sourceforge,我抓到的版本為 0.7.4 版本。
這裡順便把coLinux幫我們包好的各大Linux Distribution的filesystem image
檔也抓下來,我使用的是 Debian-5.0r2-lenny.7z。

2. 安裝coLinux
抓完後執行解開,基本上照著點下一步就ok了。另外,TAP Driver記得安裝唷。
裝好後先別急著執行 coLinux,先把剛才的 Debian-5.0r2-lenny.7z 解開放在
coLinux的目錄下。

3. 網路設定-Windows
修改debian-lenny.conf的內容,把網路介面設成 eth0=tuntap。
(這一步看個人使用習慣,我是習慣透過tap配合NAT來使用。)
點選控制台->網路連線,把新增出來的網路介面名稱改為"TAP"方便示別。
接著點入原有的LAN的介面->內容->進階,把"允許其他網路使用著透過這台..."打勾,
開啟NAT的服務。

4. 網路設定-Debian
接著回到coLinux的目錄下執行debian-lenny.bat。
進到Debian的console後,用預設帳密 root / colinux 登入。先設定網路,
修改/etc/network/interfaces,把eth0的部份改為以下:

allow-hotplug eth0
iface eth0 inet static
address 192.168.0.100
netmask 255.255.255.0
gateway 192.168.0.1

修改/etc/resolv.conf,加入DNS:
nameserver 168.95.192.1

這裡補充一點,到/etc/modprobe.d/aliases把ipv6 Module給取消掉,
因為ipv6會影響到samba的運作,所以要修改一下:
alias net-pf-10 off

把以上這行取代掉原本的alias net-pf-10 ipv6即可。

5. 安裝Tools
再來就可以透過apt-get這個好用的tool把該裝的裝一裝了,
e.g. sshd, samba, gcc, subversion...etc。
這裡建議先裝前2個,這樣可以透過putty連進去,畫面操作上會比較順手。

6. 增加Partition
另外,由於我們的Partition是使用別人幫我們包好的filesystem image檔,
大小是固定的2gb。使用上多少會有所限制,所以這時可以透過以下方法新增
出額外的image檔來使用。
首先,在coLinux目錄下使用windows內建的指令來新增一空白的檔案:
c:\coLinux>fsutil file createnew Debian-pub.ext3.8gb 8589934592

這裡我建了一個8gb大小的檔案出來。
接著修改debian-lenny.conf的內容,把這個image檔mount進去,在conf檔內加入:
cobd1="Debian-pub.ext3.8gb"

改完後存檔,重新啟動coLinux,進到debian後,使用以下指令來建立ext3 filesystem:
debian# mkfs.ext3 /dev/cobd1

跑完後就可以mount啦,記得修改一下/etc/fstab把新的filesystem image自動mount起來:
/dev/cobd1      /pub            ext3    errors=remount-ro 0       1


7. 總結
以上就是這次安裝的一些重要步驟,至於其他Debian設定上的細節就沒提到了。
有什麼問題再寫E-mail問我吧。

[技術] ATM流量管理(QoS)

Written on 11:53 上午 by Yu Lai

最近在弄ATM Qos,自然也學到了不少東東,以下是一些相關的資料整理。

依照ATM Forum的Traffic Management Specification Version 4.0規範,ATM的服務類別分為以下的定義:

1. Constant Bit Rate (CBR)
可提供固定速率的服務,對傳輸延遲、傳輸遺失及傳輸跳動等服務品質的要求最為嚴格,適合應用於及時性或需要固定頻寬的服務。適用的應用服務如下:
-交談式視訊服務 (e.g., videoconferencing)。
-交談式音訊服務 (e.g., telephone)。
-分散式視訊 (e.g., television, distributed classroom)。
-分散式音訊 (e.g., radio, audio feed)。
-其他視訊服務 (e.g., video on demand)。
-其他音訊服務 (e.g., audio library)。

2. Real-Time Variable Bit Rate (rt-VBR)
VBR的服務品質提供了對傳輸延遲和傳輸遺失的保證,主要針對影像和對傳輸延遲敏感的服務。另外,根據對延遲要求的不同,又可細分為及時性(VBR-rt)和非及時性(VBR-nrt)兩類。適用的應用服務如下:
-即時應用服務(包含CBR所列)但可容許些微的cell loss率,或是較有效率的網路資源應用(註)。

3. Non-Real-Time (nrt-VBR)
和VBR-rt相比,VBR-nrt可允許較多的傳輸延遲。適用的應用服務如下:
-緊急性的交易程序 (e.g., airline reservations, banking transactions, process monitoring)。
-Frame Relay interworking。

4. Available Bit Rate (ABR)
ABR的服務品質保證了最小傳輸頻寬,適合IP和LAN的服務,ABR需要在ATM層提供流量控制(Flow Control),以避免網路發生壅塞或超載。適用的應用服務如下:
-任何UBR的應用,配合ABR的flow-control可以得到較少的cell lose率。
-緊急性的資料傳輸 (e.g., defense information)。
-超級電腦應用服務。
-需較少的delay行為的傳輸服務 (e.g., remote procedure call, distributed file service, or computer process swap/paging)。

5. Unspecified Bit Rate (UBR)
UBR適合的服務與ABR相同,但無任何服務保證。適用的應用服務如下:
-一般文字/資料/圖片傳送 (e.g., banking transaction, credit card verification, email, telex, fax, news feed, weather sat. pictures, file transfer, library browsing, telecommuting, telnet)

註:
當服務品質的要求愈高時,相對地對傳輸頻寬的需求就愈高,在配置網路頻寬時的彈性也就跟著下降。對CBR而言,因為從頭到尾都必須提供固定的頻寬,根本就沒有多工增益(Multiplexing Gain)可言。但是對VBR-nrt和ABR而言,因為訊務本身具有叢集(Bursty)特性,系統只需要提供介於最高所需頻寬和平均所需頻寬的等效頻寬即可。隨著訊務的叢集特性愈明顯,網路可以容納的用戶數也愈多,多工增益也跟著提高,因此CBR的收費最高,VBR、ABR次之,UBR最低。

[技術] MSN與各家防毒軟體的設定

Written on 10:44 上午 by Yu Lai

一般我們在使用MSN時, 在傳送檔案時,
MSN都會要我們設定防毒軟體或是使用它們自己的LiveCare.
使用LiveCare是也ok, 但每次都要等它更新完才能掃毒實在有夠久的.

但各家防毒軟體的設定單檔掃描的方式也都不同,
以下是在網路上找到的, 有幾個我自己也沒試過, 參考看看吧.

== Avira AntiVir 9.x 小紅傘 ==
"C:\Program Files\Avira\AntiVir Desktop\avscan.exe" /CFG="C:\Program Files\Avira\AntiVir Desktop\Profile.txt" /PATH=%file%

同時需建立一文字檔Profile.txt於安裝目錄下, 內容如下:
[CFG]
GuiMode=2
ExitMode=3

[SEARCH]
Parameter=0x00000002
Parameter=0x00000020
Parameter=0x00000100
Parameter=0x00000400
Parameter=0x00010000
Parameter=0x00000080

[SCANNER]
BootsektorStart=0
Memory=0
ScanRootkits=0

參數說明:
GuiMode=?
1=顯示完整視窗
2=精簡
3=不顯示

ExitMode=3 (掃描後離開)
BootsektorStart=0 (取消開機磁區掃描)
Memory=0 (取消記憶體掃描)
ScanRootkits=0 (取消Rootkit掃描)

== ESET's NOD32 ==
"C:\Program Files\Eset\nod32.exe" /selfcheck+ /list+ /scroll+ /quit+ /pattern+ /heur+ /scanfile+ /scanboot- /scanmbr- /scanmem- /arch+ /sfx+ /pack+ /mailbox- /adware /unsafe /ah /prompt /all

== Symantec AntiVirus ==
"C:\Program Files\Symantec AntiVirus\Rtvscan.exe" /selfcheck+ /list+ /scroll+ /quit+ /pattern+ /heur+ /scanfile+ /scanboot- /scanmbr- /scanmem- /arch+ /sfx+ /pack+ /mailbox- /adware /unsafe /ah /prompt /all

== Norton AntiVirus ==
"C:\Program Files\Norton Internet Security Professional\Norton AntiVirus\ccIMScan.exe"

== Avast ==
"C:\Program Files\Alwil Software\Avast4\ashQuick.exe"

== Kaspersky ==
"C:\Program Files\Kaspersky Lab\Kaspersky Internet Security 6.0\avp.exe" scan %1

== McAfee 2007 ==
"C:\Program Files\McAfee\VirusScan\mcods.exe"

== PC-cillin ==
"C:\Program Files\Trend Micro\Internet Security 2005\PCCVScan.exe"

[閒聊] 馬來西亞出差心得

Written on 10:03 上午 by Yu Lai

這陣子好久沒發佈文章了,
不是沒東西可以發,
只是真的工作上忙了點.
這篇算是去馬來西亞的一些感想與心得吧.

二月底時去了馬來西亞出差,
本來說好的2個禮拜,
結果搞到整整1個月才回來.

在馬來西亞那段時間,
飲時大概是最不習慣的一環了吧.
這段期間也可以說是過的吃香喝辣的日子XD,
每天吃的三餐,
一定有一道菜是雞肉,
外加一道一定是紅色的菜.
而TM(Telcom Malaysia)也很不錯的在他們的Lab裡提供下午茶給我們吃,
但5天裡大概也有4天是紅通通的沒看過的東東,
然後飲料不是甜的要命的咖啡就是色素+糖水 = =.

由於我們是住在離位於Cyber Jaya的TM Lab有一段距離的Subang Jaya.
所以我們有在當地租用2台Van做為移動工具.
但也因為有一段距離(約3x公里),
加上人數眾多(約20人),
所以每天都要安排班次,
過著早出晚歸的日子,
算起來每天的工時比在台灣還誇張.
有時甚至過了半夜12點還在TM Lab. 唉, 真命苦 .__.

另外, 在跟TM的人溝通上用英文是很ok的,
雖然他們的英文也是有點口音,
但基本上還聽得懂,
不像跟印度阿三一樣聽嘸.
而每天早上Hotel會提供報紙給我們,
有華文的也有英文的報紙.
對了, 說到這個,
我們在TM這段期間裡,
有上他們的新聞喔 XD.

最後,
這篇主要是隨便寫寫啦,
會看起來沒什麼內容是因為工作內容不方便透露太多,
加上也有一段時間了,
有些東東也有點忘了,
請多多見諒吧.

[技術] 在Linux User-Space下實做L3 Protocol

Written on 4:01 下午 by Yu Lai

其實這篇應該是要接續上一篇寫的,因為用到的方法是和上一篇相同
的,但由於主題比較不太一樣,所以就分開來寫了。

在Linux中,一般要實做新的L3 protocol,大都是從kernel去下手,
效能較好,能存取的資源也比較多。但在開發embedded system下往
往有專案時間壓力以及軟體彈性的需求,去改kernel來達到這些要求
也就有點不太實際。所以我採用了在上一篇中使用的方法,也就是
Raw Socket與LPF(Linux Packet Filter)來完成一個L3 Protocol的
實做。

和Sniffer一樣的,我們使用了Raw Socket與LPF,比較不同的地方在
於LPF所使用的Filter。由於我們的protocol是定義成採用0x1219的
ether type,所以在配合tcpdump生成BPF code時用了以下的指令。

# tcpdump -dd -s 2048 ether proto 0x1219
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 1, 0x00001219 },
{ 0x6, 0, 0, 0x00000800 },
{ 0x6, 0, 0, 0x00000000 }

以下是部份的實做的程式碼:

#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <net/if.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/filter.h>
#include <linux/sockios.h>


void *mcpV2Handler(void *arg) {

int sock, n;
int rr;
U8 buf[2048];
U8 tmp[8], tmpSlot;
U8 lastBegMac[6];
U32 lastBegTime = 0;
U32 * pGroupKey;
tMcpFrame *frame;
tMcpPacket *packet;
tMcpCardInfo *cardInfo;
pthread_t mcpV2Sender_tid;
pthread_t mcpV2TxRx_tid;
struct sock_fprog filter;

/* Using tcpdump to generate BPF code */
/*
# tcpdump -d -s 2048 ether proto 0x1219
(000) ldh [12]
(001) jeq #0x1219 jt 2 jf 3
(002) ret #2048
(003) ret #0
*/
struct sock_filter bpf_code[]= {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 1, 0x00001219 },
{ 0x6, 0, 0, 0x00000800 },
{ 0x6, 0, 0, 0x00000000 }
};

filter.len = sizeof(bpf_code)/sizeof(bpf_code[0]);
filter.filter = bpf_code;

/* set detached thread */
pthread_detach(pthread_self());

if ((sock=socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL)))<0) {
perror("socket");
exit(1);
}

/* Attach the bpf filter to the socket */
if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))<0){
perror("setsockopt");
close(sock);
exit(1);
}

/* ----------- Start implement ----------- */

while(1) {
n = recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL);
if(n < 22) { /* 6+6+2+2+4+2+N */
printf("invalid packet\n");
continue;
}

frame = (tMcpFrame *)buf;

if(memcmp(frame->srcAddr, myMac, 6) == 0)
continue;

MCP_LOG("Dump: %02x%02x%02x%02x%02x%02x|"
"%02x%02x%02x%02x%02x%02x|"
"%04x|%04x|%08x|%04x|"
"%02x %02x %02x %02x %02x %02x %02x %02x %02x",
frame->dstAddr[0], frame->dstAddr[1], frame->dstAddr[2],
frame->dstAddr[3], frame->dstAddr[4], frame->dstAddr[5],
frame->srcAddr[0], frame->srcAddr[1], frame->srcAddr[2],
frame->srcAddr[3], frame->srcAddr[4], frame->srcAddr[5],
ntohs(frame->etherType),
ntohs(frame->mcpProtoType),
ntohl(frame->groupKey),
ntohs(frame->dataLength),
frame->data[0], frame->data[1], frame->data[2], frame->data[3],
frame->data[4], frame->data[5], frame->data[6], frame->data[7], frame->data[8]);

if(ntohs(frame->mcpProtoType) == 1 && ntohl(frame->groupKey) == myGroupKey) {
/* blah blah */
/* blah blah */
/* blah blah */
}

}

close(sock);

}

[技術] 在Linux下實作Sniffer

Written on 1:39 下午 by Yu Lai

在這裡先感謝一下黃仁竑老師,因為這篇其實這是之前唸研究所時,
上課所要交的作業。沒想到最近在工作上也用到了,呵呵。

雖然在Linux下有許多好用的Sniffer工具,如: tcpdump 或 libpcap等。
但若了解如何自己實作Sniffer,對於實作網路相關的protocol會有更深的了解。
在實作sniffer之前,在Linux下有幾個東西我們要先了解。

首先是raw socket,透過raw socket,可以讓我們從Layer 2(Ethernet)
的資料開始解讀,而不是已經被核心處理過的tcp/udp payload。

sock=socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));

接著是LPF(Linux Packet Filter),在Linux的kernel中,有個LPF的機制
可以預先設定過濾socket讀取到的內容。當然這個在實作sniffer不是必要
的,我們大可在讀取資料後自行filter掉非必要的data。但透過LPF,可以
讓我們專心在實作資料的呈現上。
而LPF的使用,我們可以使用一種pseudo-machine code language叫作BPF。
它是一種用來描述filter的語言,我們可以透過tcpdump這支好用的工具來
產生bpf的sample code。使用方法就是使用tcpdump -d
tcpdump -dd 來生出C使用的code。另外,tcpdump所生成的
sample code預設只會抓取96個字元,所以要再加上-s參數來指定抓取的數量。

tcpdump -d -s 2048 tcp and host 140.123.230.166
(000) ldh [12]
(001) jeq #0x86dd jt 10 jf 2
(002) jeq #0x800 jt 3 jf 10
(003) ldb [23]
(004) jeq #0x6 jt 5 jf 10
(005) ld [26]
(006) jeq #0x8c7be6a6 jt 9 jf 7
(007) ld [30]
(008) jeq #0x8c7be6a6 jt 9 jf 10
(009) ret #2048
(010) ret #0

tcpdump -dd -s 2048 tcp and host 140.123.230.166
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 8, 0, 0x000086dd },
{ 0x15, 0, 7, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 5, 0x00000006 },
{ 0x20, 0, 0, 0x0000001a },
{ 0x15, 2, 0, 0x8c7be6a6 },
{ 0x20, 0, 0, 0x0000001e },
{ 0x15, 0, 1, 0x8c7be6a6 },
{ 0x6, 0, 0, 0x00000800 },
{ 0x6, 0, 0, 0x00000000 }

把Filter設到socket上。
struct sock_filter BPF_code[]= {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 8, 0, 0x000086dd },
{ 0x15, 0, 7, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 5, 0x00000006 },
{ 0x20, 0, 0, 0x0000001a },
{ 0x15, 2, 0, 0x8c7be6a6 },
{ 0x20, 0, 0, 0x0000001e },
{ 0x15, 0, 1, 0x8c7be6a6 },
{ 0x6, 0, 0, 0x00000060 },
{ 0x6, 0, 0, 0x00000000 }
};
struct sock_fprog Filter;
Filter.len = 11;
Filter.filter = BPF_code;

setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter))

最後是把網卡的promiscuos mode打開,網卡一般會比對dst mac和自己的
Mac Address,若不相同或不是broadcast的封包會被drop掉不處理。
若要實作sniffer,這個mode一定要打開,才能監聽到別人的封包。

strncpy(ethreq.ifr_name,"eth0",IFNAMSIZ);
ioctl(sock,SIOCGIFFLAGS,ðreq);
ethreq.ifr_flags|=IFF_PROMISC;
ioctl(sock,SIOCSIFFLAGS,ðreq);

以下是完整的sample code,不過年代久遠,也沒時間compile測試,
如有錯誤不能compile,請見諒。XD

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <linux/filter.h>
#include <sys/ioctl.h>


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

int sock, sock_server, sock_client, n, i;
char buffer[2048];
unsigned char *iphead, *ethhead, *tcphead;
int addr_len;
struct sockaddr_in sa_cli;
struct ifreq ethreq;
FILE* fPtr;

struct sock_filter BPF_code[]= {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 8, 0, 0x000086dd },
{ 0x15, 0, 7, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 5, 0x00000006 },
{ 0x20, 0, 0, 0x0000001a },
{ 0x15, 2, 0, 0x8c7be6a6 },
{ 0x20, 0, 0, 0x0000001e },
{ 0x15, 0, 1, 0x8c7be6a6 },
{ 0x6, 0, 0, 0x00000800 },
{ 0x6, 0, 0, 0x00000000 }
};

struct sock_fprog Filter;

Filter.len = 11;
Filter.filter = BPF_code;

if ((sock=socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)))<0) {
perror("socket");
exit(1);
}

/* Set the network card in promiscuos mode */
strncpy(ethreq.ifr_name,"eth0",IFNAMSIZ);
if (ioctl(sock,SIOCGIFFLAGS,ðreq)==-1) {
perror("ioctl (SIOCGIFCONF) 1");
close(sock);
exit(1);
}
ethreq.ifr_flags|=IFF_PROMISC;
if (ioctl(sock,SIOCSIFFLAGS,ðreq)==-1) {
perror("ioctl (SIOCGIFCONF) 2");
close(sock);
exit(1);
}

/* Attach the filter to the socket */
if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter))<0){
int temp=sizeof(Filter);
printf( "%d" , temp);
perror("setsockopt");
close(sock);
exit(1);
}

/* Open the result file. */
if ((fPtr = fopen("dump.txt", "w")) == NULL) {
perror("fopen");
close(sock);
exit(1);
}

while (1) {
n = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
printf("%d bytes read\n",n);

/* Check to see if the packet contains at least
* complete Ethernet (14), IP (20) and TCP/UDP
* (8) headers.
*/
if (n<42) {
perror("recvfrom():");
printf("Incomplete packet (errno is %d)\n", errno);
close(sock);
exit(0);
}

ethhead = buffer;
printf("Source MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
ethhead[0], ethhead[1], ethhead[2], ethhead[3], ethhead[4], ethhead[5]);
printf("Destination MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
ethhead[6], ethhead[7], ethhead[8], ethhead[9], ethhead[10], ethhead[11]);

iphead = buffer+14; /* Skip Ethernet header */
if (*iphead==0x45) { /* Double check for IPv4 and no options present */
printf("Source host %d.%d.%d.%d\n",
iphead[12], iphead[13], iphead[14], iphead[15]);
printf("Dest host %d.%d.%d.%d\n",
iphead[16], iphead[17], iphead[18], iphead[19]);
printf("Source,Dest ports %d,%d\n",
(iphead[20]<<8)+iphead[21], (iphead[22]<<8)+iphead[23]);
printf("Layer-4 protocol %d\n",
iphead[9]);
}

tcphead = iphead+20;
if (iphead[9] == 0x06) {
printf("TCP Sequence Number: %x%x%x%x\n",
tcphead[4], tcphead[5], tcphead[6], tcphead[7]);
printf("TCP Acknowledgement Number: %x%x%x%x\n",
tcphead[8], tcphead[9], tcphead[10], tcphead[11]);
printf("TCP Header Length: %d\n",
tcphead[12]>>4);
printf("TCP Control Bits: %02x (UAPRSF)\n",
tcphead[13]);
printf("TCP Window Size: %d\n",
(tcphead[14]<<8)+tcphead[15]);
for(i=4*(tcphead[12]>>4);i<n-14-20;i++) {
printf("%c", tcphead[i]);
}
printf("\n");
}
}

}


Ref:
http://www.linuxjournal.com/article/4659

[技術] Linux下的Timer

Written on 10:36 上午 by Yu Lai

其實之前就有用到Timer,只是最近又再一次用到,所以把相關的部份整理一下。
在Linux下實做定時器有兩種方法,分別是alarm()和setitimer(),以下分別介紹:

1. alarm()
alarm()可以用來設定信號SIGALRM在指定的秒數後傳到目前的process。
使用起來比起setitimer較為簡單,但由於使用的單位是秒數,
所以如果不要求很精確的話,用alarm()配合signal()就夠了。

unsigned int alarm(unsigned int seconds)

alarm()用來設置信號SIGALRM在經過參數seconds指定的秒數後傳送給目前的process。
如果參數seconds為0,則之前設置的鬧鐘會被取消,並將剩下的時間返回,
如果之前未設鬧鐘則返回0。

void sigalrm_fn(int sig) {

printf("alarm!\n");
alarm(2);

return;

}

int main(void) {

signal(SIGALRM, sigalrm_fn);
alarm(1);
while(1) pause();

}


2. setitimer()
setitimer()比alarm功能強大,支持3種類型的Timer:
ITIMER_REAL : 以系統真實的時間來計算,它送出SIGALRM信號。
ITIMER_VIRTUAL : 以Process在User-Mode下花費的時間來計算,它送出SIGVTALRM信號。
ITIMER_PROF : 以Process在User-Mode下和Kernel-Mode下所費的時間來計算,它送出SIGPROF信號。

int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));

setitimer()第一個參數which指定定時器類型(上面三種之一);
第二個參數是struct itimerval的一個instance;第三個參數可不做處理。
setitimer()調用成功返回0,否則返回-1。

struct itimerval {
struct timeval it_interval; /* timer interval */
struct timeval it_value; /* current value */
};

itimerval結構中的it_value是減少的時間,當這個值為0的時候就發出相應的信號。
然後再將it_value設置為it_interval值。也就是說如果itimerval.it_interval不為0,
則該定時器將持續有效(每隔一段時間就會發送一個信號)。

下面是關於setitimer的一個簡單示範,在該例子中,
每隔一秒發出一個SIGALRM,每隔0.5秒發出一個SIGVTALRM信號:
int sec;

void sigroutine(int signo) {

switch (signo){
case SIGALRM:
printf("Catch a signal -- SIGALRM \n");
signal(SIGALRM, sigroutine);
break;
case SIGVTALRM:
printf("Catch a signal -- SIGVTALRM \n");
signal(SIGVTALRM, sigroutine);
break;
}
return;

}

int main() {

struct itimerval value, ovalue, value2;
sec = 5;

printf("process id is %d\n", getpid());
signal(SIGALRM, sigroutine);
signal(SIGVTALRM, sigroutine);

value.it_value.tv_sec = 1;
value.it_value.tv_usec = 0;
value.it_interval.tv_sec = 1;
value.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &value, &ovalue);

value2.it_value.tv_sec = 0;
value2.it_value.tv_usec = 500000;
value2.it_interval.tv_sec = 0;
value2.it_interval.tv_usec = 500000;
setitimer(ITIMER_VIRTUAL, &value2, &ovalue);

for(;;) ;

}


PS:
Linux信號機制基本上是從Unix系統中繼承過來的。
早期Unix系統中的信號機制比較簡單和原始,後來在實踐中暴露出一些問題,
因此,把那些建立在早期機制上的信號叫做"不可靠信號",
信號值小於SIGRTMIN(SIGRTMIN=32,SIGRTMAX=63)的信號都是不可靠信號。
這就是"不可靠信號"的來源。它的主要問題是:Process每次處理信號後,
就將對信號的響應設置為Default動作。在某些情況下,將導致對信號的錯誤處理;
因此,User如果不希望這樣的操作,那麼就要在信號處理函數結尾再一次使用signal(),重新安裝該信號。

[技術] 在C中列出目錄與檔案

Written on 8:50 上午 by Yu Lai

一般在C中,我們可以使用opendir()與readdir()來列出目錄下所有的檔案。
以下是範例程式:

#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>

main() {
DIR * dir;
struct dirent * ptr;
int i;
dir =opendir(“/etc/rc.d”);
while((ptr = readdir(dir))!=NULL) {
printf(“d_name: %s\n”,ptr->d_name);
}
closedir(dir);
}

配合struct dirent,定義如下:
struct dirent {
ino_t d_ino;
off_t d_off;
unsigned short int d_reclen;
unsigned char d_type;
char d_name[256];
};

d_ino 此目錄進入點的inode
d_off 目錄文件開頭至此目錄進入點的位移
d_reclen d_name的長度,不包含NULL字符
d_type d_name所指的檔案類型
d_name 檔名
其中unsigned cahr d_type;可以來判斷是子目錄或是一般的檔案。
但不知是我使用的uClibC的問題,沒實作到還怎樣,使用上一直有問題。

後來還是找到解決方法,方法有2種,分別如下:
1. 再使用一次readdir()來判斷回傳值,若回傳為NULL,即為檔案。
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>

main() {
DIR * dir;
DIR * dir2;
struct dirent * ptr;
int i;
dir =opendir(“/etc/rc.d”);
while((ptr = readdir(dir))!=NULL) {
char pathname[100];
sprintf(pathname,"/etc/rc.d/%s", ptr->d_name);
if((dir2 = opendir(pathname))==NULL) {
printf("%s: file\n", ptr->d_name);
} else {
printf("%s: directory\n", ptr->d_name);
closedir(dir2);
}
}
closedir(dir);
}

2. 使用int stat(const char *file_name, struct stat *buf),
在struct stat其中的 st_mode 可以用來判斷是哪種檔案(也就是上面 d_type的 功用)。
為了方便,POSIX另外有定義幾個MACRO:
S_ISLNK(st_mode) : 是symbolic link
S_ISREG(st_mode) 一般檔案(regular file)
S_ISDIR(st_mode) 目錄(directory)
S_ISCHR(st_mode) 字元設備檔(char device)
S_ISBLK(st_mode) 區塊設備檔(block device)
S_ISSOCK(st_mode) local-domain socket
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>

main() {
DIR * dir;
struct dirent * ptr;
int i;
dir =opendir(“/etc/rc.d”);
while((ptr = readdir(dir))!=NULL) {
char pathname[100];
struct stat buf;
sprintf(pathname,"/etc/rc.d/%s", ptr->d_name);
stat(pathname, &buf);
if(S_ISREG(buf.st_mode))
printf("%s: file\n", ptr->d_name);
else
printf("%s: directory\n", ptr->d_name);
}
closedir(dir);
}