Previous Next Contents

6. Demonstrations of how to use SSLtcl

SSLtcl main program is a loadable module SSLtcl.so which can be loaded by tclsh or wish at any time. It then gives the programmer access to an extended version of tcl sockets. If you already know how to use the socket command then read the manual page and get on with it.

If you feel unsure how to use sockets under tcl then have a look in demo. There you find six example programs that utilize sockets with SSL. They show different ways of configuring the socket under tcl.

The tcl socket command is among the most easiest ways to create applications that can communicate over tcp/ip. Its most fundamental aspect is that it either creates a client socket that directly tries to connect to a server. Or it creates a server socket that listens on the specified port and then creates additional sockets for each client that connect so that is can service more than one client at a time.

To get tcl sockets to work in this nice way you have to have it in an event loop and you have to configure the channel the socket is wrapped in so that the program can take back command when it has started serving a client.

The scripts in the demo directory contain different solutions to this problem.

The scripts tstCli.tcl and tstSrv.tcl is two simple scripts that utilize sockets and SSL in an easy way; but with the negative sideffect that the server only will service one client at time.

Lets take a look at tstCli.tcl

    9   set shouldbe [exec cat tstCli.tcl]
    10  load ../SSLtcl.so SSLtcl
    11  
    ...   
    16  set s [socket -ssl -verify 1 -ciphers RC4-MD5 -cert demoCA/newcert.pem -key \

    17  demoCA/newkey.pem -CAfile demoCA/cacert.pem localhost 443]

    18  
    19  puts $s ''GET /''
    20  puts ''Req complete''
    21  flush $s
    22  set got ''''
    23  while { [gets $s l ] >= 0 } {
    24          if { $got == '''' } {
    25                  set got $l
    26          } else {
    27                  set got ''$got\n$l''
    28          }
    29          # puts ''RECV($l)''
    30  }
    31  close $s
    32  puts ''Client done''
    33  if { $got == $shouldbe } {
    34          puts ''Client successful!!!''
    35  } else {
    36          puts ''Bummer!!!  Client did not rec what it should have!''

    37          exit -1;
    38  }
    39  

As you see it loads in SSLtcl.so in line 10. SSLtcl.so is not as is common under C based applications loaded from the best found location. Therefore you have to specify the full path. For example

load /usr/local/lib/SSLtcl.so SSLtcl

tstCli.tcl is a string fall through application. On line 16 it opens a socket and sets certain characteristics of it. Here we make it a client socket which uses SSL. All possible options is used in this example. The application will have its own certificate and will also have a file which contain certificate from Certificate Authorities it trusts. It also tells that it will only tolerate use of a special cipher.

The socket command returns a channel identifier which we now can use to read from and write to.

On line 19-21 the application writes to the socket and flushed the channel so that it really sends something. Because we are using SSL the communication with the server will take place over a cryptated tunnel.

We then go in a loop and wait for something to read on the channel on lone 23-29. When we get something we immediately closes the cannel, as on line 31.

This could be the basis of a webbrowser fetching webpages. That is, for a connectionless protocol.

The server tstSrv.tcl is not that useful for real life problems, because it blocks while servicing clients. But is fairly easy to understand.

     9  set data [exec cat tstCli.tcl]
    10  
    11  # This is the callback procedure that has to be part of the socket call

    12  proc getit { s ip port args } {
    13          global data
    14          puts $args
    15          puts ''Server socket ($s $ip $port)''
    16          set req [gets $s];
    17          puts ''RECV($req)''
    18          if { $req == ''GET /'' } {
    19                  puts $s $data
    20          } else {
    21                  puts ''UNKNOWN request''
    22                  puts $s ''UNKNOWN request''
    23          }
    24          close $s
    25  }
    26  
    27  # load the module, with full path to it
    28  load ../SSLtcl.so SSLtcl
    29  set s [socket -server getit -ssl -Verify 1 -cert \
    30  demoCA/newcert.pem -key demoCA/newkey.pem \
    31  -CAfile demoCA/cacert.pem 443]
    32  puts $s
    33  set tst 0
    34  puts ''Server waiting connection on $s''
    35  
    36  # Go into the eventloop
 37     vwait tst

The main different between the client socket and a server socket is that the application have to enter an event loop. A server program is therefore not as straight a client program. Every server socket has to have a command to call back when a request arrives.

At line 29 the channel is created. As we see we have to tell tcl that wee want a server socket with the switch -server. This option have a necessary argument, namely a callback command.

This is created on line 12-25. When a client connects this client will be handed over to the callback command, in this case a procedure. The procedure is rather straightforward. It read from the channel with gets (line 16). Observe that this is not the same channel as that returned by the socket command, but is a new channel given as a argument to the procedure. It then writes back to the channel with puts $channelid something.

At line 36 we went into an event loop. Nothing would have happen on the socket channel before we did go into that loop because tcl would not know how to handle the callback but would be busy doing other things.

A connections is closed by closing the connection socket. The server socket is closed first when you close the channel you got back from the socket command.

To do something more useful one would like at least the server to be able to respond to more than one client at a time. tstSrvReal is an example of such a client. It is basically build on two callback. One for the server socket to call, and one for every connections socket to call. To get a callback from every socket when it need attention wee have to configure it for that. This is done with the command filevent. At line 36 you can see how it is used in this example.

        9       # server writing back to client
    10  proc getit_fork {s l} {
    11          puts $s $l
    12          flush $s
    13  }
    14  
    15  # the callback from filevent
    16  proc getit_hand {s} {
    17          puts filevent
    18            set l [gets $s]    ;# get the client packet
    19          puts ''got $l''
    20          if {[eof $s]} {    ;# client gone or finished
    21                  close $s        ;# release the servers client channel

    22          } elseif {$l == ''Q''} {
    23                  close $s
    24                  exit
    25          } elseif {$l == ''q''} {
    26                  close $s
    27                  return
    28          } else {
    29                  getit_fork $s $l
    30          }
    31  }
    32  
    33  # The connection callback, called from ssl
    34  proc getit { s ip port args } {
    35          puts ''in getit''
    36          fileevent $s readable [list getit_hand $s]
    37          
    38  
    39          fconfigure $s -buffering line -blocking 0
    40          return
    41          
    42  }
    43  
    44  # load the module
    45  load ../SSLtcl.so SSLtcl
    46  
    47  # create socket, with ssl
    48  set s [socket -server getit -ssl -Verify 1 -cert \
    49  demoCA/newcert.pem -key demoCA/newkey.pem \
    50  -CAfile /home/peter/ssl/demoCA/cacert.pem 443]
    51  puts ''Server waiting connection on $s''
    52  
    53  # Go into the eventloop
  54    vwait events

The main part of the program is rather short. On line 45 to 54 we load the module, creates the socket and goes into the event loop.

But in the callback procedure we give to the -server option we behave differently. There we instead gives a new callback, configures the new channel and returns so that the main program can continue on.

The filevent command is used to get tcl to call a procedure when there is something happening on the cannel. In our case we want is to call the procedure getit_hand when the channel is readable. And we send the new channel as an argument.

We also configure the cannel. Especially useful is to configure it for non blocking mode. If we do not do that the server will not be able to service new client until the first connected has at least send something, which means that a client could easily freeze the whole server.

In the new callback we read in what's in the socket and examine its connect. Useful is to check for End Of File, which is done on line 20 so that we know if the client has disappeared.

The stsCliReal.tcl is based on the same principles that tstSrvReal, that is, we implement an event loop and a callback even in the client. This is particularly good for connections that will be durable.

        9       load ../SSLtcl.so SSLtcl
    10  
    11  #  I'm repeating this a few times to check for 
    12  #  problems that may accumulate like file descriptor not being

    13  #  closed.
    14  proc read_sock {sock} {
    15    set l [gets $sock]
    16          if {[eof $sock]} {
    17                  close $sock
    18                  set eventLoop ''done''
    19          }
    20    puts stdout ''ServerReply:$l''
    21  }
    22  
    23  # Read a line of text from stdin and send it to the echoserver socket,

    24  # on eof stdin closedown the echoserver client socket connection

    25  # this implements sending a message to the Server.
    26  proc read_stdin {wsock} {
    27          global  eventLoop
    28          set l [gets stdin]
    29          puts ''l: $l''
    30          if {[eof stdin]} {
    31                  close $wsock             ;# close the socket client connection

    32                  set eventLoop ''done''     ;# terminate the vwait (eventloop)

    33          } elseif {$l == ''Q''} {
    34                  puts $wsock $l
    35                  close $wsock
    36                  exit
    37          } elseif {$l == ''q''} {
    38                  puts $wsock $l
    39                  close $wsock
    40                  exit
    41          } else {
    42                  puts $wsock $l           ;# send the data to the server

    43    }
    44  }
    45  
    46  # Create the socket and ssl enables it
    47  set s [socket -ssl -verify 1 -ciphers RC4-MD5 -cert demoCA/newcert.pem -key \

    48  demoCA/newkey.pem -CAfile demoCA/cacert.pem localhost 443]

    49  
    50  puts $s
    51  fileevent $s readable [list read_sock $s]
    52  fconfigure $s -buffering line
    53  fileevent stdin readable [list read_stdin $s]
    54  vwait eventLoop
    55  puts ''Finished''

In this we create the socket and then a callback for that socket with filevent on lines 47 and 51. We also creates a callback for standardin. This means that we can type something on the screen at it will be sent to the server. If something is on standardin we read it and sends it to the server. If something is on the socket, we reads it and prints it to the terminal. On line 54 we go into an eventloop by waiting on an event on the variable eventLoop.

The two scripts tstSrvRealNoSSL.tcl and tstCliRealNoSSL.tcl is exactly the same as the above scripts, except that they do not configure the socket for SSL (but it uses the socket command provided by SSLtcl.)


Previous Next Contents