[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 |