【ただの技術備忘録】CentOSで無線LANにつなげてみる【その1】

手持ちのノート、DELL INSPIRON630mにCentOSをぶち込んでみたが、やはりノートらしく無線で鯖を立てたいところ。
が、当然鯖はコンソール派なので、GUIは使わない方向で接続設定してみる。
出来れば、有線DLもしない方向。マゾ縛りプレイである。

やるまでの事象は大きく分けて下記の通り。

  1. 無線LANバイスを認識させる(ドライバとかファームウェアとか)
  2. 無線LANバイスをネットワークコンフィグと関連付ける(eth1とか)
  3. 無線接続の為のパッケージインストールと設定
  4. 接続と自動接続設定

1.無線LANバイスの認識
CentOS5はインストールした時点では無線LANを認識しない。そもそもネットワークデバイスとして認識すらしない。はてさて。

# ifconfig 
eth0      Link encap:Ethernet  HWaddr 00:12:3F:6A:F8:57  
          inet addr:192.168.1.3  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:676 errors:0 dropped:0 overruns:0 frame:0
          TX packets:129 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:177325 (173.1 KiB)  TX bytes:18072 (17.6 KiB)
          Interrupt:209 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:560 (560.0 b)  TX bytes:560 (560.0 b)

今回の機種は無線LANバイスにipw2200を使用しているがロードされない。
ファームウェアが無いとかぬかす。以下からダウンロード。
Intel® PRO/Wireless 2200BG Driver Firmware

dmesg によると ipw2200 のバージョンは 1.2.2。ファームウェアはv3.0が出てるからそれをDL。

# dmesg | grep ipw
ipw2200: Intel(R) PRO/Wireless 2200/2915 Network Driver, 1.2.2kmprq
ipw2200: Copyright(c) 2003-2006 Intel Corporation
ipw2200: Detected Intel PRO/Wireless 2200BG Network Connection
ipw2200: ipw2200-bss.fw request_firmware failed: Reason -2
ipw2200: Unable to load firmware: -2
ipw2200: failed to register network device
ipw2200: probe of 0000:02:03.0 failed with error -5

違うバージョンの人は適当に探してください。
ダウンロードしたら、解凍してインストール

# tar zxvf ipw2200-fw-3.0.tgz 
ipw2200-fw-3.0/
ipw2200-fw-3.0/ipw2200-bss.fw
ipw2200-fw-3.0/ipw2200-sniffer.fw
ipw2200-fw-3.0/LICENSE.ipw2200-fw
ipw2200-fw-3.0/ipw2200-ibss.fw
# cd ipw2200-fw-3.0
# ls
LICENSE.ipw2200-fw  ipw2200-bss.fw  ipw2200-ibss.fw  ipw2200-sniffer.fw
# cp *.fw /lib/firmware/

/etc/modprobe.confに

alias eth1 ipw2200

を追記。eth1は1でも2でも、wanでも好きにしてくだしあ。これでデバイスを紐付けできるので、再起動でも。再起動後、ifconfigすればeth1が出る、はず。うん。

【ただの技術備忘録】GoogleのGoをCentos5.3にインストールしてみた

原文は以下のページ
http://golang.org/doc/install.html


Introduction
BSDライセンスよー、GCC使ってるからねーてところ。

Environment variables
環境変数を設定。

  1. $GOROOTにはGoのルートを指定するらしい。例では$HOME/goと書いてる。
  2. $GOOSには使用するOS、今回はlinuxなのでlinuxを入れておく。
  3. $GOARCHはCPUアーキテクチャを。今回は386.
  4. $GOBINはオプションでバイナリへのPATHらしい。$PATHが設定されてればそれを使う模様。デフォルトで$HOME/binも読み込むのか?よくわからん。一応書いておく。

一応、homeにはbinディレクトリを作っておく。
※追記:$HOME/binにバイナリをインストールするから、$HOME/binへPATH通しておけよ、てことのようだ

# mkdir go
# mkdir bin
# export GOROOT=$HOME/go
# export GOOS=linux
# export GOARCH=386
# export PATH=$PATH:$HOME/bin
# source .bashrc

設定したら反映しろ、とのことなので最後の行を実行。


Fetch the repository
Mercurialをインストールしてないとhgコマンドが使えないらしいので、インストールしておく。が、インストールにはeasy_installを使うらしいのでpython-setuptoolsをインストールしておく。

# yum install python-setuptools
# easy_install mercurial

で、リポジトリからダウンロード

# hg clone -r release https://go.googlecode.com/hg/ $GOROOT
requesting all changes
adding changesets
adding manifests
adding file changes
added 3976 changesets with 16799 changes to 2931 files
updating working directory
1640 files updated, 0 files merged, 0 files removed, 0 files unresolved

Install Go
GoのToolchainはCで書いてるから、gccとかその辺準備しろと。

yum install bison gcc libc6-dev ed

終わったら、マニュアルどおりにやってみる。

# cd go/src
# ./all.bash
〜中略〜
make[2]: Leaving directory `/root/go/src/pkg/os'
--- FAIL: os_test.TestRemoveAll
        RemoveAll "_obj/_TestRemoveAll_" succeeded with chmod 0 subdirectory?(extra *os.PathError=lstat _obj/_TestRemoveAll_: no such file or directory)
FAIL
make[1]: *** [test] エラー 1
make[1]: ディレクトリ `/root/go/src/pkg/os' から出ます
make: *** [os.test] エラー 2

なんてこった。と、調べてみたらあった。
http://code.google.com/p/go/issues/detail?id=22
どうやら、rootディレクトリでは出来ませんよ、てことらしい。ノーマルユーザーでやってくれって書いてるので、一般ユーザーのホームディレクトリで同様の作業を繰り返す。

./all.bash
make.bash: line 41: /home/okt/bin/quietgcc: 許可がありません

ほ、ほわー!?と思ったら、binディレクトリがroot権限になっていたのでchownでユーザ権限に戻しておく。再び繰り返す。

./all.bash
〜中略〜
--- cd ../test
0 known bugs; 0 unexpected bugs

上記のコメントが出ればおkらしい。

Writing programs
コンパイルの仕方。

# 8g hoge.go
# 8l hoge.8

実行

# ./8.out

と言うことらしい。以下原文。
The identifier letters for 386 and arm are ‘8’ and ‘5’. That is, if you were compiling for 386, you would use 8g and the output would be named file.8.
サイトだと6gとかなってるけど、8でやるのがこの環境だと正しいらしい。ソコは適宜。以下サンプルプログラム。
hoge.go

//mainパッケージの宣言?
//Every Go source file declares, 
//using a package statement, 
//which package it's part of.
package main

//Package implementing formatted I/O.
//とあるのでI/O系のフォーマットか?
import "fmt"

func main() {
    //↓注目すべきは、セミコロンが無いこと
    //サンプルでもあったりなかったり
    //どっちでもいいっぽい
    fmt.Printf("hoge, world\n")
}

実行結果

# 8g hoge.go
# 8l hoge.8
# ./8.out
hoge, world

ココまで。

【ただの技術備忘録】【第5回】LinuxC、ソケットプログラミング〜解説編2〜

2.ソケットのアドレス
各ソケットドメインには独自のアドレス形式が必要。故に、ソケットにIPやプロトコルを割り当てる為の構造体が準備されている。AF_INETドメインではnetinet.hで定義されているsockaddr_in構造体を使用する。

#include <netinet/in.h>

struct sockaddr_in {
    short int           sin_family;//ドメイン指定
    unsigned short int  sin_port;//ポート指定
    struct in_addr      sin_addr;//IP指定
};

struct in_addr {
    unsigned long int   s_addr;
};

今回の場合、

server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
server_address.sin_port = 7743;

で、指定している。AF_INET(IPV4)で、IP127.0.0.1のポート7743、というソケット情報を「作成しただけ」の状態。この情報を、1で作ったソケットディスクリプタ命名するのだが、それは次回。厳密に言うとこの指定の仕方は拙いのだが(バイトオーダーの関係で動かない可能性がある)なぁに、かえって免疫がつく。というのは冗談で、一応同じマシンなら動くのでそこらへんは後ほど解説していく。

【ただの技術備忘録】【第6回】LinuxC、ソケットプログラミング〜解説編3〜

3.bind関数でソケットを命名する

socketシステムコールで作成したソケットを、他のプロセスから利用できるようにソケットに命名する。他のプロセスから利用できるようにする、ということはIPやポートなどをソケットに関連付けるわけだが、その基本情報は前回既に作っているので、実際に割り当てるためにbind関数(システムコール)を使う。

#include <sys/socket.h>

int bind(int socket, const struct sockaddr *address, size_t address_len);

名前無しファイルディスクリプタsocketに対して、パラメータaddressを割り当てる。address_lenはアドレス構造体の長さ。パラメータaddressは、実際使用するソケットドメインによってサイズや構造体形式が異なるので、汎用アドレス型のsockaddr構造体にキャストして利用します。

今回は

server_len = sizeof(server_address);
bind(server_sockfd,(struct sockaddr *)&server_address,server_len);

としているので、1で生成したserver_sockfdに対しserver_address構造体を割り当てている。コレにより、server_sockfdはIP127.0.0.1、ポーロ7743として他のプロセスから利用できるようになった。bindシステムコールは、成功すると0を失敗すると-1を返しerrnoにそのエラーの値が格納される。

次回はキューと接続。

【ただの技術備忘録】【第1回】LinuxC、ソケットプログラミング初歩

 諸般の事情によりソケットプログラム初歩を記してみるなど。


 ソケットプログラミングというと何だか小難しく聞こえるが、基本的にはファイルディスクリプタを媒介として入出力を行うだけだ。言い換えるとパイプ処理とプロセス間通信の延長戦に過ぎない。それが理解できればソケットプログラミングは60%終わったようなものだ。後はそれぞれの関数とタイミング、バイトオーダーなどを考慮すれば良いだけである。
 前述のとおりソケットプログラミングでは、ファイルディスクリプタ使用してデータのやり取りを行う。コレは、パイプの概念を拡張し、新たにネットワークの概念を取り入れたもの、という認識で大方間違いはないと思われる。ソケットインターフェースの規格に関してはWindowsSockets(俗称winsock)が有名で、名前から予想が付くとおりWindowsOSで動作する規格である。LinuxUNIXのソケットとやや異なるが、コンセプトは同じなので相互に通信処理を行うことも当然できる。まぁ、そうでないと困るわけだが。
 さて、前口上はこの辺で、実際にソケットプログラミングをするときに行う手順を確認しておく。これはあくまでも概略なのでご配慮願いたい。

  1. ソケットを生成
  2. ソケットに命名
  3. 接続する
  4. 処理
  5. 接続を切る
  6. 消えろソケット!

 実際に作成するときは、接続元と接続先、もっと言えばクライアントとサーバの二つのソケットプログラムを作成する必要があるので注意が必要。最も、引数やオプションでサーバクライアントを分けるように組んでも良いので結局のところ個人の自由である。何を選択するかは各個々人にお任せする。

ここで、多くの書籍やサイトではクライアントプログラムを書き始めるが、僕はサーバ側から組みたいと思う。恐らくクライアントプログラムから始めるのは、処理が少なくプログラムがわかりやすいせいだと思うが、先に受け皿を作ってからのほうが気分的によろしい。

【仕様】
クライアントからサーバに入力された文字を、
一つずらしてサーバからクライアントに返す。
【例】
クライアント入力「A」→サーバ出力「B」

【基本設計】
+使用するIPはlocalhost(ループバックアドレス:127.0.0.1)
+使用するポートは7743(特に意味はない。強いて言えば名無しさん。)
+標準入力は加味せず、ベタの決めうち(エラー処理とか改行処理が面倒なので)

ということで、次回はさくっとプログラムを記載したいと思う。

【ただの技術備忘録】【第2回】LinuxC、ソケットプログラミング初歩

予告どおり、さくっとプログラムを記載。このプログラムは基本的にLinuxGCCで組むので、Widows諸君はWinsockの参考書片手に、概念だけ理解していただけると助かる。

サーバプログラム「server.c」

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

int main (int argc, char *argv[])
{
    //ソケットファイルディスクリプタ
    int server_sockfd, client_sockfd;
    //ソケットサイズ代入用変数
    int server_len, client_len;
    //ソケットの構造体
    struct sockaddr_in server_address;
    struct sockaddr_in client_address;

    //ソケットを生成
    server_sockfd = socket(AF_INET,SOCK_STREAM ,0);

    //ソケット構造体にパラメータを設定
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_address.sin_port = 7743;

    //構造体のサイズを取得
    server_len = sizeof(server_address);

    //ソケットファイルディスクリプタとソケット構造体を結びつけ
    //俗に言う「ソケットに名前をつける」行為だと思う
    bind(server_sockfd,(struct sockaddr *)&server_address,server_len);

    //接続キューを作成する
    //この場合は接続キューを5個作成
    listen(server_sockfd,5);

    //無限ループ
    while(1) {
        //受信用変数、送信用変数
        char recv;
        char send;

        //接続要求を受け入れる
        client_len = sizeof(client_address);
        client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len);

        //なんか処理
        //client_sockfdから受信変数に1バイト読み込み
        //インクリメントして送信変数に代入
        //client_sockfdに送信変数から1バイト書き込み
        read(client_sockfd, &recv,1);
        send = recv+1;
        write(client_sockfd, &send, 1);

        //クライアントソケットを閉じる
        close(client_sockfd);
    }
}

クライアントプログラム「client.c」

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>

int main (int argc, char *argv[])
{
    //ソケットファイルディスクリプタ
    int sockfd;
    //ソケットサイズ代入用変数
    int len;
    //ソケットの構造体
    struct sockaddr_in address;
    //接続結果代入用変数
    int result;
    //受信用変数、送信用変数
    char send = 'a';
    char recv;

    //ソケットを生成
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    //ソケット構造体にパラメータを設定
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr("127.0.0.1");
    address.sin_port = 7743;

    //構造体のサイズを取得
    len = sizeof(address);

    //サーバに接続要求を出す
    //許可されれば接続する
    result = connect(sockfd,(struct sockaddr *) &address, len);

    //接続許可が下りなければ
    //-1が返ってくるのでエラー処理
    if(result == -1) {
        printf("Server connection err\n");
        exit(1);
    }

    //送受信
    write(sockfd,&send,1);
    read(sockfd,&recv,1);

    //受信したものを表示
    printf("Recv:%c\n",recv);

    //接続を閉じる
    close(sockfd);
    return 0;
}

解説は次回。

【ただの技術備忘録】【第3回】LinuxC、ソケットプログラミング初歩

まず、前回のプログラムの実行方法である。
サーバプログラムを「server.c」、クライアントプログラムを「client.c」とした場合に

$ gcc -o server server.c
$ gcc -o client client.c
$ chmod +x server
$ chmod +x client

で、コンパイルが通るはず。
因みにstdlib.hを読み込んでいる理由は、exit関数を使っているから。別にstdlib.hを読み込まなくても使えるが、コンパイル時の警告が気持ち悪いのでつけておく。
さらに前準備として、今回は7743ポートを使用しているのでiptableなど、マシンにFW(ファイアウォール、火壁)を設定している場合は解除しておくのが望ましい。
さて、いざ実行となるが、ターミナルを二個立ち上げるのがなんとなくよろしい。ターミナル1で

$ ./server

を実行し、ターミナル2で

$ ./client

を実行する。その場合、タイムラグ無しで

$ ./client
Recv:b

こうなるはずである。
もし、ターミナルを二個立ち上げられない方は

$ ./server&
$ ./client
Recv:b

コレでもよろしい。


次回、いよいよ解説編。