In this assignment, you are asked to implement a simulated distributed hierarchical naming system. The system is implemented as a number of cooperating name servers, each of which represents a domain in the overall name space, similar to the Internet Domain Name System (DNS). The naming system resolves names to a corresponding integer numbers. Your task is to implement an appropriate name server and a client that can be used to access the naming system. The server must be capable of performing both iterative and recursive name lookups and further, client and server must be able to handle both corresponding reply types. To keep things simple, all name server and client processes are executed on the same machine.
Each name server is started with a single argument:
server <filename>where <filename> denotes the name of a configuration file. The syntax of the configuration file is specified below. The client is invoked with a single argument:
client <name>where <name> denotes the absolute name that is being looked up in the naming system. An absolute name contains a variable number of edge labels, represented by alpha-numerical strings, separated by a dot. In contrast to the typical DNS notation, labels in a name are ordered from higher to lower layers in the naming hierarchy. Consequently, absolute names start with a dot whereas relative names start with a label.
The server configuration file describes the domain that is being represented by a server, as well as the configuration of the name resolution process. It is an ASCII file that may contain the following types of attributes (an example is given below) and attribute fields:
DOMAIN <name> <transport id> NS <label> <transport id> <flags> ID <label> <entity>Each attribute entry in the configuration begins with one of the keywords DOMAIN, NS or ID and is followed by the attribute fields, each of which is coded as a string (containing alphanumeric characters or dots) and separated by whitespace. Each attribute entry must be written in a separate row of the configuration file. Attribute fields are:
Only a single DOMAIN attribute must be given in any configuration file. The <name> field contains the absolute name prefix of the domain represented by the server. The <transport id> field contains the local transport identifier of this server.
There may be an arbitrary number of NS attributes present in the configuration file. These entries refer to other name servers that can be contacted to obtain information about subdomains. The <label> field contains the edge label of each subdomain while the <transport id> field contains the transport identifier of the respective name server.
There may be an arbitrary number of ID attributes present in the configuration file. These entries provide mappings from an edge label <label> to an entity number <entity>.
The software system consists of a server program and a client program. Multiple processes of the server program are started with different configuration files to represent a name space. Each invocation of the client program performs a single lookup operation and finishes upon reception of a response by printing the entity's id or adequately reporting about a potential lookup failure. You must implement the communication between the client and servers, as well as between servers using a suitable communication protocol on top of TCP or UDP and with the help of indirect transport addressing as described below.
A name server reacts to incoming requests and after carrying out basic checks, first performs an internal lookup on the requested name. If the entry found specifies an entity number (ID), the result is transmitted back to the requester. Otherwise (NS), subsequent actions depend on the flags of the name server entry. If no matching entry can be found, an error code is returned. Each lookup request must generate a response.
The communication protocol must support both iterative and recursive lookups. The details of the communication protocol are left for you to design. If a name server is configured to perform a recursive lookup for a name, it responds with the entity number found for the name. In case of an iterative lookup, a name server responds by referring the requester to the next name server, if necessary. Both server and client programs must be able to accept both types of responses and continue the name resolution in case of an iterative lookup. The server program should write information into a per-process log file which illustrates execution of the name resolution. Explain the format of your logging output in the README file. The server logfile should be named nameServerLog<name>.<number> where <name> is the name of the domain (including the first dot) and <number> is the server's transport identifier, as specified in the DOMAIN attribute in the server's configuration file. The client program must print logging information on standard output.
You should appropriately structure your software to clearly separate communication operations from managing the naming entries, such that the communication mechanisms could be easily replaced by others (such as another transport protocol or RPC). Further, the client and server part of the communication mechanism should be separated to facilitate code reuse between the client and the server program. The name server does not have to be implemented as a concurrent server. It is acceptable to process all incoming requests sequentially.
In reality, at most one name server would execute on a network node and it would have a fixed transport port where it can be contacted. For the assignment, it must be possible to run multiple name server processes and assign fixed transport identifiers to each of them, so that they can be referred to in the configuration file of other servers. Using fixed port numbers may result in a conflict where multiple users on the same machine attempt to use identical port numbers. Because it would be a significant challenge to rely on the availability of certain port numbers during development and testing, the name servers use an additional level of indirection, borrowed from the RPC system that typically exists on every UNIX machine.
Server processes bind their socket(s) to arbitrary port numbers assigned by the operating system and register the resulting port numbers for their transport identifier with a port mapping service (typically called rpcbind process). This mapping service uses two parts, called program number and version number in the RPC system, to identify an actual transport port number. By using a unique identifier as program number (e.g. each student's student ID), the version number can then be used to identify different servers without causing any naming conflict, even if two users use the same numbers to identify server processes on a single machine. Effectively, the used program number (student ID) is globally unique for all servers and clients and the version number is used as transport identifier to distinguish different servers.
A process registers and deregisters a transport port with the port mapping service by using the system functions pmap_set and pmap_unset. A port is looked up by calling pmap_getport. Please see the respective man-pages for details. Example code for C/C++, Java, and Python will be provided on the course web page. Note that on Solaris, port mapping only works, if the process registering the mapping actually has a socket bound to that address (as in the example code). Otherwise, the system automatically removes the mapping later.
IMPORTANT: As a convention, the root server is always assigned transport identifier 1. Therefore, the client program implicitly know how to find the root server to begin the name resolution.
Example for a root configuration file:
DOMAIN . 1 NS xyz 15 I NS abc 19 R ID hello 9999
Example for a domain configuration file for the domain .xyz:
DOMAIN .xyz 15 NS ccc 20 R ID fred 7777 ID mary 8888Given these configuration files, a lookup for .xyz.mary starting at the root server would be resolved through one iterative lookup step. It would result in the number 8888.