Hello,
I wrote a program a while ago, which browse ID software's Enemy
Territory (ET) game servers around the world to search for online
friends or colleagues or to attempt locating the country of the
server.
It is using UDP sockets and the ET protocol was reverse-engineered
with a sniffer.
"get-servers-list-string" contacts ID Software main server to retrieve
the list of ET servers.
I feel that the solution implemented in get-servers-list-string is not
optimal. Is the function efficient in term of CPU usage? Is there a
different way to wait for input on the stream than the one implemented
in the do iteration?
Thanks!
(defconstant +oob+
(let ((c (code-char 255)))
(format nil "~A~A~A~A" c c c c)))
(defun get-servers-list-string (host port
&key (sleep-time 0.1)
(max-retries 5))
"Get ET servers list from host:port.
Return the unparsed string of hosts if successful"
(with-output-to-string (s)
(let ((str
(sys:make-fd-stream
(connect-to-inet-socket host port :datagram)
:input t :output t :buffering :full)))
(unwind-protect
(progn
(format str "~Agetservers.82.full.empty" +oob+)
(finish-output str)
(let ((retries 0))
(do ((c (read-char-no-hang str nil :eof)
(read-char-no-hang str nil :eof)))
((eql retries max-retries))
(cond (c (format s "~A" c)) ; we have a char. Save it.
(t (sleep sleep-time) ;we do not have a char. Retry
(incf retries))))))
(close str)))
s))
* (get-servers-list-string "etmaster.idsoftware.com" 27950)
=> "����getserversResponse blabla...