〜 ネットワーク 〜
プライベートIPアドレスを取得 (要WSOCK.DLL)

HSPではソケットで通信できるようにするHSPSock.DLLが同梱されていますが、
作成した実行ファイルと共にDLLを一緒に配布する必要があるので、
様々な理由により「なんとかDLLナシで実現できないか」と思う人たちの為の参考Tipsです。

今回のTipsはipgetに代わるサンプルモジュールの紹介で、ホストのIPアドレスを取得を取得します。
取得するには、まずAPIWSAStartupでソケットの初期化を行います。
APIWSAStartupの引数は「ソケットのバージョン」「WSADATA構造体へのポインタ」。
今回は基本機能しか使わないのでソケットのバージョンには1.1を指定します。
指定方法は16ビット値の上位8ビットがマイナー、下位8ビットがメジャーバージョンを示しているので、
「0x0101」を指定しておけばOKです。
WSADATA構造体は以下のようになっている398バイトのもの。
typedef struct WSADATA {
WORDwVersion,// 使用しているWinsockのバージョン
WORDwHighVersion,// 利用可能な最大のバージョン
CHARszDescription[257],// 発売元等、Winsock実装に関する文字列
CHARszSystemStatus[129],// ステータス、構成要素に関する文字列
SHORTiMaxSockets,// 予約
SHORTiMaxUdpDg,// 予約
FARpVendorInfo// ベンダーに関する情報が格納されている構造体等へのポインタ
}
この構造体は枠組みを用意しておくだけで、特に何も設定しておく必要はありません。 関数が成功すると0を返すので、続いてローカルマシンのホスト名を取得するAPIgethostnameを使います。 APIgethostnameに「受取先変数」「変数サイズ」を指定して失敗するとSOCKET_ERROR(=-1)が、 成功すると0が返ると同時に引数にしていた変数にホスト名が格納されるので、 次はその「ホスト名」を引数にしてAPIgethostbynameでホスト情報を取得します。 尚、失敗した時にAPIWSAGetLastErrorを用いることで以下の詳細情報を知ることができます。
定数定数値内容
WSAEFAULT0x271E指定引数は有効なユーザーアドレス空間の一部ではない
WSAEINPROGRESS0x2734ブロッキング呼出が進行しているか、サービスプロバイダーがコールバック関数を処理中
WSAENETDOWN0x2742ネットワークサブシステムが停止している
WSANOTINITIALISED0x276D事前にWSAStartupを成功させておく必要あり
ホスト情報を取得するAPIgethostbynameが失敗するとSOCKET_ERROR(=-1)が返るので、 APIgethostnameと同様にAPIWSAGetLastErrorを用いて以下の詳細情報を確認してください。
定数定数値内容
WSAEINTR0x2714ブロッキング呼出は、WSACancelBlockingCallによってキャンセルされた
WSAEFAULT0x271E指定引数は有効なユーザーアドレス空間の一部ではない
WSAEINPROGRESS0x2734ブロッキング呼出が進行しているか、サービスプロバイダーがコールバック関数を処理中
WSAENETDOWN0x2742ネットワークサブシステムが停止している
WSANOTINITIALISED0x276D事前にWSAStartupを成功させておく必要あり
WSAHOST_NOT_FOUND0x2AF9正式なホスト名が見つからない
WSATRY_AGAIN0x2AFA正式でないホストが見つからないか、サーバーが停止している
WSANO_RECOVERY0x2AFB回復不能なエラーが発生
WSANO_DATA0x2AFCホスト名は有効であるが要求された種類のデータは見つからない
ホスト情報の取得に成功するとホスト情報が入ったhostent構造体のポインタが返るので、 dupptr命令でhostent構造体16バイト分を取り出します。
typedef struct hostent {
FARh_name,// ホストの正式名称
FARh_aliases,// エイリアスリスト
SHORTh_addrtype,// アドレスのタイプ
SHORTh_length,// アドレスの長さ
FARh_addr_list// ホストのアドレスのリスト
}
この中でIP取得に必要なのが12バイト目から4バイト分の上記構造体のh_addr_list部分。 コレには複数入っていることもあることから中にはさらにポインタが入っているので、 再度dupptr命令で、h_addr_listが指し示すアドレスから4バイト分を取り出します。 コレでIPアドレスが取得できますが、 通常我々が設定する「XXX.XXX.XXX.XXX」ではなくコンピュータがわかる形式となっているので、 自分達が理解できる文字列に直すにはAPIinet_ntoaを使います。 ソケット通信が全て終了すれば、最後にAPIWSACleanupを使ってリソースを解放してください。 尚、ローカルアドレスが割り当てられていると自分のマシンだけではグローバルIPは取得できないようです。 解決法の1つとしてコチラに載せてあるので参照してみてください。

sockinit メジャーバージョン, マイナーバージョン
メジャーバージョン初期化するソケットのメジャーバージョンを指定する。
尚、メジャー・マイナーバージョン共に省略した場合は1.1として初期化する。
マイナーバージョン初期化するソケットのマイナーバージョンを指定する。

sockexit
[パラメータなし]ソケットのリソースを解放するだけの為、パラメータは必要ない。
尚、終了時に自動的に呼び出されるので命令を実行する必要はない。

gethost 受取先変数
受取先変数取得したホスト名を受け取る文字列型変数を指定する。

getip 受取先変数
受取先変数取得したIPアドレスを受け取る文字列型変数を指定する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
	ll_libload wsock, "wsock32.dll"
	ll_getproc gethostname, "gethostname", wsock
	ll_getproc gethostbyname, "gethostbyname", wsock
	ll_getproc inet_ntoa, "inet_ntoa", wsock
	ll_getproc WSACleanup, "WSACleanup", wsock
	ll_getproc WSAStartup, "WSAStartup", wsock

#module
#deffunc sockinit int, int
	mref major, 0 : mref minor, 1
	sdim wsa, 398
	if major = 0 & minor = 0 : major = 1 : minor = 1
	prm = major + (minor << 8)
	ll_getptr wsa : ll_ret prm.1
	ll_callfunc prm, 2, WSAStartup@
	return

#deffunc sockexit onexit
	ll_callfnv WSACleanup@
	return

#deffunc gethost val
	if wsa = 0 : sockinit
	mref host, 24
	ll_getptr host : ll_ret prm
	prm.1 = 256
	ll_callfunc prm, 2, gethostname@
	return

#deffunc getip val
	mref rstr, 24
	mref stt, 64
	if host = 0 : gethost host
	ll_getptr host : ll_ret prm
	ll_callfunc prm, 1, gethostbyname@ : ll_ret prm
	ll_peek prm, prm, 16
	wpeek i.0, prm, 12
	wpeek i.1, prm, 14
	prm = i.1 << 16 + i.0
	ll_peek4 prm, prm
	ll_peek4 prm, prm
	ll_callfunc prm, 1, inet_ntoa@ : ll_ret prm
	ll_peek rstr, prm, 256
	return
#global

	sdim info, 128, 2
	gethost info.0
	mes "ホスト名=" + info.0
	getip info.1
	mes "IP=" + info.1
	stop

sockinit メジャーバージョン, マイナーバージョン
メジャーバージョン初期化するソケットのメジャーバージョンを指定する。
尚、メジャー・マイナーバージョン共に省略した場合は1.1として初期化する。
マイナーバージョン初期化するソケットのマイナーバージョンを指定する。

sockexit
[パラメータなし]ソケットのリソースを解放するだけの為、パラメータは必要ない。
尚、終了時に自動的に呼び出されるので命令を実行する必要はない。

ホスト名 = gethost( )
ホスト名取得したホスト名の受取先を指定する。
[パラメータなし]ホスト名を取得するだけの為、パラメータは必要ない。

IP = getip( )
IPIPアドレスの受取先を指定する。
[パラメータなし]IPを取得するだけの為、パラメータは必要ない。。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#uselib "wsock32.dll"
#func	global gethostname "gethostname" var, int
#cfunc	global gethostbyname "gethostbyname" str
#cfunc	global inet_ntoa "inet_ntoa" int
#func	global WSACleanup "WSACleanup"
#func	global WSAStartup "WSAStartup" int, var

#module
#deffunc sockinit int major, int minor, local i
	sdim wsa, 398
	if major = 0 & minor = 0 : i = 1, 1 : else : i = major, minor
	WSAStartup i.0 + (i.1 << 8), wsa
	return

#deffunc sockexit onexit
	WSACleanup
	return

#defcfunc gethost local s
	if wsa = 0 : sockinit
	sdim s, 256
	gethostname s, 256
	return s

#defcfunc getip local i, local s
	dupptr i, gethostbyname(gethost()), 16
	dupptr i, lpeek(i, 12), 4
	dupptr i, i, 4
	dupptr s, inet_ntoa(i), 256, 2
	return s
#global

	mes "ホスト名=" + gethost()
	mes "IP=" + getip()