1 // query Doom2D:Forever master server
2 module dfmsq
is aliced
;
10 enum NET_MSG_LIST
= "\xca"; // 202
14 char[256] ipstr
= 0; // [0] is length
16 char[256] namestr
= 0; // [0] is length
17 char[256] mapstr
= 0; // [0] is length
24 @property const(char)[] ip () const pure nothrow @trusted @nogc { pragma(inline
, true); return ipstr
.ptr
[1..1+cast(ubyte)ipstr
.ptr
[0]]; }
25 @property const(char)[] name () const pure nothrow @trusted @nogc { pragma(inline
, true); return namestr
.ptr
[1..1+cast(ubyte)namestr
.ptr
[0]]; }
26 @property const(char)[] map () const pure nothrow @trusted @nogc { pragma(inline
, true); return mapstr
.ptr
[1..1+cast(ubyte)mapstr
.ptr
[0]]; }
28 const(ubyte)[] parse (const(ubyte)[] data
) {
29 if (data
.length
< 10) throw new Exception("out of data");
32 if (data
.length
< 1) throw new Exception("out of data");
33 ubyte res
= data
.ptr
[0];
39 if (data
.length
< 2) throw new Exception("out of data");
40 ushort res
= cast(ushort)(data
.ptr
[0]|
(data
.ptr
[1]<<16));
45 void getstr (char[] st
) {
48 st
[0] = cast(char)len
;
50 if (data
.length
< len
) throw new Exception("out of data");
51 st
[1..1+len
] = (cast(const(char)[])data
)[0..len
];
69 @property string
mode () const pure nothrow @trusted @nogc {
71 case 0: return "unknown";
75 case 4: return "COOP";
76 case 5: return "SINGLE";
77 default: return "invalid";
82 writeln(name
, " at ", ip
, ":", port
, ", map ", map
, "; mode: ", mode
, "; players: ", players
, " of ", maxplayers
, "; version is ", protover
, "; protected: ", haspass
);
87 ENetPeer
*connectToServer (ENetHost
* client
) {
92 enet_address_set_host(&address
, "mpms.doom2d.org");
94 // Initiate the connection, allocating the two channels 0 and 1.
95 peer
= enet_host_connect(client
, &address
, 2, 0);
96 if (peer
is null) throw new Exception("No available peers for initiating an ENet connection.");
98 // wait up to 5 seconds for the connection attempt to succeed.
99 if (enet_host_service(client
, &event
, 5000) > 0 && event
.type
== ENET_EVENT_TYPE_CONNECT
) {
103 // either the 5 seconds are up or a disconnect event was received
104 // reset the peer in the event the 5 seconds had run out without any significant event
105 enet_peer_reset(peer
);
110 void runClient (bool compress
) {
111 auto client
= enet_host_create(
112 null, // create a client host
113 1, // only allow 1 outgoing connection
114 2, // allow up 2 channels to be used, 0 and 1
115 57600/8, // 56K modem with 56 Kbps downstream bandwidth
116 14400/8, // 56K modem with 14 Kbps upstream bandwidth
118 if (client
is null) throw new Exception("An error occurred while trying to create an ENet client host.");
119 scope(exit
) enet_host_destroy(client
);
120 if (compress
) enet_host_compress_with_range_coder(client
);
122 writeln("connecting to server...");
123 auto peer
= connectToServer(client
);
125 writeln("connection failed!");
129 // create a reliable packet of size 1 with query
130 auto packet
= enet_packet_create(NET_MSG_LIST
.ptr
, 1, ENET_PACKET_FLAG_RELIABLE|ENET_PACKET_FLAG_NO_ALLOCATE
);
132 // Send the packet to the peer
133 enet_peer_send(peer
, NET_CH_MAIN
, packet
);
137 // wait up to 1000 milliseconds for an event
138 while (enet_host_service(client
, &event
, 1000) > 0) {
139 switch (event
.type
) {
140 case ENET_EVENT_TYPE_CONNECT
:
142 writefln("WTF?! A new client connected from %s:%s.", event
.peer
.address
.host
, event
.peer
.address
.port
);
143 // store any relevant client information here
144 //event.peer.data = "Client information\0".dup.ptr;
145 enet_peer_reset(event
.peer
);
147 case ENET_EVENT_TYPE_RECEIVE
:
148 //writefln("A packet of length %s was received on channel %s.", event.packet.dataLength, event.channelID);
150 scope(exit
) enet_packet_destroy(event
.packet
);
151 //write(" ["); for (int f = 0; f < event.packet.dataLength; ++f) write(cast(char)event.packet.data[f]); write("]\n");
152 // clean up the packet now that we're done using it
153 auto data
= cast(const(ubyte)[])(event
.packet
.data
[0..event
.packet
.dataLength
]);
154 if (data
.length
< 2) {
155 writeln(" ERROR: received packed too small");
158 if (data
[0] != cast(ubyte)NET_MSG_LIST
[0]) {
159 writeln(" ERROR: invalid reply received");
163 writeln("server count: ", count
);
166 foreach (immutable sidx
; 0..count
) {
168 data
= si
.parse(data
);
171 } catch (Exception e
) {
172 writeln("FATAL: invalid packed received!");
176 enet_peer_disconnect_later(peer
, 0);
178 case ENET_EVENT_TYPE_DISCONNECT
:
179 writefln("disconnected.");
180 // reset the peer's client information
181 event
.peer
.data
= null;
191 void main (string
[] args
) {
192 enum compress
= false;
193 if (enet_initialize() != 0) throw new Exception("An error occurred while initializing ENet.");
194 scope(exit
) enet_deinitialize();