> ## 10. Telnet

> The library, `Vserial.lib`, implements the telecommunications network interface, known as telnet. The implementation is a telnet-to-serial and serial-to-telnet gateway. This chapter is divided into two parts. The first part describes the library from Dynamic C version 7.05 and later. The second part describes the library prior to 7.05.

> ### 10.1 Telnet (Dynamic C 7.05 and later)

> This implementation is more general than the previous one. Any of the four serial ports can be used and other I/O streams can be added. Multiple connections are supported by the use of unique gateway identifiers.

> #### 10.1.1 Setup

> To use a serial port, the circular buffers must be initialized. For instance, if serial port A is used by an application, then the following macros must be defined in the program:

>     #define AINBUFSIZE   31
>     #define AOUTBUFSIZE  31

> It might be necessary to have bigger buffers for some applications.

> #### 10.1.1.1 Low-level Serial Routines

> A table to hold the low-level I/O routines must be defined as type `VSerialSpec`.

>     typedef struct {
>        int id;           // unique ID to match w/ calls to listen/open
>        int (*open)();   // serial port routines, or
>        int (*close)();  //  serial port compatible routines.
>        int (*tick)();
>        int (*rdUsed)();
>        int (*wrFree)();
>        int (*read)();
>        int (*write)();
>     } VSerialSpec;

> For each serial port (A, B, C and D), there is a pre-defined macro in `VSERIAL.LIB`:

>     #define VSERIAL_PORTA(id) { (id), serAopen, serAclose, NULL, serArdUsed, serAwrFree, serAread, serAwrite }

> The parameter being passed to `VSERIAL_PORTA` is the unique gateway identifier mentioned earlier. This value is chosen by the developer when entries are made to the array of type `VSerialSpec` (also known as the spec table).

> #### 10.1.1.2 Configuration Macros

> #### VSERIAL_DEBUG

> Turns on debug messages.

> #### VSERIAL_NUM_GATEWAYS

> The number of telnet sessions must be defined and must match the number of entries in the spec table.

> #### 10.1.2 Function Reference (Dynamic C 7.05 and later)

> ## vserial_close

>     int vserial_close(int id);

> ### Description

> Closes the specified gateway. This will not only terminate any network activity, but will also close the serial port.

> ### Parameters

> #### id

> ID of the gateway to change, as specified in the spec table.

> ### Return value

> `0`: Success;
> `1`: Failure.

> ### Library

> VSERIAL.LIB

> ## vserial_init

>     int vserial_init ( void );

> ### Description

> Initializes the daemon and parses the spec table.

> ### Return value

> `0`: Success;
> `1`: Failure.

> ### Library

> VSERIAL.LIB

> ## vserial_keepalive

>     int vserial_keepalive ( int id, long timeout );

> ### Description

> This function sets the keepalive timer to generate TCP keepalives after `timeout` periods of inactivity. This helps detect if the connection has gone bad.

> Keepalives should be used at the application level, but if that is not possible, then `timeout` should be set so as to not overload the network. The standard timeout is two hours, and should be set sooner than that only for a Very Good Reason.

> ### Parameters

> #### id

> Unique gateway identifier.

> #### timeout

> Number of seconds of inactivity allowed before a TCP keepalive is sent. A value of 0 shuts off keepalives.

> ### Return value

> `0`: Success;
> `1`: Failure.

> ### Library

> VSERIAL.LIB

> ## vserial_listen

>     int vserial_listen(int id, long baud, int port, long remote_host, int flags);

> ### Description

> Listens on the specified port for a telnet connection. The gateway process is started when a connection request is received. On disconnect, re-listen happens automatically.

> ### Parameters

> #### id

> ID of the gateway to change, as specified in the spec table.

> #### baud

> The parameter to send to the `open()` serial port command; it's usually the baud rate.

> #### port

> The local TCP port to listen on.

> #### remote_host

> The remote host from whom to accept connections, or 0 to accept a connection from anybody.

> #### flags

> Option flags for this gateway. Currently the only valid bit flags are `VSERIAL_COOKED` to strip out telnet control codes, or 0 to leave it a raw data link.

> ### Return value

> `0`: Success;
> `1`: Failure.

> ### Library

> VSERIAL.LIB

> ## vserial_open

>     int vserial_open(int id, long baud, int port, long remote_host, int flags, long retry);

> ### Description

> Opens a connection to a remote host and maintains it, starting the gateway process.

> ### Parameters

> #### id

> ID of the gateway to change, as specified in the spec table.

> #### baud

> The parameter to send to the `open()` serial port command; it's usually the baud rate.

> #### port

> The TCP port on the remote host to connect to.

> #### remote_host

> The remote host to connect to.

> #### flags

> Option flags for this gateway. Currently the only valid bit flags are `VSERIAL_COOKED` to strip out telnet control codes, or 0 to leave it a raw data link.

> #### retry

> The retry timeout, in seconds. When a connection fails, or if the connection was refused, we will wait this number of seconds before retrying.

> ### Return value

> `0`: Success;
> `1`: Failure.

> ### Library

> VSERIAL.LIB

> ## vserial_tick

>     int vserial_tick(void);

> ### Description

> Runs the telnet daemon - must be called periodically.

> ### Return value

> `0`: Success;
> `1`: Failure.

> But call it periodically no matter the return value! An error message can be seen when 1 is returned if you `#define VSERIAL_DEBUG` at the top of your program.

> ### Library

> VSERIAL.LIB

> #### 10.1.3 Sample Program (Dynamic C 7.05 and later)

>     /********************************************************************
>      * vserial.c
>      * This demonstrates the use of the new VSERIAL.LIB, which provides
>      * a gateway between serial ports or serial-port-like devices, and
>      * a telnet-style TCP socket.
>      *******************************************************************/

>     #define MY_IP_ADDRESS  "10.10.6.105"
>     #define MY_NETMASK  "255.255.255.0"
>     #define MY_GATEWAY  "10.10.6.1"

>     /*
>      * Each gateway mapping must be uniquely identified with a number.
>      * Macros are used for code readability.
>      */
>     #define GATEWAY_PORTC 1

>     /*
>      * Serial buffer sizes have to be defined any time the serial ports
>      * are used, because of how RS232.LIB works.
>      */

>     #define CINBUFSIZE  31
>     #define COUTBUFSIZE 31

>     /* Uncomment this to see debug messages */
>     //#define VSERIAL_DEBUG

>     /*
>      * The number of gateways that will be specified. This must match the
>      * number of rows in the VSerialSpecTable that is defined below.
>      */

>     #define VSERIAL_NUM_GATEWAYS 1

>     #use "vserial.lib"

>     /*
>      * This table defines the low-level serial routines used to talk to
>      * the serial port hardware. Each row is one possible hardware
>      * gateway. Because the built-in Rabbit serial ports will be used
>      * often, shortcut-macros are defined for each of the ports, A-D.
>      * They take as a parameter an identifier such that they can be
>      * referenced by the vserial_* functions below.
>      */

>     const VSerialSpec VSerialSpecTable[] = {
>        VSERIAL_PORTC(GATEWAY_PORTC),
>     };

>     main()
>     {
>        sock_init();

>        /* Initilize the vserial library (parse the above structures)*/
>        if(vserial_init()) {
>           printf("Error starting vserial library!\n");
>           exit(-1);
>        }

>        /* Enable our first serial->tcp mapping  */
>        if(vserial_listen(GATEWAY_PORTC,57600,23,0L,VSERIAL_COOKED)) {
>           printf("Error listening!\n");
>           exit(-1);
>        }

>        /*
>         * Force the tcp connection to be persistent. This causes
>         * TCP Keepalives to be sent on the socket periodically. It is
>         * important to note that this can cause a large amount of
>         * network traffic over time.
>         */
>        if(vserial_keepalive(GATEWAY_PORTC,30)) {
>           printf("Error setting keepalive!\n");
>           exit(-1);
>        }

>        /* run it */
>        for(;;) {
>           vserial_tick();
>        }
>     }

> ### 10.2 Telnet (pre-Dynamic C 7.05)

> #### 10.2.1 Configuration Macros

> #### SERIAL_PORT_SPEED

> The baud rate of the serial port. Defaults to 115,200 bps.

> #### TELNET_COOKED

> `#define` this to have telnet control codes stripped out of the data stream (useful if you are actually Telneting to the device from another box; should probably NOT be defined if you are using two devices as a transparent bridge over the Ethernet).

> #### 10.2.2 Function Reference

> ## telnet_init

>     int telnet_init(int which, longword addy, int port);

> ### Description

> Initializes the connection.

> ### Parameters

> #### which

> Is one of the following:

> - `TELNET_LISTEN`--Listens on a port for incoming connections.
> - `TELNET_RECONNECT`--Connects to a remote host, and reconnects if the connection dies.
> - `TELNET_CONNECT`--Connects to a remote host, and terminates if the connection dies.

> #### addy

> IP address of the remote host, or 0 if we are listening.

> #### port

> Port to bind to if we are listening, or the port of the remote host to connect to.

> ### Return value

> `0`: Success;
> `1`: Failure.

> ### Library

> VSERIAL.LIB

> ## telnet_tick

>     int telnet_tick(void);

> ### Description

> Must be called periodically to run the daemon.

> ### Return value

> `0`: Success (call it again);
> `1`: Failure; `TELNET_CONNECT` died, or a fatal error occurred.

> ### Library

> VSERIAL.LIB

> ## telnet_close

>     void telnet_close(void);

> ### Description

> Terminates any connections currently open, and shuts down the daemon.

> ### Library

> VSERIAL.LIB

> #### 10.2.3 An Example Telnet Server

> ####

>     /*
>      * Telnet Server: Listens on a telnet port for a connection, and
>      * transparently passes data on to the serial port
>      */

>     // Initilize the IP address/etc as usual
>     #define MY_IP_ADDRESS "10.10.6.105"
>     #define MY_NETMASK "255.255.255.0"
>     #define MY_GATEWAY "10.10.6.19"
>     #define MY_NAMESERVER "10.10.6.19"

>     #define SERIAL_PORT_SPEED 115200

>     /*
>      * We want RAW data, leaving in any telnet/etc control codes.
>      * (this is a raw data port). #define this to cook the input.
>      */
>     #undef TELNET_COOKED

>     #memmap xmem
>     #use "dcrtcp.lib"
>     #use "vserial.lib"

>     /*
>      * TCP Port to listen on. 0 defaults to normal telnet port
>      */
>     #define SERVER_PORT 0

>     main() {
>        sock_init();  // Init TCP/IP
>        telnet_init(TELNET_LISTEN,0,SERVER_PORT); //Init Vserial server

>        // Loop on telenet_tick() to run server; this is non-blocking
>        while(!telnet_tick())
>             continue;

>        // Error happened, close telnet connection (shouldn't happen)
>        telnet_close();
>     }

> #### 10.2.3.1 A Sample Client To Connect to the Server

>     // Client.c Connects to above server, at given IP address and port

>     #define MY_IP_ADDRESS "10.10.6.105"
>     #define MY_NETMASK "255.255.255.0"
>     #define MY_GATEWAY "10.10.6.19"
>     #define MY_NAMESERVER "10.10.6.19"

>     // Set the speed of the serial port
>     #define SERIAL_PORT_SPEED 115200

>     #undef TELNET_COOKED
>     #memmap xmem
>     #use "dcrtcp.lib"
>     #use "vserial.lib"

>     // TCP Port to connect to. 0 defaults to normal telnet port
>     #define SERVER_PORT 0

>     // Remote IP to connect to.
>     #define REMOTE_HOST "10.10.6.19"

>     main() {
>        sock_init();
>        /*
>         * Init the VSerial server to connect, and reconnect if the
>         * connection is lost
>         */
>        telnet_init(TELNET_RECONNECT,resolve(REMOTE_HOST),SERVER_PORT);

>        // Loop on telenet_tick() to run it; this is non-blocking
>        while(!telnet_tick())
>           continue;

>        // Error happened, we get here - close it (shouldn't happen)
>        telnet_close();
>     }

Z-World http://www.zworld.com Voice: 530.757.3737 Fax: 530.757.3792 or 530.753.5141 sales@zworld.com