カテゴリー別アーカイブ: Linux

ターミナルに出力する文字に色付けするメモ

ターミナルに出力する文字に色をつけるということを試してみた。

LinuxであったりWindowsであったり他にも色々あるけれど、どの程度互換性があるのか分からないけど、とりあえずCentOS5.4とMacOSX10.6で動作することは確認してる。

Pythonで書くとこんな感じ。

print '\033[32mAAAA\033[0m'

AAAAが緑色で表示される。

\033が、ASCIIコードでESCを表していて、[32mがANSIカラーで緑色を表してる。
[0mはリセットを表しており、[32と[0mで文字を囲むことで、その囲まれた部分だけに色がつき、[0m以降に書く文字には色がつかなくなる。

IRC Server インストール

ローカル環境にテスト用の IRC サーバーを立てたメモ。

OSは CentOS 5.4

インストール

ソースからインストールする。

今回落としてきたのは、こちら
最終更新日時が 31-May-2005 21:42 のやつ。

解凍したら configure する。

configure が終わったら i686-pc-linux-gnu に移動して make する。(そう指示される)

$ wget http://www.ircnet.jp/dist/server/jp-patch/irc2.11.1p1.tgz
$ tar zxvf irc2.11.1p1.tgz
$ cd irc2.11.1p1
$ ./configure --prefix=~/opt/irc2.11.1p1
$ cd i686-pc-linux-gnu/
$ make all
$ make install

自分の環境では何事もなくすんなりいった。

設定

設定ファイルを作成する。

インストール先に etc ディレクトリがあるので、そこに ircd.conf を作成する。

今回はローカル用サーバなので、一番簡単な設定で済ます。

設定ファイルの書き方は、同じインストール先の etc ディレクトリにある ircd.conf.example を参考。

$ cd ~/opt/irc2.11.1p1/etc
$ vi ircd.conf
M:local.host:192.168.11.30:Tokyo:6667:392A
A:HOGE:HOGE<hoge@hoge.com>:Client Server::IRCnet:
P::::6667::
Y:10:90::100:512000:10.2:32.2:
I:::::10::

実行

マシンを起動するときに自動起動・・・とかは考えない。

直接コマンドを叩いて起動する。

$ cd ~/opt/irc2.11.1p1/sbin
$ ./ircd

TCPポート 6667 の開放を忘れずに。

pthread_key + 使い方

pthread_key 周辺の使い方を勉強。
スレッドごとにメモリ領域を確保する仕組み。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
 
static pthread_key_t g_key;
 
// スレッド単位で保持するデータ
struct MyData{
    int count;
    char data;
};
 
static void* thread_call( void *arg )
{
    pthread_t self_id = pthread_self();
    printf( "self_id:%u\n", self_id );
 
    // データがすでに存在するか調査
    struct MyData *p;
    if( pthread_getspecific( g_key ) ){
        printf( "self_id:%u Already exists.", self_id );
        return NULL;
    }
 
    // データ作成
    if( !(p = (struct MyData *)calloc( 1, sizeof(*p) )) ){
        perror( "calloc()" );
        return NULL;
    }
    pthread_setspecific( g_key, p );
    p->count = 0;
    p->data = 'A';
 
    // 本当にスレッド単位で保持されているかテスト
    int i;
    for( i = 0; i < 26; ++i ){
        p = (struct MyData *)(pthread_getspecific( g_key ));
        printf( "self_id:%u id:%u data:%c\n", self_id, p->count++, p->data++ );
        usleep(1000);
    }
    p = (struct MyData *)(pthread_getspecific( g_key ));
    if( p->count == 26 ){
        printf( "self_id:%u success.\n", self_id );
    }
    else{
        printf( "self_id:%u error!!\n", self_id );
    }
 
    // 終了
    free(p);
    pthread_setspecific( g_key, 0 );
}
 
int main()
{
    // pthread key を初期化
    if( pthread_key_create( &g_key, NULL ) ){
        perror( "pthread_key_create()" );
        return 0;
    }
 
    // スレッドを複数作成。
    const int TNUM = 3;
    pthread_t tid[TNUM];
    int i;
    for( i = 0; i < TNUM; ++i ){
        if( pthread_create( &tid[i], NULL, thread_call, NULL ) ){
            perror( "pthread_create()" );
            continue;
        }
        printf( "Created a thread. id:%u\n", tid[i] );
    }
 
    // 全スレッドが終了するのを待機。
    for( i = 0; i < TNUM; ++i ){
        pthread_join( tid[i], NULL );
    }
 
    // pthread key を削除
    pthread_key_delete( g_key );    
    return 0;
}

実行

$ gcc main.c -lpthread
$ ./a.out
Created a thread. id:663552
Created a thread. id:2625536
Created a thread. id:3162112
self_id:663552
self_id:2625536
self_id:3162112
self_id:663552 id:0 data:A
self_id:2625536 id:0 data:A
self_id:3162112 id:0 data:A
self_id:663552 id:1 data:B
self_id:2625536 id:1 data:B
...
self_id:2625536 id:25 data:Z
self_id:663552 success.
self_id:3162112 id:25 data:Z
self_id:2625536 success.
self_id:3162112 success.

send と recv と送信バッファ溢れ

send と recv の使い方と送信バッファ溢れについて。

manpage

Manpage of SEND
Manpage of RECV

SEND

non-blocking の場合。
send が失敗して外部変数 errno に EINTR が設定されている場合は、再度送信を試みる必要がある。
データをソケットの送信バッファに入れることが出来ない場合、外部変数 errno に EAGAIN か EWOULDBLOCK が設定される。
いつデータが送信できるようになるかを知るために select などのシステムコールを使うことが出来る。(後述:送信バッファ溢れ)

以下、ソースコードから抜粋した send のサンプル。

int res = 0;
char* p = buffer; // 送るデータ
size_t len = buffer_size; // 送るデータのサイズ
while( len > 0 ){
    while( true ){
        res = send( socket, p, len, MSG_DONTWAIT ); // 一度に全部送れるとは限らない
        if( errno != EINTR ) break; // システム割り込みチェック
    }
    if( res < 0 ){
        if( errno == EAGAIN ||
            errno == EWOULDBLOCK ){
            // 書き込めない状態。それなりの対応が必要(後述:送信バッファ溢れ)
        }
        else{
            // なんらかのエラー(コネクション切断とか)
        }
    }
    len -= res;
    p += res;
}

RECV

non-blocking の場合。
操作が停止するような場合、外部変数 errno に EAGAIN か EWOULDBLOCK が設定される。

以下、ソースコードから抜粋した recv のサンプル。

int res = 0;
while( true ){
    res = recv( socket, buffer, buffer_size, MSG_DONTWAIT );
    if( errno != EINTR ) break;
}
if( res == 0 ){
    // EOF
}
 
if( res < 0 ){
    if( errno == EAGAIN ||
        errno == EWOULDBLOCK ){
        // not ready yet.
    }
    else{
        // error.
    }
}

送信バッファ溢れ

データ送信時に送信バッファが溢れてしまった場合、書き込み可能なタイミングを見計らって、溢れたデータを再送信してあげる必要がある。
送信バッファが溢れたとき、send 関数は失敗し、errno に EAGAIN, EWOULDBLOCK を格納する。
対策として例えば、送信データをキューなり可変長バッファなりで一時的に保持し、select などで書き込み可能になるタイミングを監視して、再送信する方法がある。

サンプル:sendbuffer-overflow
事前に libevent をインストールしておく必要あり。
動作環境 Linux のみ。(送信バッファと受信バッファの数値を linux/sockios.h 使って確認してる為)
1.サーバは受信時に3秒間待機する。
2.クライアントはサーバへデータを送信しまくり、EAGAIN or EWOULDBLOCK を発生させる。
3.エラー発生後、クライアントは書き込み可能イベントを監視し、検知したらデータを再送信する。
2ー3の動作を繰り返し、サーバに規定のデータ(0 – 499 までの連番)が全部届いたら成功。

インストール

$ git clone http://github.com/utahta/sendbuffer-overflow.git
$ cd sendbuffer-overflow
$ ./configure --prefix=/path/to/sendbuffer-overflow --with-libevent=/path/to/libevent
$ make
$ make install

実行

コマンドプロンプトをふたつ立ち上げ、1つめにサーバを起動します。

$ /path/to/sendbuffer-overflow/bin/sbt_server

2つめにクライアントを起動します。

$ /path/to/sendbuffer-overflow/bin/sbt_client

手元では、以下のような結果になりました。

$ /path/to/sendbuffer-overflow/bin/sbt_server
connected. sd:7
recv buffer size:274 sd:7
waiting 3 sec.
... 省略
message received. sd:7 str:abcdefghijklnmopqrstuvwxyz:495
message received. sd:7 str:abcdefghijklnmopqrstuvwxyz:496
message received. sd:7 str:abcdefghijklnmopqrstuvwxyz:497
message received. sd:7 str:abcdefghijklnmopqrstuvwxyz:498
message received. sd:7 str:abcdefghijklnmopqrstuvwxyz:499 // 499 まで届いた
$ /path/to/sendbuffer-overflow/bin/sbt_client
send buffer size. :50436
... 省略
send buffer size:48498 res:0 sd:6
send buffer size:48772 res:0 sd:6
send buffer size:49046 res:0 sd:6
not ready yet: Resource temporarily unavailable // 書き込み失敗
send buffer size:49152 res:-10 sd:6
not ready yet: Resource temporarily unavailable
send buffer size:49152 res:-10 sd:6
... 省略
resend buffer size:88558 res:0 sd:6 // 書き込み可能になったので再送信

このサンプルでは、可変長処理をさぼってあらかじめ大きなバッファを確保してごまかしてたり。
終了処理に手抜きがあったり。(delete してなかったり)
とりあえずサンプルということで。

Net-SNMP

下書きで放置していたSNMPに関するメモ。

インストール

Net-SNMPからソースをダウンロード。

$ tar zxvf net-snmp-5.4.2.1.tar.gz
$ cd net-snmp-5.4.2.1
$ ./configure --prefix=/usr/local/net-snmp-5.4.2.1 --disable-embedded-perl --without-perl-modules
 ************** Configuration Section **************
-Press return to continue-
Default version of SNMP to use (3):
System Contact Information (@):
System Location (Unknown):
Location to write logfile (/var/log/snmpd.log):
Location to write persistent information (/var/net-snmp):
$ make
# make install

必要であれば、エイリアスを設定。

$ cd /usr/local
# ln -s net-snmp-5.4.2.1 net-snmp

SNMP設定

# vi /usr/local/net-snmp/snmpd.conf
... 以下、設定内容。
com2sec hogetest 192.168.11.0/24 hogetest_com
com2sec hogetest localhost hogetest_com
 
group hogetest_grp v1 hogetest
 
view hogetest_view included .1.3.6.1.4.1.2021
 
access hogetest_grp "" any noauth exact hogetest_view none none
 
exec writetest /usr/local/net-snmp/a.sh
...

アクセスサンプル用のテキスト

# vi /usr/local/net-snmp/a.sh
/bin/echo aaa

起動

# snmpd -Lsd -Lf /var/log/snmpd.log -p /var/run/snmpd -a

-Lsd : syslogを有効にする
-Lf : snmpdの出力を送るファイル名の指定
-p : ファイル名 プロセスIDを保存するファイル名
-a : 送信元IPアドレス(NMS)をログに記録する

OIDを取得

英文字の形(OID = name)

$ ./snmpwalk -OQS -c hogetest_com -v 1 localhost .1.3.6.1.4.1.2021.8.1.extNames | grep writetest

数値の形(OID = name)

$ ./snmpwalk -OQSn -c hogetest_com -v 1 localhost .1.3.6.1.4.1.2021.8.1.extNames | grep writetest

値(exec)を取得

$ ./snmpget -c hogetest_com -v 1 localhost UCD-SNMP-MIB::extOutput.1
UCD-SNMP-MIB::extOutput.1 = STRING: aaa
$ ./snmpget -OQv -c hogetest_com -v 1 localhost UCD-SNMP-MIB::extOutput.1
aaa

参考

NET-SNMPのインストール
SNMPによるネットワークシステムの監視
SNMPによるネットワークモニタリング