[plt-scheme] telnet client in scheme

From: Toon (camden at camden.be)
Date: Wed Jun 4 20:03:56 EDT 2003

Here's a simple client I've written to make chatprogs and stuff...
The client starts to try to connect to a server from the moment you ask
your client to connect, on failure he automatically tries to connect
again...
Use (client 'disconnect) to disconnect or stop the attempt...

Hope it will help you with wathever you wanted to do... It works totally
the same as telnet anyway...

Greetz.
toon

Usage:

(define client (create-basic-client <inputmanager>)) => inputmanager could
be display, anyway a proc with 1 var
(client 'set-ip "<ip-address>")
(client 'set-port <port>)
(client 'connect)

then use

(client "<msg>") to write to server => When you work graphical the msg will
be a string anyway, so this
                                                          is the easiest way
...


the basic-client code:

(define (create-basic-client inputmanager)
  (letrec [;;ServerIP

           (ip #f)

           ;;Serverport

           (port #f)

           ;;Inputport

           (input #f)

           ;;Outputport

           (output #f)

           ;;Are you currently trying to connect to server?

           (trying-to-connect? #f)

           ;;The reading-thread

           (return-loop-thread #f)

           ;;Connecting to server

           (connect (lambda ()
                      (if (and (not input) (not output) ip port)
                          (set! return-loop-thread (thread (lambda ()

(error-display-handler connection-error-manager)
                                                             (set!
trying-to-connect? #t)

(call-with-values
                                                              (lambda ()
(tcp-connect ip port))
                                                              (lambda
(inputport outputport)
                                                                (set! input
inputport)
                                                                (set! output
outputport)))
                                                             (set!
trying-to-connect? #f)

(return-loop)))))))

           ;;Disconnecting from server

           (disconnect (lambda (reconnect?)
                         (if return-loop-thread
                             (begin
                               (if (output-port? output)
                                   (close-output-port output))
                               (if (input-port? input)
                                   (close-input-port input))
                               (set! input #f)
                               (set! output #f)
                               (if reconnect?
                                   (read-me 'connect)
                                   (begin
                                     (kill-thread return-loop-thread)
                                     (set! return-loop-thread #f)))))))

           ;;Reading servermsg's and sending them to the inputmanager

           (return-loop (lambda ()
                          (let [(data (read-line input))]
                            (if (eof-object? data)
                                (begin
                                  (inputmanager "DISCONNECTED")
                                  (read-me 'disconnect 'reconnect))
                                (begin
                                  (inputmanager (car (split data "\r")))
                                  (return-loop))))))

           ;;Automatically reconnecting on failure while trying to connect

           (connection-error-manager (lambda (string struct)
                                       (if trying-to-connect?
                                           (begin
                                             (set! input #f)
                                             (set! output #f)
                                             (read-me 'connect)))))

           ;;Abstractions of the ADT and server-output-manager

           (read-me (lambda (m . args)
                      (case m
                        ((connect) (connect))
                        ((disconnect) (disconnect (pair? args)))
                        ((set-ip) (if (not (null? args)) (set! ip (car
args))))
                        ((set-port) (if (not (null? args)) (set! port (car
args))))
                        ((delete-ip) (set! ip #f))
                        ((delete-port) (set! port #f))
                        (else (if (and output (string? m))
                                  (display (string-append m "\r\n") output)
                                  #f)))))]
    read-me))
----- Original Message ----- 
From: "Neil W. Van Dyke" <neil at neilvandyke.org>
To: "Chris" <chris81 at wanadoo.fr>
Cc: "ml plt scheme" <plt-scheme at qua.cs.brown.edu>
Sent: Wednesday, June 04, 2003 1:47 PM
Subject: Re: [plt-scheme] telnet client in scheme


>   For list-related administrative tasks:
>   http://list.cs.brown.edu/mailman/listinfo/plt-scheme
>
> Chris <chris81 at wanadoo.fr> writes at 12:13 04-Jun-2003 +0200:
> > I just want to know if a client telnet made in scheme allready exist and
>
> One might exist (I don't know), but writing your own is a really good
> learning exercise.
>
> > and it's send me nothing back but i see the connexion opened in the
telnetd
> > log. Am I missing something ?
>
> Perhaps the Telnet server is not sending a full line; for example, maybe
> it's just sending "Password: " without a newline sequence.  Or maybe
> it's using a nonstandard newline convention, like CR (PLT's "read-line"
> can be made to handle this, but there's a better way).
>
> Instead of using "read-line", you probably want your code to read single
> characters or blocks of characters, rather than waiting for the server
> to send a newline.  You will need this for other parts of the protocol
> anyway.  Here's a simple variation on the code you posted:
>
>     (display "*DEBUG* Connecting...\n")
>
>     (define-values (p-in p-out) (tcp-connect "host" 23))
>
>     (display "*DEBUG* Connected.\n")
>
>     (let loop ()
>       (display "*DEBUG* Waiting for character...\n")
>       (let ((c (read-char p-in)))
>         (printf "*DEBUG* Read character: ~S\n" c)
>         (loop)))
>
> If this code doesn't read any characters from your Telnet server, then
> it could be waiting for the client to send one or more newlines or it
> could be waiting for the client to initiate a cryptographic
> authentication.  Don't think too hard about "*DEBUG*" messages that
> aren't appearing, since they might be stuck in unflushed I/O buffers.
> Try running a protocol sniffer or packet analyzer, like the free
> Ethereal, while you connect to your Telnet server with your system's
> Telnet client, to see how it works.
>
> Once you can read and write single characters with your Telnet server,
> take a look at the PLT procedures "read-string-avail!/enable-break" and
> "write-string-avail/enable-break", and "object-wait-multiple" for how to
> do this robustly and more efficiently.
>
> Searching for "telnet" from "http://www.rfc-editor.org/rfcsearch.html"
> yields over 100 documents, most of which are not relevant to you.  RFC
> 318 ("ftp://ftp.rfc-editor.org/in-notes/rfc318.txt") might be a good
> starting point.
>
> -- 
>                                              http://www.neilvandyke.org/




Posted on the users mailing list.