Chapter 8. Using Additional Internet Services

By now we know that Tcl has the functionality to create networked applications. We also know how to build simple client-server communication functionality. However, as with any programming language, being able to plug into existing protocols and communicating using standards that other systems are using is very important. This chapter talks about various standards, how Tcl fits into these (technologies), and how to use Tcl for various types of protocols and data encodings.

We will also talk about communication with users using e-mail. We'll start with sending simple e-mails, followed by learning how to send attachments and multipart types. Using this we'll show how to send and receive e-mails in order to do tasks such as informing users and/or customers. We'll also show how to read e-mails, how to parse them and how simple mechanisms can be built to create an automated e-mail management system.

This chapter also talks about many other protocols that we can use Tcl with. We'll talk about using Lightweight Directory Access Protocol (LDAP) to look up information and/or authenticate users, manually querying host names and time servers.

We'll also show Tcl's comm protocol, which is an RPC mechanism that can be used to invoke remote procedures on same or different machines. We'll show how this can be used both for running commands remotely and locally. We'll also show how we can introduce basic security features and how Tcl can be made to offer limited access to commands.

When writing our applications, it is essential to remember that there are many cases where all network-related functions may throw errors—a network can be down, the server we are communicating with might not be responding or may prevent us from gaining access due to invalid credentials, misconfiguration, or some other reason.

At all stages of writing an application, you should remember to make sure that you handle such errors properly. This is especially important for networked applications. Packages for handling network communication take care of catching such errors. Our application also needs to handle this properly and clean up all resources, inform the user or create a log of such errors—and when it makes sense, the application should retry communication periodically.

Also, when performing checks of any data retrieved from remote systems, we should check if all the conditions are satisfied instead of checking for known problems. For example, we should check if the status is one of the acceptable ones instead of checking if the status is a known error status. Troubleshooting Tcl applications and more recommendations for making applications error prone are described in more details in Chapter 4, Troubleshooting Tcl Applications .

Checking DNS

Tcl can be used to query Domain Name Servers using the dns package. This package allows us to query for various domain-related information. The package is an implementation of the DNS protocol client and it uses the DNS servers configured on the system by default. Although, it can also be configured to use different name servers.

The main command for querying DNS is dns::resolve, which returns a token that can then be used to get results. This command should be invoked with the query as the first argument and all options appended after it. The query can have multiple formats—the first one being the hostname. It can also be specified as dns:<hostname> or dns://<servername>/<hostname> where servername is the name of DNS server sent to the query.

The result from a query can be multiple servers. For example, in order to check the IP addresses of www.google.com, we can do the following:

package require dns
set token [dns::resolve "www.google.com"]

As DNS queries are always asynchronous, we should now wait for the query to finish. The dns::wait command can be run to achieve this and accepts one argument, which is the token that was returned by dns::resolve:

dns::wait $token

It is best to check whether the query has worked or not. Similar to the http package, the dns::status command is used for this. The status can be ok, error, timeout, or eof. For errors, the actual error message can be retrieved using the dns::error command. . For example, we can check if DNS query succeeded by doing:

if {[dns::status $token] != "ok"} {
puts "Problem querying DNS"
exit 1
}

Now we can retrieve IP addresses from the query. We can do this using the dns::address command:

set iplist [dns::address $token]
puts "Google.com IP addresses: [join $iplist ", "]."

Finally, we need to clean all the information related to this query by running:

dns::cleanup $token

Depending on query types, the results can be retrieved using different commands:

  • dns::name—for queries that return hostnames.
  • dns::address—for queries that return addresses.
  • dns::cname—for queries that return canonical names.

    All these commands return a list of results with zero or more entries. The command dns::result can be used to retrieve raw results as Tcl list. In this case each element is a sublist with one or more name-value pairs that can then used for dict command and/or array set.

For example, we can also query DNS servers that serve the google.com domain by doing:

set token [dns::resolve "google.com" -type NS]
dns::wait $token
if {[dns::status $token] == "ok"} {
puts "DNS servers: [join [dns::name $token] ", "]."
}

There are multiple types of queries that can be performed and they map to DNS query types.

Below is a table of commonly used query types:

Type

Result type

Comment

A

dns::address

IP addresses for specified hostname

PTR

dns::name

Reverse DNS (host name from IP address)

NS

dns::name

Name servers that should be asked about specific domains

MX

dns::name

Mail servers that should be used when delivering an e-mail to specified domain; each server specified as<priority> <servername> where lower priority indicates higher precedence

For example, in order to list the mail servers for the gmail.com domain, we can do the following:

set token [dns::resolve "gmail.com" -type MX]
dns::wait $token
if {[dns::status $token] == "ok"} {
set mxlist [dns::name $token]
set mxlist [lsort -index 0 -integer $mxlist]
puts "MX servers:
[join $mxlist 
]"
puts "--"
}

After retrieving the results we can sort them. We are using the fact that the format of MX definitions can be treated as Tcl sublist. We tell lsort to sort the list, treating each element as a sublist and compare using the first element of this sublist, comparing items as integers. Finally, we join the list with each entry being a separate line and print it out.

Using callbacks

By default, DNS queries are asynchronous and we used dns::wait to wait for the results. In order to perform queries using callbacks, we can use the -command option from dns::resolve command. Command is specified as a value for this parameter, Callbacks described will be run with a DNS token appended as additional argument after the query has been performed as specified.

For example, from our previous example we know the IP addresses of all hosts that were resolved for www.google.com. We can now query what names those IP addresses resolve to by running:

set counter [llength $googleiplist]
foreach ip $iplist {
dns::resolve "dns:$ip" 
-type PTR 
-command [list onResolveDone $ip]
}
vwait done

This will cause the onResolveDone command to be run after each IP address is resolved. We've also set counter variable to track how many queries are left—initially being number of IP addresses. The final line enters an event loop in order to avoid exiting the application before our queries are completed.

The command we're invoking will print out the result, decrease the counter, and if it was the last query, exit:

proc onResolveDone {ip token} {
global counter
set name [dns::name $token]
if {[dns::status $token] == "ok"} {
puts "$ip resolves do $name"
} else {
puts "Failed to resolve $ip"
}
dns::cleanup $name
incr counter -1
if {$counter == 0} {exit 0}
}

Note

Examples of querying DNS in Tcl are located in the 01dns directory in the source code examples for this chapter.

More information about the dns package, as well as the remaining configuration options can be found in its documentation at the package's SourceForge project at: http://tcllib.sourceforge.net/doc/dns.html

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.190.156.93