Jim Lawless' Blog


A TCP Command Line Interface in Rhino JavaScript

Originally published on: Sat, 24 Oct 2009 01:13:27 +0000

Several weeks ago, I introduced the first in a series of posts that will explore various Internet protocols using Rhino JavaScript to create the supporting software.

Please see: http://www.mailsend-online.com/blog?p=40

In this installment, I want to introduce a small utility that we will use at the beginning of many of these posts as an initial testbed before we attempt to write any scripts. We'll call this program tcp_cli.js ( or just tcp_cli ).

In tcp_cli, I intend to do these things:

Since I intend to obtain user input, I need to read from Java's System.in object. Rhino JS already has a print() function, so I thought I'd make a counterpart function called readLine(). I created the readLine() function in a separate library called readline.js. Please see the source code below:


// Provide a function to read from the Java
// standard input object System.in.
//
// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

importPackage(java.io, java.lang);

var stdin=null;

   // We can't reference System.in because "in"
   // is a JS keyword, so we use the brackets to
   // dereference the "in" member of System.
function readLine() {
   if(stdin==null) {
stdin=new BufferedReader(
new InputStreamReader(
System['in']));
   }
   return stdin.readLine();
}

Note that since in is a JavaScript keyword, I had to look up the property 'in' using the square-bracket syntax.

I chose to create a separate thread to monitor the responses we get back from the service to simplify the code at this time. Both of the calls to read data from either the standard console input device or to read data from the socket may block ( or halt processing until a read operation can complete ) which can be a bit unwieldy.

We will effectively have two running threads. One will be polling the service we are conversing with and will display that service's responses. The other thread ( our main thread of execution ) will poll the standard input device and will send those entered strings of text to the service.

Some of you may be asking "Why are you reinventing 'telnet' ?"

Telnet is a TCP terminal client that is often used to perform the kinds of exploratory tasks that I intend to introduce in this series of posts. The only drawback to using telnet as a client is that one must type precisely what one intends to type ... if you backspace over an error to correct it, the entire stream of characters including backspaces is sent to the service.

The service, more often than not, sees the backspace characters as noise and will yield some sort of error message.

By leveraging the console input device for input, we are afforded the luxury of correcting ourselves as we type before we send anything to the server.

An added bonus is that on many operating-systems, you simply have to press the cursor-up key to scroll through strings that you have already entered. One might find it easier to perform repetitive operations by using this feature.

So, to answer the question, I have not recreated telnet; I have created something similar that allows me to more readily send correct data to the given TCP service.

Here is the source code for tcp_cli:

tcp_cli.js


// TCP session interactive command
// prompt client.
//
// License: MIT / X11
// Copyright (c) 2009 by James K. Lawless
// jimbo@radiks.net http://www.radiks.net/~jimbo
// http://www.mailsend-online.com
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

importPackage(java.io,java.lang);

load("tcplib.js");
load("readline.js");

   print("What server do you wish to connect to?");
   server=readLine();
   print("What port do you wish to connect to?");
   port=readLine();

   sock=tcpConnect(server,port);
// Start a thread to monitor the server's responses
var mon = new Runnable() {
run: function () {
         var s;
for(;;) {
            try {
               if(sock.inp.ready()) {
                  s=sock.inp.readLine();
                  print(s);
               }
            }
            catch(e) {
               print("(monitor is ending...)");
               break;
            }
}
}
};

new Thread(mon).start();
  
   
   for(;;) {
      s=readLine();
      if(s=="alldone")
         break;
      tcpSendStringLine(sock,s);
   }
   tcpClose(sock);

This segment of code may look a little strange:


var mon = new Runnable() {
run: function () {
         var s;
for(;;) {
            try {
               if(sock.inp.ready()) {
                  s=sock.inp.readLine();
                  print(s);
               }
            }
            catch(e) {
               print("(monitor is ending...)");
               break;
            }
}
}
};

new Thread(mon).start();

The first line instantiates a new Runnable object. Runnable objects are primarily objects capable of being scheduled by the Java thread-manager. When the thread-manager schedules a Runnable object for execution, it ultimately calls that object's run() method.

We provide a body for the run() method as a JS function. The function loops indefinitely until an exception is thrown. Then, the message (monitor is ending...) is displayed and we drop out of the thread. The monitor thread then ceases execution.

After defining this object, we formally need to instruct the thread-manager to schedule the object for execution. The construction of a Thread object via the new operator followed by a call to that Thread object's start() method schedules the execution.

We then drop into our console input loop.

Let's test tcp_cli with the finger server we constructed in the last post. Start the finger server: java -jar js.jar fingerSrv3.js

In a separate console window, invoke the tcp_cli script: java -jar js.jar tcp_cli.js

You'll be prompted for a server and port. Choose localhost and 79 respectively. A connection will then be made. A blank line will appear. You may type a string to send to the service. Enter 'test' with no quotes and hit ENTER.

Including the early conversation, you should see something like: What server do you wish to connect to? localhost What port do you wish to connect to? 79 test Heya! The time is Fri Oct 23 2009 19:55:21 GMT-0500 (CDT)

In the finger server window you should see something like: test

To terminate tcp_cli enter the string 'alldone' in lower-case with no quotes: alldone

You should then see the "(monitor is ending...)" message.

Now, we have a simple TCP command-line interface. In the next installment, I'd like to explore the POP3 protocol. ( We'll learn how to read inbound Internet mail from a POP3 provider.)

The source tcp_cli.js can be downloaded at: http://www.mailsend-online.com/wp/tcp_cli.zip

Unless otherwise noted, all code and text entries are Copyright ©2009 by James K. Lawless



Views expressed in this blog are those of the author and do not necessary reflect those of the author's employer. Views expressed in the comments are those of the responding individual.

stumbleupon Save to StumbleUpon
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Previous post: Preventing Windows Screen-Saver Activation
Next post:A Data Manipulation Library for TAP


About Jim ...


Click **here**
to try out MailWrench;
a command-line SMTP /
SMTPS (Google Gmail)
mailer for Windows.


Follow me on Twitter

http://twitter.com/lawlessGuy


Recent Posts

A JavaScript REPL for Android Devices

MailSend is Free

My Blog Engine

The October 10th Bug

A Review of Kevin Mitnick's Book Ghost in the Wires

Spellbound by Web Programming

Backlinks to my Blog Posts

Play MP3 Files with Python on Windows


Random Posts

Directory Traversal in Rhino JavaScript

Auto Save Images from the Clipboard

A Simple Associative Array Library in C

Understanding TRS-80 CMD Files

Getting the Windows Console Text Color

WSH JavaScript Includes

Spellbound by Web Programming

E-mail cleansing

Internet Protocols and Rhino JavaScript

Scott Ballantyne: Blazin' Into Forth


Full List of Posts

http://www.mailsend-online.com/bloglist.htm


Recent Posts from my Other Blog

Remembering Dr. San Guinary

Why Some Web Sites will go Dark on Jan 18th

SNL Superhero Skit

More Ruby Games

My Ruby Game Challenge Entry

Steal this Bookmarklet

Nerd Toys

Learn New Jargon, You Must

Spot the Wiebe

Tech Magazine Glory Days

Book Review : Paull Allen - Idea Man

A 90's Experiment in Online Systems - The U.S. West CommunityLink Service