2.4 Interacting with a Network Service

The next program begins really interacting with a network service by printing something into the special file. It asks the so-called finger service if a user of the machine is logged in. When testing this program, try to change the variable ‘finger_server’ to some other machine name in your local network:

BEGIN {
  finger_server     = "andrew.cmu.edu"
  finger_connection = "/inet/tcp/0/" finger_server "/finger"
  print "wnace" |& finger_connection
  while ((finger_connection |& getline) > 0)
    print $0
  close(finger_connection)
}

After telling the service on the machine which user to look for, the program repeatedly reads lines that come as a reply. When no more lines are available (because the service has closed the connection), the program also closes the connection. If you tried to replace ‘finger_server’ with some other server name, the script probably reported being unable to open the connection, because most servers today no longer support this service. Try replacing the login name of Professor Nace (wnace) with another login name (like help). You will receive a list of login names similar to the one you asked for. In the 1980s you could get a list of all users currently logged in by asking for an empty string ("").

The final close() call could be safely deleted from the above script, because the operating system closes any open connection by default when a script reaches the end of execution. But, in order to avoid portability problems, it is best to always close connections explicitly. With the Linux kernel, for example, proper closing results in flushing of buffers. Letting the close happen by default may result in discarding buffers.

When looking at /etc/services you may have noticed that the ‘daytime’ service is also available with ‘udp’. In the earlier examples, change ‘tcp’ to ‘udp’ and try if the ‘finger’ and ‘daytime’ clients still work as expected. They probably will not respond because a wise administrator switched off these services. But if they do, you may see the expected day and time message. The program then hangs, because it waits for more lines to come from the service. However, they never do. This behavior is a consequence of the differences between TCP and UDP. When using UDP, neither party is automatically informed about the other closing the connection. Continuing to experiment this way reveals many other subtle differences between TCP and UDP. To avoid such trouble, you should always remember the advice Douglas E. Comer and David Stevens give in Volume III of their series Internetworking With TCP (page 14):

When designing client-server applications, beginners are strongly advised to use TCP because it provides reliable, connection-oriented communication. Programs only use UDP if the application protocol handles reliability, the application requires hardware broadcast or multicast, or the application cannot tolerate virtual circuit overhead.

This advice is actually quite dated and we hesitated to repeat it here. But we left it in because we are still observing beginners running into this pitfall. While this advice has aged quite well, some other ideas from the 1980s have not. The ‘finger’ service may still be available in Microsoft Windows Server 2019, but it turned out to be a never-ending cause of trouble. First of all, it is now obvious that a server should never reveal personal data about its users to anonymous client software that connects over the wild wild Internet. So every server on the Internet should reject ‘finger’ requests (by disabling the port and by disabling the software serving this port). But things got even worse in 2020 when it turned out that even the client software (the ‘finger’ command documented in the link above) is a security problem. A tool called DarkFinger allows to leverage the Microsoft Windows ‘finger.exe’ as a file downloader and help evade network security devices.