[BlueLeaf1336]> PROGRAM> WinSock勉強会>
history | TOP |
2002/12/02:作成
T**Ent | TOP |
これまでに、THostEntに関する関数を使ってきたので、WinSock.pasにある似たような構造体についても、考えてみることにする。 で、TNetEnt(PNetEnt)、TServEnt(PServEnt)、TProtoEnt(PProtoEnt) の3つが見つかる。宣言はこんな感じ。
type PNetEnt = ^TNetEnt; {$EXTERNALSYM netent} netent = record n_name: PChar; n_aliases: ^PChar; n_addrtype: Smallint; n_net: u_long; end; TNetEnt = netent;
あんまり情報がないが、わかる範囲で。Joint Endeavour of Delphi Innovators (Project JEDI)にあったらしいWinSock2.pasのコメントを参考に。
type PServEnt = ^TServEnt; {$EXTERNALSYM servent} servent = record s_name: PChar; s_aliases: ^PChar; s_port: Word; s_proto: PChar; end; TServEnt = servent;
コピー〜あんまり情報がないが、わかる範囲で。
type PProtoEnt = ^TProtoEnt; {$EXTERNALSYM protoent} protoent = record p_name: PChar; p_aliases: ^Pchar; p_proto: Smallint; end; TProtoEnt = protoent;
コピー(2)〜あんまり情報がないが、わかる範囲で。
何がなんだか。ただ、THostEntに名前も構造も似ているので、おんなじような関数があるはず。例によって、WinSock.pasより、次のようなものが見つかった。 ただし、TNetEntに関しては、それらしきものが見つからず、いったい何者なのか不明だ。
{$EXTERNALSYM getservbyport} function getservbyport(port: Integer; proto: PChar): PServEnt; stdcall;
{$EXTERNALSYM getservbyname} function getservbyname(name, proto: PChar): PServEnt; stdcall;
{$EXTERNALSYM getprotobynumber} function getprotobynumber(proto: Integer): PProtoEnt; stdcall;
{$EXTERNALSYM getprotobyname} function getprotobyname(name: PChar): PProtoEnt; stdcall;
getprotobyname | TOP |
とりあえず、いけそうなところから攻めていこう。最初は、getprotobyname。なぜかというと、FTPってのを知っている。FileTransferProtocolの略のはず。 つまり、
getprotobyname('FTP')で、何かよさそうなものが返ってくる感じがする。やってみよう。こんな感じ。 基本的には、THostEntでやったのと同じ内容。
function ProtoAliases(ProtoEntry: PProtoEnt): string; type PPChar=^PChar; var ppc: PPChar; begin Result := ''; ppc := PPChar(ProtoEntry^.p_aliases); while assigned(ppc^) do begin Result := Result + ',' + ppc^; inc(ppc); end; Result := Copy(Result, 2, MaxInt); end; procedure TForm1.Button7Click(Sender: TObject); var ProtoEntry: PProtoEnt; ProtoName : string; begin ProtoName := 'FTP'; ProtoEntry := getprotobyname(PChar(ProtoName)); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('p_name:' + ProtoEntry^.p_name); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('p_aliases:' + ProtoAliases(ProtoEntry)); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('p_proto:' + IntToStr(ProtoEntry^.p_proto)); ShowMessage(SysErrorMessage(WSAGetLastError)); end;
...だめだ。「要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。」が出た。getprotobynameの実行直後のWSAGetLastErrorが吐いたエラーだ。
困ったときのWinSock。「Proto」で検索してみると...
const { Protocols } {$EXTERNALSYM IPPROTO_TCP} IPPROTO_TCP = 6; { tcp }
他にもあるが、こんな感じの定数宣言が並んでいるところがあった。この中には、「FTP」はない。「TCP」で試してみよう。...来た。 Button7Clickのbeginの次行をいろいろ変更した結果をまとめて見る。 と、その前に、さっき見つけた定数宣言はこんなの。
const { Protocols } {$EXTERNALSYM IPPROTO_IP} IPPROTO_IP = 0; { dummy for IP } {$EXTERNALSYM IPPROTO_ICMP} IPPROTO_ICMP = 1; { control message protocol } {$EXTERNALSYM IPPROTO_IGMP} IPPROTO_IGMP = 2; { group management protocol } {$EXTERNALSYM IPPROTO_GGP} IPPROTO_GGP = 3; { gateway^2 (deprecated) } {$EXTERNALSYM IPPROTO_TCP} IPPROTO_TCP = 6; { tcp } {$EXTERNALSYM IPPROTO_PUP} IPPROTO_PUP = 12; { pup } {$EXTERNALSYM IPPROTO_UDP} IPPROTO_UDP = 17; { user datagram protocol } {$EXTERNALSYM IPPROTO_IDP} IPPROTO_IDP = 22; { xns idp } {$EXTERNALSYM IPPROTO_ND} IPPROTO_ND = 77; { UNOFFICIAL net disk proto } {$EXTERNALSYM IPPROTO_RAW} IPPROTO_RAW = 255; { raw IP packet } {$EXTERNALSYM IPPROTO_MAX} IPPROTO_MAX = 256;多分、コレの、IPPROTO_をどけた部分が、プロトコル名称になると読んだ。では行ってみよう。
name: PChar | p_name | p_aliases | p_proto | 予想値 |
---|---|---|---|---|
IP | ip | IP | 0 | 0 |
ICMP | icmp | ICMP | 1 | 1 |
IGMP | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | 2 | ||
GGP | ggp | GGP | 3 | 3 |
TCP | tcp | TCP | 6 | 6 |
PUP | pup | PUP | 12 | 12 |
UDP | udp | UDP | 17 | 17 |
IDP | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | 22 | ||
ND | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | 77 | ||
RAW | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | 255 | ||
MAX | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | 256 |
うーん。これ以上突っ込みようがない。まあ、過半数は予想通りなので、よしとしよう。
getprotobynumber | TOP |
しかし、この関数とこの定数宣言に関連があるとわかったことで、getprotobynumberについても突破口が開いた。それに、今度の関数は、定数宣言から勝手に想像した名称ではなく、宣言そのものを使えばよいに決まっているので、さっきエラーが出たやつらの正式名称もわかるはず。行ってみよう。 こんな感じで。
procedure TForm1.Button8Click(Sender: TObject); var ProtoEntry: PProtoEnt; begin ProtoEntry := getprotobynumber(IPPROTO_IP); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('p_name:' + ProtoEntry^.p_name); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('p_aliases:' + ProtoAliases(ProtoEntry)); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('p_proto:' + IntToStr(ProtoEntry^.p_proto)); ShowMessage(SysErrorMessage(WSAGetLastError)); end;
基本的には、さっきとおんなじ。getprotobynumberの引数を、変えた結果がコレ。
proto: Integer | p_name | p_aliases | p_proto |
---|---|---|---|
IPPROTO_IP | ip | IP | 0 |
IPPROTO_ICMP | icmp | ICMP | 1 |
IPPROTO_IGMP | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | ||
IPPROTO_GGP | ggp | GGP | 3 |
IPPROTO_TCP | tcp | TCP | 6 |
IPPROTO_PUP | pup | PUP | 12 |
IPPROTO_UDP | udp | UDP | 17 |
IPPROTO_IDP | xns-idp | XNS-IDP | 22 |
IPPROTO_ND | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | ||
IPPROTO_RAW | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | ||
IPPROTO_MAX | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 |
さっきだめで、今回いけたのはxns-idpだけ。残りはやっぱりだめ。 ということは、WinSock1.1ではだめなんだろうか。わからんけどここまでにしておこう。 あ。getprotobyname(PChar('xns-idp'))は試しておこう。...予想通り。
次へいこう。
getservbyport/getservbyname | TOP |
あと残ってるのは、getservbyportとgetservbynameだが、 なんとなく、さっきとおんなじような定数宣言があると見た。WinSock.pasを検索。
const { Port/socket numbers: network standard functions} {$EXTERNALSYM IPPORT_ECHO} IPPORT_ECHO = 7; {$EXTERNALSYM IPPORT_DISCARD} IPPORT_DISCARD = 9; {$EXTERNALSYM IPPORT_SYSTAT} IPPORT_SYSTAT = 11; {$EXTERNALSYM IPPORT_DAYTIME} IPPORT_DAYTIME = 13; {$EXTERNALSYM IPPORT_NETSTAT} IPPORT_NETSTAT = 15; {$EXTERNALSYM IPPORT_FTP} IPPORT_FTP = 21; {$EXTERNALSYM IPPORT_TELNET} IPPORT_TELNET = 23; {$EXTERNALSYM IPPORT_SMTP} IPPORT_SMTP = 25; {$EXTERNALSYM IPPORT_TIMESERVER} IPPORT_TIMESERVER = 37; {$EXTERNALSYM IPPORT_NAMESERVER} IPPORT_NAMESERVER = 42; {$EXTERNALSYM IPPORT_WHOIS} IPPORT_WHOIS = 43; {$EXTERNALSYM IPPORT_MTP} IPPORT_MTP = 57;
const { Port/socket numbers: host specific functions } {$EXTERNALSYM IPPORT_TFTP} IPPORT_TFTP = 69; {$EXTERNALSYM IPPORT_RJE} IPPORT_RJE = 77; {$EXTERNALSYM IPPORT_FINGER} IPPORT_FINGER = 79; {$EXTERNALSYM IPPORT_TTYLINK} IPPORT_TTYLINK = 87; {$EXTERNALSYM IPPORT_SUPDUP} IPPORT_SUPDUP = 95;
const { UNIX TCP sockets } {$EXTERNALSYM IPPORT_EXECSERVER} IPPORT_EXECSERVER = 512; {$EXTERNALSYM IPPORT_LOGINSERVER} IPPORT_LOGINSERVER = 513; {$EXTERNALSYM IPPORT_CMDSERVER} IPPORT_CMDSERVER = 514; {$EXTERNALSYM IPPORT_EFSSERVER} IPPORT_EFSSERVER = 520;
const { UNIX UDP sockets } {$EXTERNALSYM IPPORT_BIFFUDP} IPPORT_BIFFUDP = 512; {$EXTERNALSYM IPPORT_WHOSERVER} IPPORT_WHOSERVER = 513; {$EXTERNALSYM IPPORT_ROUTESERVER} IPPORT_ROUTESERVER = 520;
const { Ports < IPPORT_RESERVED are reserved for privileged processes (e.g. root). } {$EXTERNALSYM IPPORT_RESERVED} IPPORT_RESERVED = 1024;
あほみたいにあった。IPPORT_で始まる定数宣言。コレを使っていってみよう。とりあえず。getservbyportから。と、あっさり思ったが、いきなり壁だ。 portは、間違いなく、上のIPPORT_**だろう。 protoのほうは、その前にやったIPPROTO_**の**の部分だろう。 って、いったいどれだけの組み合わせがあんねん。
ただ、1024かその辺までは、Well Known Portとして予約済みです。 みたいな記述を読んだことがある。それでやってみよう。こんな感じで。 の前に、portとprotoの組み合わせをまとめておこう。
いかん。違う。ポートとサービスが大体決められてるだけで、ポートとプロトコルはまた別の話ちゃうの?うーん。全パターン行ってみようか。 ただ、さっきプロトコル名称が最後まで取れなかったのは無視で。
というわけで組み合わせ表はコレ。
port: Integer | proto: PChar | ||||||
---|---|---|---|---|---|---|---|
IPPORT_ECHO(7) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_DISCARD(9) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_SYSTAT(11) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_DAYTIME(13) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_NETSTAT(15) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_FTP(21) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_TELNET(23) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_SMTP(25) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_TIMESERVER(37) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_NAMESERVER(42) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_WHOIS(43) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_MTP(57) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_TFTP(69) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_RJE(77) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_FINGER(79) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_TTYLINK(87) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_SUPDUP(95) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_EXECSERVER(512) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_LOGINSERVER(513) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_CMDSERVER(514) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_EFSSERVER(520) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_BIFFUDP(512) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_WHOSERVER(513) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_ROUTESERVER(520) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
IPPORT_RESERVED(1024) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
量が見えたほうがやる気になるかと思ったら、余計やる気がなくなってしまった。 まあ、適当に。こんな感じで。
procedure TForm1.Button9Click(Sender: TObject); var ServEntry: PServEnt; ProtoName: string; begin ProtoName := 'ip'; // ProtoName := RadioGroup1.Items.Names[RadioGroup1.ItemIndex]; ServEntry := getservbyport(IPPORT_ECHO, PChar(ProtoName)); ShowMessage(SysErrorMessage(WSAGetLastError)); if ServEntry = nil then Exit; ShowMessage('s_name:' + ServEntry^.s_name); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('s_aliases:' + ServAliases(ServEntry)); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('s_port:' + IntToStr(ServEntry^.s_port)); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('s_proto:' + ServEntry^.s_proto); ShowMessage(SysErrorMessage(WSAGetLastError)); end;
get***は、失敗すると、nilが返るらしいので、判定行をやっと追加してみた。コレを使って、全組み合わせを試してみよう。
表の最初から10個ほど試したけど、全部「要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。」 今思えば、このコンピュータ、サービスなんてなーんも開始してないんじゃないのか?ひょっとして。意味ないやん。
となると、多分getservbynameも同じだ。きっと。 しかも、さっきの結果を使って、サービスの正式名称を取得しようと思ってたのに、だめになったおかげで、名称に何を書けばよいのやら。多分、(今度こそ)「FTP」とかなんだろうけど、どうせサービス動いてないし確かめようもねーよ。
ま、やるとしたらこんな感じか。の前に、組み合わせ表だ。さっきの役立たずの表にほぼ同じ。
name: PChar | proto: PChar | ||||||
---|---|---|---|---|---|---|---|
ECHO(7) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
DISCARD(9) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
SYSTAT(11) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
DAYTIME(13) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
NETSTAT(15) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
FTP(21) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
TELNET(23) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
SMTP(25) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
TIMESERVER(37) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
NAMESERVER(42) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
WHOIS(43) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
MTP(57) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
TFTP(69) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
RJE(77) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
FINGER(79) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
TTYLINK(87) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
SUPDUP(95) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
EXECSERVER(512) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
LOGINSERVER(513) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
CMDSERVER(514) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
EFSSERVER(520) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
BIFFUDP(512) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
WHOSERVER(513) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
ROUTESERVER(520) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
RESERVED(1024) | ip | icmp | ggp | tcp | pup | udp | xns-idp |
で、こんな感じのコードで。
procedure TForm1.Button10Click(Sender: TObject); var ServEntry: PServEnt; ProtoName: string; begin ProtoName := 'ip'; // ProtoName := RadioGroup1.Items.Names[RadioGroup1.ItemIndex]; ServEntry := getservbyname(PChar('TELNET'), PChar(ProtoName)); ShowMessage(SysErrorMessage(WSAGetLastError)); if ServEntry = nil then Exit; ShowMessage('s_name:' + ServEntry^.s_name); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('s_aliases:' + ServAliases(ServEntry)); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('s_port:' + IntToStr(ServEntry^.s_port)); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage('s_proto:' + ServEntry^.s_proto); ShowMessage(SysErrorMessage(WSAGetLastError)); end;
...なに?。かえってきたで。答えが。もうコレで終わりにしようと思ってたのに。
しかし、あれだね。定数の宣言が、IPPORT_**にもかかわらず、全パターン試そうっても抜けとるな。proto=ip限定じゃないのか?
いやいや。それも含めて勉強会だ。というわけで、エラーにならなかった結果を挙げる。いやいや。さっきのprotoを変えても同じだ。組み合わせる必要なし。
name: PChar | s_name | s_aliases | s_port | s_proto |
---|---|---|---|---|
ECHO | echo | ''(空欄) | 1792 | tcp |
DISCARD | discard | sink,null | 2304 | tcp |
SYSTAT | systat | users | 2816 | tcp |
DAYTIME | daytime | ''(空欄) | 3328 | tcp |
NETSTAT | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
FTP | ftp | ''(空欄) | 5376 | tcp |
TELNET | telnet | ''(空欄) | 5888 | tcp |
SMTP | smtp | 6400 | tcp | |
TIMESERVER | timed | timeserver | 3330 | udp |
NAMESERVER | nameserver | name | 10752 | tcp |
WHOIS | nicname | whois | 11008 | tcp |
MTP | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
TFTP | tftp | ''(空欄) | 17664 | udp |
RJE | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
FINGER | finger | ''(空欄) | 20224 | tcp |
TTYLINK | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
SUPDUP | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
EXECSERVER | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
LOGINSERVER | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
CMDSERVER | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
EFSSERVER | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
BIFFUDP | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
WHOSERVER | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
ROUTESERVER | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 | |||
RESERVED | 要求した名前は有効で、データベースにありますが、解決された正しい関連データがありません。 |
結局半分近くエラーだった。全部書かんでよかった。 しかし、なんと言うか、ひょっとして知らんところで動いてるのか?たとえば、TELNET。そんなことないと思うけど。どうなんだろう。
しかし、こういう組み合わせ対決するときは、もっと考えて楽なようにテストコード作るべきだ。コーディングが楽なのは、あとがしんどくて仕方がない。しかし、進まんな。
今日はここまで。
EOF | TOP |