Screenshot
Introduction
gfxscan is a simple port scanner developed to search for remote computers on LAN running game servers.
It sends simple UDP request asynchronously to all the IPSs on a particular port in a subnet. The port being 27015 in case of counter strike. The response is then parsed to get the details of the server. There are many additional requests which can be made to know more about the game, which I will be posting later.
I tried to find a simple port scanner for LAN and Googled a lot, but didn't find any. So I decided to write my own game server scanner.
Problems Faced
Major problem was to reduce the time wait for a read call. I got rid of it by setting option System::Net::Sockets::SocketOptionName::ReceiveTimeout
as 1000.
sock->SetSocketOption(System::Net::Sockets::SocketOptionLevel::Socket,
System::Net::Sockets::SocketOptionName::ReceiveTimeout,1000);
The blocking nature of a socket can be nulled using sock->set_Blocking(false)
.
Major Code Fragments
- Creating a UDP socket, starting a new thread to read for the response from hosts if found a server, and sending UDP requests to hosts in a subnet:
void scanServers(String* ip[],int prt,int count)
{
boolRead =1;
port = prt;
sock = new Socket(AddressFamily::InterNetwork,
SocketType::Dgram,ProtocolType::Udp);
readThread = new Thread(new ThreadStart(this,read));
readThread->Start();
Byte msg[]= System::Text::Encoding::ASCII->GetBytes("xxxxinfo\0");
Byte msg2[]= new Byte[1000];
msg[0] = 0xff;
msg[1] = 0xff;
msg[2] = 0xff;
msg[3] = 0xff;
for(int i=0;i<count;i++)
{
IPAddress* ipAdd = IPAddress::Parse(ip->GetValue(i)->ToString());
IPEndPoint* endPoint = new IPEndPoint(ipAdd,port);
EndPoint* senderRemote = __try_cast<EndPoint*>(endPoint);
try
{
sock->SendTo(msg, 0, msg->Length, SocketFlags::None, endPoint);
}
catch ( SocketException* se )
{
MessageBoxButtons::OK, MessageBoxIcon::Exclamation);
}
}
}
- Setting the non-blocking and time wait options, reading from hosts on the same socket, decoding the message, and then sending it to display the message correctly:
void read()
{
IPEndPoint* sender = new IPEndPoint(IPAddress::Any, port);
EndPoint* senderRemote = __try_cast<EndPoint*>(sender);
Byte msg2[]= new Byte[1000];
sock->set_Blocking(false);
sock->SetSocketOption(System::Net::Sockets::SocketOptionLevel::Socket,
System::Net::Sockets::SocketOptionName::ReceiveTimeout,1000);
while(boolRead==1)
{
try
{
int iR = sock->ReceiveFrom(msg2, 0, msg2->Length,
SocketFlags::None, &senderRemote);
Char chars[] = new Char[2000];
Decoder* d = Encoding::UTF8->GetDecoder();
int charLen = d->GetChars(msg2, 0, msg2->Length, chars, 0);
String* str = new String(chars);
parseAndAdd(str);
}
catch (SocketException* se)
{
MessageBox::Show(se->Message,"exception while sending",
MessageBoxButtons::OK, MessageBoxIcon::Exclamation);
}
}
this->labelStatus->set_Text(new String("Scan Complete."));
this->labelStatus->Invalidate();
}
I am looking forward to making a class to provide a neat interface to find game servers on LAN, and to ping them for more information of the game, like no. of players, map being played, and status of each player.
Happy Gaming till then :)