This is a Telnet client providing the basic Telnet services. It supports sending and receiving data (asynchronously), and the negotiation of Telnet options, but it does not implement any option.
Wrapper for exceptions that already passed the exception handler.
# | Telnet_data of string
# | Telnet_nop
# | Telnet_dm
# | Telnet_brk
# | Telnet_ip
# | Telnet_ao
# | Telnet_ayt
|(*||are you there?||*)|
# | Telnet_ec
# | Telnet_el
# | Telnet_ga
# | Telnet_sb of char
|(*||Begin of subnegotiation||*)|
# | Telnet_se
|(*||End of subnegotation||*)|
# | Telnet_will of char
|(*||Acknowledges that option is in effect||*)|
# | Telnet_wont of char
|(*||Acknowledges that option is rejected||*)|
# | Telnet_do of char
|(*||Requests to turn on an option||*)|
# | Telnet_dont of char
|(*||Requests to turn off an option||*)|
# | Telnet_unknown of char
# | Telnet_eof
|(*||End of file||*)|
# | Telnet_timeout
telnet_command is the interpretation of the octets in a Telnet
session, i.e. it is one level above the octet stream. See RFC 854
for an explanation what the commands mean.
the data chunks between the commands. Note that you do not need
to double octets having value 255; this is done automatically.
Telnet_unknown represents any command not covered by RFC 854, for
example the End-of-record-mark (introduced in RFC 885) would be
Telnet_eof represents the end of the octet
stream, useable in both directions.
Telnet_timeout is added to the
input queue if I/O has not been happened for the configured period
telnet_options: modifies the behaviour of the client. Do not mix these
options up with the options negotiated with the remote side.
# | Telnet_binary
|(*||see RFC 856||*)|
# | Telnet_echo
|(*||see RFC 857||*)|
# | Telnet_suppress_GA
|(*||see RFC 858||*)|
# | Telnet_status
|(*||see RFC 859||*)|
# | Telnet_timing_mark
|(*||see RFC 860||*)|
# | Telnet_ext_opt_list
|(*||see RFC 861||*)|
# | Telnet_end_of_rec
|(*||see RFC 885||*)|
# | Telnet_window_size
|(*||see RFC 1073||*)|
# | Telnet_term_speed
|(*||see RFC 1079||*)|
# | Telnet_term_type
|(*||see RFC 1091||*)|
# | Telnet_X_display
|(*||see RFC 1096||*)|
# | Telnet_linemode
|(*||see RFC 1184||*)|
# | Telnet_flow_ctrl
|(*||see RFC 1372||*)|
# | Telnet_auth
|(*||see RFC 1416||*)|
# | Telnet_new_environ
|(*||see RFC 1572 and 1571||*)|
# | Telnet_option of int
|(*||all other options||*)|
telnet_negotiated_option: names for the most common options, and
the generic name
Telnet_option for other options.
# | Not_negotiated
# | Accepted
# | Rejected
An option has one of three states:
Not_negotiated: There was no negotiation about the option. This means that the option is turned off (but this client is allowed to reject it explicitly)
Accepted: Both sides have accepted the option.
Rejected: One side has rejected the option. This also means that the option is off, but the client refuses to send further acknoledgements that the option is off (to avoid endless negotiation loops).
Converts the option name to the character representing it on the octet-stream level.
Converts a character representing an option to the internal option name.
# | Telnet_connect of (string * int)
Telnet_connect(host,port): The client connects to this port.
Telnet_socket s: The client uses an already connected socket.
Telnet_socket? Telnet is a symmetrical protocol; client and servers
implement the same protocol features (the only difference is the
environment: a client is typically connected with a real terminal; a server
is connected with a pseudo terminal). This simply means that this
implementation of a client can also be used as a server implementation.
You need only to add code which accepts new connections and which passes
these connections over to a
telnet_session object via
telnet_session object has two queues, one for arriving data,
one for data to send.
Once the session object is attached to an event system, it connects
to the remote peer, and processes the queues. Input is appended to
the input queue; output found on the output queue is sent to the
If input arrives, a callback function is invoked.
You may close the output side of the socket by putting
onto the output queue.
Once the EOF marker has been received, a
Telnet_eof is appended to
the input queue, and the connection is closed (completely). The
session object detaches from the event system automatically in this
Set an input handler as callback function in the session object. The input handler is called when new input data have been arrived. It should inspect the input queue, process the queue as much as possible, and it should remove the processed items from the queue. While processing, it may add new items to the output queue.
If you are not within the callback function and add items to the
output queue, the session object will not detect that there are
new items to send - unless you invoke the
If you want option negotiation, it is the simplest way to use
the special option negotiation methods. Configure the options
as you want (invoking
disable etc), but do not forget
to modify the way input is processed. Every
_dont command must be passed to
Sets the host name and the port of the remote server to contact.
Sets the callback function. This function is called after new commands have been put onto the input queue. The argument passed to the callback function indicates whether a 'Synch' sequence was received from the remote side or not.
Note Synch: If the client sees a data mark command it will assume
that it is actually a Synch sequence. The client automatically
Telnet_data commands from the input queue (but not
Telnet_datas inside subnegotiations). The data mark command
itself remains on the queue.
Sets the exception handler. Every known error condition is
caught and passed to the exception handler.
The exception handler can do whatever it wants to do. If it
raises again an exception, the new exception is always propagated
up to the caller (whoever this is). Often the caller is the
event system scheduler (i.e.
Unixqueue.run); see the documention
If you do not set the exception handler, a default handler is
active. It first resets the session (see method
then wraps the exception into the
and raises this exception again.
The queue of commands to send to the remote side. If you add new
commands to this queue, do not forget to invoke the
method which indicates to the event system that new data to
send is available.
After commands have been sent, they are removed from the queue.
Closes the connection immediately and empties all queues. All negotiated options are reset, too.
The following methods deal with Telnet protocol options. These are negotiated between local and remote side by the Will, Won't, Do and Don't commands.
The "local" options describe the modification of the behaviour
of the local side; the "remote" options describe the modifications
of the remote side. Both set of options are independent.
This object may track the set of accepted and rejected options
if the following methods are used; but this works only if
_dont commands received from
the remote side are processed by
you need to invoke this method for the mentioned commands in
your command interpretation loop.
The idea is: If you enable an option, it is possible to switch it on. If the remote side requests the option to be enabled, the request will be acknowledged. If the remote side does not request the option, it remains off.
You can also actively demand an option (
request_remote_option); this is of course only possible if
the option is already enabled. In this case the client tries
actively to switch it on.
You can also disable an option. If the option is on, the client actively rejects the option; following the Telnet protocol this is always possible (rejections cannot be rejected).
reset methods are somewhat dangerous. They simply reset
the internal state of the client, but do not negotiate. This
possibility was added to allow the Timing Mark option to send
again timing marks even if the previous timing marks have
already been accepted. After
reset, the client thinks the
option was never negotiated; but nothing is done to tell
the remote side about this.
option_negotiation_is_over: true if no option negotiation is
pending (i.e. nothing has still to be acknowledged).
This method should be called as follows:
If you find a
Telnet_sb at the beginning of the input queue,
remove this command
Queue.take, and invoke
This method scans the queue and looks for the associated
Telnet_se command. If it does not find it,
None is returned.
Telnet_se is found, the parameter enclosed by the two commands
is returned as
Some s where
s is the parameter string. Furthermore,
in the latter case the data items and the closing
removed from the queue.
Running the session
Attach to the event system. After being attached, the client is ready to work.
Run the event system
If there are commands in the output queue, the event system is signaled that this client wants to do network I/O.
At the next output oppurtunity, a Synch sequence is sent to the remote peer. This means that the passed commands, extended by an additional Data Mark command, are sent to the peer as urgent data.
Sending a Synch sequence has higher priority than the output queue; processing of the output queue is deferred until the Synch sequence has been completely sent.
Set whether the timeout value is to be applied to the input side
of the connection. This is
true by default.
A telnet session