TWSNMP FC:Wake On LANに対応 途中
一昨日、フィードバックに要望のあったWake On LANのパケットの送信に対応する方法を調べました。
まずは旧バージョンのTWSNMPのソースコードを読んでみました。
BOOL CWolSock::DoWol(CString szMacAddr,CString szIP)
{
if( szMacAddr.IsEmpty() ) return(FALSE);
unsigned int cMacAddr[6];
int c = sscanf_s(szMacAddr,"%x:%x:%x:%x:%x:%x",&cMacAddr[0],&cMacAddr[1],&cMacAddr[2],&cMacAddr[3],&cMacAddr[4],&cMacAddr[5]);
if( c!= 6 ) return(FALSE);
if(!Create(0,SOCK_DGRAM,0)) return(FALSE);
BOOL bBcst = TRUE;
SetSockOpt(SO_BROADCAST,&bBcst,sizeof(BOOL));
SOCKADDR_IN sa;
sa.sin_family = AF_INET;
sa.sin_addr.S_un.S_addr = inet_addr(szIP);
sa.sin_port = htons(WOL_PORT);
if( !Connect((SOCKADDR*)&sa,sizeof(SOCKADDR_IN)))return(FALSE);
char TxBuf[17*6];
int k =0;
for(int i = 0; i < 17;i++ ) {
for(int j =0; j < 6;j++ ) {
if( i == 0 ) {
TxBuf[k++] = (char)0xff;
} else {
TxBuf[k++] = (char) cMacAddr[j];
}
}
}
return(Send(TxBuf,sizeof(TxBuf))== sizeof(TxBuf));
}
VC++で書くとこんな感じです。解説すると0xffを6回、6バイトのMACアドレスを16回ならべたパケットをUDPでブロードキャストしています。たぶん20年近く前に作ったものです。
最近はどうなっているかGO言語で作ったサンプルを探してみました。
ありました。
2019年なので最近の仕様と思って大丈夫そうです。
やっていることは私が作ったものとだいたい同じでした。ここまでが昨日の夜の話です。
今朝は早く試したくて4時に起きて開発を始めました。すぐにコードを書こうと思いましたが作ってもテストする対象(電源をいれるPC)がないことに気づきました。そこから2時間、苦戦苦闘です。
テスト用のVaioのBIOS画面を見ましたがWake On LANの設定がありません。
Mac OSでも試してみましたが簡単にはいきません。
VaioにインストールしたLinux環境(Debian)でできないか調べました。
https://wiki.debian.org/WakeOnLan
でできそうです。
試してみましたが電源OFFからだと起動できません。
サスペンドからだと起動はできました。でも使っているVaioが古いためかOSが元の状態に戻りません。マジックパケットに反応はしているので、この問題を調べるはのは後にしました。
他にWireSharkでパケットキャプチャーすれば確認できました。
調べたことを元にGO言語でプログラムを作ってみました。
func SendWakeOnLanPacket(mac string) error {
ra, err := net.ResolveUDPAddr("udp4", "255.255.255.255:9")
if err != nil {
return err
}
la, err := net.ResolveUDPAddr("udp4", ":0")
if err != nil {
return err
}
c, err := net.DialUDP("udp4", la, ra)
if err != nil {
return err
}
defer c.Close()
hw, err := net.ParseMAC(mac)
if err != nil {
return err
}
packet := []byte{}
prefix := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
packet = append(packet, prefix...)
for i := 0; i < 16; i++ {
packet = append(packet, hw...)
}
_, err = c.Write(packet)
return err
}
です。スッキリ書けていると思います。テストコードも書いてみました。
func TestWol(t *testing.T) {
err := SendWakeOnLanPacket("78:84:3c:2a:ac:08")
if err != nil {
t.Fatal(err)
}
}
です。実行するとちゃんとWake On LAN(WOL)のパケットを送信しています。
ここまで実施したところで時間切れです。明日、メニューから送信できるようにしようと思います。
明日に続く