@node net, stream, main, Top
@comment  node-name,  next,  previous,  up
@chapter net

@menu
* connection.c::                
* accept_connection.c::         
* access.c::                    
* init.c::                      
* util::                        
@end menu

@node connection.c, accept_connection.c, net, net
@comment  node-name,  next,  previous,  up
@section ./client/connection.c

@defun new_connection
@cartouche
@example
STREAM * new_connection (
char* @var{hostname}, int @var{ip}, 
short @var{port}, int (*func)( ), 
void* @var{work}
);
@end example
@end cartouche

@heading 説明
@example
@var{hostname} : 接続先サーバ名
@var{ip} : 接続先サーバアドレス（@var{hostname}=0 のときのみ有効）
@var{port} : 接続先ポート
@var{func} : ギャーベージコレクション対応関数
@var{work} : ギャーベージコレクションワークエリア
@end example

@sp 1

接続先サーバを与えて、TCP コネクションを張る。


@heading リターンデータ
接続に失敗すると、-1, 成功すると、サーバとのストリームのディスクリプタを返す。

@heading 詳細
@var{hostname}を指定すると、指定されたサーバの@var{port}へつながる。@var{hostname}=0 とすると、@var{ip} に指定された@var{ip}アドレスのサーバに接続される。
接続に時間がかかっているときにかかる、ギャーベージコレクション要求に対応する必要がある。要求の対応処理を行う関数と、対応処理に必要なワークエリアをnew_connection を呼び出す側が用意し、それぞれ、func, work にセットする。new_connection はしかるべき時にこの関数を呼び出せばよい。
長くかかる可能性がある処理の両側を以下のように囲って下さい。

@sp 1

@example
if ( func )
     (*func)(0,work);

[長くかかる処理。]
if ( func )
     (*func)(1,work);
@end example

@sp 1

このようにすれば、[長くかかる処理] の間で、ギャーベージコレクション要求が発生した場合に対応が可能になります。

@heading 履歴
@table @samp
@item 02/4/12 
最後のconnect システムコールを呼んでいるところで、if(errno == EINTR) でリトライするコードが抜けていました。ごくまれに、インタラプトが掛かり、エラーリターンしてしまいます。Windows/Mac ではシグナルの扱いがUNIX とは異なっていると思いますが、この点も注意してください。
@item 02/11/07 
UNIX の機種依存部分の関数、src/machine/std/net/client/connection.c におけるnew_connection にて、EISCONN (すでにコネクションが張られている) というエラーが返ることが分かったので、この場合、問題ないということで、先へ処理を進めるように変更しました。このエラーが発生する原因は、connect にて、EINTRの発生が、Solaris のOS のなかで、不可分処理になっていないためと思われます。
@end table
@end defun

@node accept_connection.c, access.c, connection.c, net
@comment  node-name,  next,  previous,  up
@section ./server/accept_connection.c

@defun accept_connection
@cartouche
@example
#include "server.h"
ACCESS_KEY *
accept_connection(STREAM * @var{sd});
@end example
@end cartouche

@heading 説明

@example
@var{sd}: 接続待ちを行うソケットのディスクリプタ
@end example

init server で初期化した接続待ちソケットを指定し、クライアントから接続が来るのを待つ。接続が来た場合、そのアクセスキーを返す。

@heading リターンデータ
接続に成功すると、対応するストリームのアクセスキーが返る。失敗すると、0 が返る。
@heading 詳細
リターンするアクセスキーの構造体は以下の構造になっている。

@example
typedef access_key @{
    STREAM * @var{s};  /*　
    int @var{ip};      /* クライアントのip アドレス*/
    void * @var{work}; /* = 0 */
@} ACCESS_KEY;
@end example
@end defun


@node access.c, init.c, accept_connection.c, net
@comment  node-name,  next,  previous,  up
@section ./server/access.c

@defun check_permission
@cartouche
@example
#include "server.h"
int
check_permission(ACCESS_PERMISSION * @var{ap},int @var{ip});
@end example
@end cartouche

@heading 説明
@example
@var{ap} : アクセスパーミッションリスト
@var{ip} : ipアドレス
@end example
与えられたipアドレスのパーミッションを返す。

@heading リターンデータ
@example
AP_ALLOW : ip は許可
AP_DENY  : ip は不許可
@end example
それ以外の値はなし。

@heading 詳細
与えられたipアドレスがマッチする設定を@var{ap}のリストの先頭からチェックしていく。マッチした時、その許可・不許可を返す。どれにもマッチしなかった場合は、不許可を返す。
@end defun


@defun free_access_list
@cartouche
@example
void
free_access_list(ACCESS_PERMISSION * @var{ap})
@end example
@end cartouche

@heading 説明
@example
@var{ap}: アクセスパーミッションリスト
@end example

@end defun



@defun init_access_permission
@cartouche
@example
#include "server.h"
void
init_access_permission(ACCESS_PERMISSION * @var{ap})
@end example
@end cartouche

@heading 説明
access permission チェックのための構造体を初期化する。

@heading リターンデータ
ごみ

@heading 詳細
@example
init_access_permission(ACCESS_PERMISSION * @var{ap})
@{
ap->head = ap->tail = 0;
@}
@end example

@end defun



@defun insert_access_list
@cartouche
@example
#include "server.h"
void
insert_access_list(
    ACCESS_PERMISSION * @var{ap},
    int @var{ip},
    int @var{mask},
    char * @var{domain},
    int @var{type}
);
@end example
@end cartouche

@heading 説明
@example
@var{ap}          : アクセスパーミッションのリスト
@var{ip}          : 対象ipアドレス
@var{mask}        : 対象ipアドレスのマスク
@var{domain}      : 対象
ドメイン@var{type}: 許可・不許可
@end example

@sp 1

@var{ip},@var{mask},@var{domain} で与えられるアドレスのクライアント、あるいはクライアントのグループに対して、アクセスの許可・不許可の設定をap で示されるアクセスパーミッションリストの最後に挿入する。

@heading リターンデータ
ごみ

@heading 詳細
このコードは機種依存ではない。そのまま使える。
ip = 0, domain = 0 の場合、インターネット上のすべてのクライアントが対象となる。@var{ip},@var{mask} にアドレスが指定されている場合、@var{domain} は無視され、このアドレスをもったクライアント、クライアントのグループに対して、許可・不許可を設定する。
@var{ip} = 0 で@var{domain} にクライアント名やドメイン名が設定されていると、これに対して、許可、不許可を与える。
@var{type} の値は、

@example
AP_ALLOW = 1
AP_DENY = 0
@end example

@sp 1

の二種類。server.h で定義されている。以上の設定を、@var{ap} に示されるリストの後ろに発行された順番に追加していく。check_permission では、このリストを前から順番に検索するので、アドレスが重複している場合は、最初に発行されたinsert_access_list がより強いと言える。

@end defun


@node init.c, util, access.c, net
@comment  node-name,  next,  previous,  up
@section ./server/init.c


@defun close_key
@cartouche
@example
#include "server.h"
int
close_key(ACCESS_KEY * @var{key});
@end example
@end cartouche

@heading 説明
@example
@var{key} :アクセスキー
@end example

アクセスキーで示されるストリームをクローズし、アクセスキーも解放する。

@heading リターンデータ
ごみ

@heading 詳細
ACCESS KEY の詳細は、accept_connection の項にある。

@end defun


@defun init_server
@cartouche
@example
#include "server.h"
int
init_server(int @var{base_port},int @var{limit});
@end example
@end cartouche

@heading 説明
@example
@var{base_port}: ポート番号
@var{limit}    : 使用するポート数
@end example

@heading リターンデータ
待ちソケットのディスクリプタ

@heading 詳細
base_port で接続待ちのソケットのポート番号を指定する。base_port がとれなかったときには、待ちポート番号をインクリメントしていく。@var{limit} - 1 回インクリメントしても、ポートがとれなかった場合にはエラーとなる。エラーしたら、プログラムそのものを終了する。
@var{limit} の指定は、プログラムのデバグ時に、異常終了した場合、そのプログラムの使っていたポートがなかなか使用可能にならないOS に対応するために用意された。しかし、solaris では、そのような現象はないため@var{limit} = 1 のみの対応でも差し支えない。

@end defun


@node util,  , init.c, net
@comment  node-name,  next,  previous,  up
@section net/util 履歴


@table @samp
@item 01/10/20
@heading gethostbyname, gethostbyaddr をリエントラントなシステムコールに
これらは、UNIX ではリエントラントではなかった。
リエントラントなシステムコールに変更したものを、

@example
src/machine/net/utils/*_r.c
@end example

に用意した。各ファイルには、*_rr という関数が定義されている。これが、バッファを用意しリエントラントなシステムコールを行う仕組み。確保されたバッファは最後にset buRer、時間がたつと自動的に解放される仕組みにしたウィンドウズのシステムコールがリエントラントであったら、上記ファイルのシステムコールをそれに置き換えてください日文研の一部サーバでは、gethostbyname、gethostbyaddr がネームDB を参照できないことがまれに発生しますこれがバグによるものなのか、ネットワークの異常なのか現在わかっていません参照できない場合、時間をおいて参照すると再び参照できるようになります今のところ、gethostbyname_rr / gethostbyaddr_rr を参照する場合、結果が返ってこなかった場合、時間をおいて参照する処理が入っています
リエントラント処理を行っても、sethostent endhostent 処理はリエントラントではありません。従って、これを使ってネームDB を参照する場合、前後をnetutils lock でロックする必要があります
@end table
