Group 1, G1
Team members: Haye Chan,
haye@cs.cornell.eduTeam 4 – Directory Service
What did I set out to do?
My part of work is Directory Service. The project is about building a telephony network on Internet to enable computers to talk to the phones. Among all other key components, directory service sits at the central piece of the whole project. It is the centralized database that stores information about users and provides information retrieval as well as various lookups.
Users of directory service fall into a wide range. Those include the signaling component that sits on the Gateway, the signaling component that sits on each workstation, the fax gateway, the voice/email gateway, the multi-party conferencing server and client. See the following diagram for its user distribution.
Since this is such a central piece of the network system, it has to have the following features:
Features
Things to note
Since I am providing interface for people to use, there are several things that I need to pay attention to.
The ideal case is we formulate a set of interface at the beginning and don’t ever change it. This is important considering the understanding of the system we have at the beginning. I know the interface has to be changed some time later. My goal would be to minimize the troubles caused to other teams. This could only be achieved by doing work earlier than other people do. We have to be able to somewhat finalize the interface before anybody starting to figure out how to use directory service. We have to finish at least the core features before anybody starts testing their code. Furthermore, upgrading of directory service versions has to be treated with great caution in order not to cause tremendous inconvenience and confusion to other teams.
In addition, we would be the best team to implement the data structures (classes) that are used across the system. We would need to implement abstract data types such as Name, Address, Digits, NameList and FullName.
Due to the nature of directory service, we have to deal with many teams. We have to talk to them as early as possible and collect the features that they would need.
Schedule
Date |
Checkpoint |
10/19 |
Get BIND to work |
10/26 |
Revise the interface |
11/2 |
Provide dummy testing code for interface to let other groups begin testing |
11/16 |
Get our server to work |
11/30 |
Finish the basic features and add additional features |
12/7 |
Declare bug-free |
I am very proud to report that, since I have carefully drafted the initial schedule, I have always been able to meet the deadlines, while the above is exactly the schedule that I submitted in Report 1. Although there are numerous difficulties arising in the middle of development, I have been able to cope with them and managed to keep in line with the schedule.
What did I actually accomplish?
I provided a version of local directory service for people to test their code individually without having the trouble of sharing a centralized database. After I finished implementing the centralized version of database, I carefully upgraded it, while retaining the old version as a package with a slightly different name.
I chose to integrate BIND into our project as our directory service. I made this decision based on the following reasons:
The decision turns out to be fairly correct, though not without pain. A fair amount of time was spent on hacking into bind query and update code since the query and especially update message format is not well specified.
Integrating BIND
I looked at all the resource record formats and picked the TXT record. This is a very flexible record format that allows me to store arbitrary string. I thus store the user record in this format:
<name> IN TXT "Ext=00001;Address=cs519g1.csuglab.cornell.edu:50444;....."
This makes the resource record well extensible and could store any fields.
After several hours of fiddling with BIND, I finally got it up and running.
Writing the Stub code
I wrote the core part of the stub in C. The C-stub contains functions for doing query and update. I then use Java Native Interface to call the C functions from Java. Since a large portion of the core C code is ported from BIND directly, the performance is very satisfactory, even after the Java and record parsing overhead. The caching effect is obvious, as the second lookup is significant faster than the first one. I’m not running hierarchical server, and I don’t quite understand where the caching is working at. My guess is that BIND on the server side caches the query results so that next time it doesn’t traverse through the database and hence it becomes much faster in the second time.
Running Slave Server
It doesn’t take long at all the get the slave server up and running. So when the master server goes down or is too busy to serve request, people can still access directory service through the slave server. The slave server works exactly in the same way as normal DNS slave server. It automatically deals with the coherency issues and provides an illusion of a centralized database. I’m proud to say that this makes our directory service a real robust and reliable one.
Accommodating various teams feature requests
During the development process, I collected features request from all teams. For example, voice email team wants to store user id on the cs519g1 machine, fax team wants to store the full name (including first name and last name) of a user as well as his email address. Signaling team decides that having a field called Dialup would significantly simplify their dial-out process and I accommodate their needs in this. The most demanding requests come from the conferencing team. They want to have a separate set of records storing conference record, which each one contains list of current users. Besides various kinds of lookup features, they also want to have various ways to dynamically update the records.
Security Features
Then I started to implement some basic security features that were included in the initial API. I keep another set of separate resource record on directory server which contains the user’s password hash and his privilege level. Everyone who wants to do query through DirectoryStub class has to call the instance method DeclareIdentity(name, password) before he can call any other functions in this class. This declare identity will query the directory service for the password hash corresponding to this user name and sets his privilege level according to the record. Then certain function calls will be enabled depending on what privilege that user has. Only password hash is stored in the database and only hash will be passed out. The password given by user is internally hashed inside DeclareIdentity() and compared against the one from directory service. In this case, as long as inverse hashing is hard enough, there will be a resonable security protection. Here I just use the Java static method String.hashCode(). More sophisticated hashing algorithm can be replaced easily in the future.
Four access levels are available at this moment.
Any user can have a privilege as a combination of the four levels above. Each function call will throw an Exception if the user does not have the appropriate access level after authentication.
Roaming Users
Whenever a user logon, the signaling component update the directory service to reflect his new machine address by calling ChangeLocation() in DirectoryStub. When a user logon, signaling component needs to call ChangeLocation(DirectoryStub.absent) to update his offline status.
Dealing with DHCP
Dealing with DHCP protocol is potentially hard, especially because we can’t find an existing DHCP network around to test it. However, I think the solution could be very simple. I decided not to store machine name instead of the IP addresses in directory service for each user. For example, only cs519g1.csuglab.cornell.edu is stored in the directory service but not the actual IP address 132.236.227.85. In that case change of IP address would not have effect on the system since machine name is relatively static. So directory service always only give out machine name, while people will do the lookup when needed. This will fit well into the DHCP protocol.
Scalability
User names are hierarchical. For example, there are currently 21 registered users in our network. They are the 21 people in our group, with names in the format <name>.g1. For instance, my user name is hayechan.g1. In the future, when the number of users grow, we could put them into sub-domains in a similar way as DNS. There’ll be people named christ.cs.cornell.us.tel, ... Name servers can be hierarchically structured in the same way as DNS. All the successful features in DNS will be inherited in our project.
Porting to NT platform
The users would then use a class called DirectoryStubForNT which has exactly the same interface as DirectoryStub. The difference is, internally, DirectoryStubForNT talks to DirectoryServerForNT.
The problem with that is this intermediate server adds overhead to the directory service for the NT users. The difference in performance between using DirectoryStub directly on UNIX and using DirectoryStubForNT is pretty obvious. If we could have anticipated this accident, I would try to port the C code to NT so that the DirectoryStub works on both NT and UNIX platform.
To my surprise, this is a total of over 4000 lines of Java and C code, not including the BIND libraries that I use.
Problems
I think most problems I ran into are minor technical problems. The single most devastating problem was the problem in getting my partner to work. I have trouble in getting my partner in replying my email. Finally I end up doing almost the whole project myself. This has put extraordinary stress on my already heavy academic schedule. I had a very hard time in getting the project finished with high quality while preparing for six final exams at the same time.
Apart from that, the major technical problems are:
What I learnt
What would I do differently next time?
First, one major mistake I made was not to make sure everybody is on UNIX at the beginning. Next time I will pay more attention to the platform issues before doing a lot of platform dependent things. This is the only part that I’m not happy with my directory service. Although the UNIX users can still get a very outstanding performance, the NT users do not have the same feeling.
Second, I would have requested a temporary machine from course staff in the very early stage so that I could run the slave directory server on it.
Third, of course we should have more often meetings.
Interface
DirectoryStub/DirectoryStubForNT - this is the stub placed on the client who needs directory services
Name - this is the class for user name
SocketAddr - this is the class for storing Machine Addresses with port number. e.g. babbage.csuglab.cornell.edu:30
Digits - this class is designed for storing digit-like data, e.g. Extension, PIN
FullName - this class is designed for fax and voice/e-mail gateway team to store a normal pronounciable full name. It provides abstraction for storing first name and last name
NameList - this class is designed for multi-party conference team to store a list of participants in a conference.
DirectoryStub
public class DirectoryStub
{
// constructor
public DirectoryStub();
// authenticate this stub with the id and corresponding password
public int DeclareIdentity(Name name, String password)
throws AuthenticationException;
// change the password to newPassword
public void ChangePassword(String newPassword)
throws AccessDeniedException, RecordNotFoundException;
// delete the old SocketAddr from database, add a new SocketAddr in
public void ChangeLocation(SocketAddr newAddr)
throws AccessDeniedException, RecordNotFoundException, InvalidSocketAddrException;
// change the dialout phonenumber for a user
public void ChangeDialout(Digits phoneNum)
throws AccessDeniedException, RecordNotFoundException, InvalidSocketAddrException;
// QUERY methods
// obtain the location of a user
public SocketAddr GetLocation(Name name)
throws AccessDeniedException, RecordNotFoundException, InvalidSocketAddrException;
public Digits GetExtension(Name name)
throws AccessDeniedException, RecordNotFoundException, InvalidSocketAddrException;
public String GetEmail(Name name)
throws AccessDeniedException, RecordNotFoundException, InvalidSocketAddrException;
public Digits GetPIN(Name name)
throws AccessDeniedException, RecordNotFoundException, InvalidSocketAddrException;
public String GetUserID(Name name)
throws AccessDeniedException, RecordNotFoundException, InvalidSocketAddrException;
public FullName GetFullName(Name name)
throws AccessDeniedException, RecordNotFoundException,
InvalidSocketAddrException;
// obtain the location of a user
public Digits GetDialout(Name name)
throws AccessDeniedException, RecordNotFoundException,
InvalidSocketAddrException;
// map address to name
public Name GetNameByAddr(SocketAddr addr)
throws AccessDeniedException, RecordNotFoundException;
// map extension to name
public Name GetNameByExt(Digits ext)
throws AccessDeniedException, RecordNotFoundException;
// following are functions for multi-party conference call
// add a conference
// return true if sucessful
// return false if conference exist already
public boolean AddConference(Digits confNum)
throws AccessDeniedException;
// add a user to a conference
public void AddUserToConference(Digits confNum, Name newUser)
throws AccessDeniedException, RecordNotFoundException;
// delete a user from a conference record
public void DeleteUserFromConference(Digits confNum, Name diedUser)
throws AccessDeniedException, RecordNotFoundException;
// delete a conference record
public void DeleteConference(Digits confNum)
throws AccessDeniedException;
public NameList GetUsersInConference(Digits confNum)
throws AccessDeniedException, RecordNotFoundException;
}
Name
public class Name {
public Name (String s):
// not implemented yet
public Enumeration parts ();
public String toString ();
}
SocketAddr
public class SocketAddr extends Address {
// hostname : e.g. babbage.csuglab.cornell.edu
public String hostname;
// port number
public int port;
// the string meaning absent when stored as SocketAddr
public static final String absent;
// constructor taking in string of the format "hostname:port"
public SocketAddr(String addr);
// return true if the this Hostname is one for a user who is not present
public boolean IsAbsent();
public String toString();
}
Digits
public class Digits {
// constructor for string
public Digits (String num);
// constructor for integer array
public Digits (int[] n);
// return an array representing the digits one by one
public int [] GetArray ();
public String toString();
public int equals(Digits digits);
}
FullName
public class FullName {
// has to be in format " "
// e.g. "Haye Chan"
public FullName (String s);
// return the First Name
public String FirstName();
// return the Last Name
public String LastName();
public String toString ();
}
NameList
public class NameList
{
// constructor which takes in string in the format
// "user1,user2,user3,..."
public NameList(String strNameList);
// return whether the name list is empty or not
// this function is independent of the token evaluation
public boolean isEmpty();
// any more names in the name list to get?
// this should always be called and checked before GetNextName
public boolean hasMoreNames();
// return the next Name in the NameList
public Name GetNextName();
// reset the namelist so that next call to getNextName()
// will return the first Name
public void Restart();
// add a Name to the current NameList
// the NameList will be Restart()'ed
public void AddName(Name newName);
// delete a Name from the NameList after the current pointer
// this function assume namelist is not empty
// the NameList will be Restart()'ed
public void DeleteName(Name delName);
public String toString();
}
Advice for course staff
I think this class is too demanding as a 4-credit class. I suggest that in later years, it should be split into two portion. The 3 credits one will include lectures, exams, and homework. While the other one will be mainly project. Or some other better combinations whichever is more appropriate.
I think one major problem students had at first was visualizing how the various components in the system comes together and function. We of course eventually figured it out, but it would have been a lot more effective if there could be more covering of the project in the lecture or sections (which we don’t have right now). I think having TAs to hold some sections for students to talk about the project might be helpful. If we could have figured out things earlier, the time would be much more sufficient.
Hardware is basically readily available quite at the right time. Course staffs are all very helpful. The project idea is excellent. A little more improvements should make it perfect.
References
In the implementation of our stub, I made use of the following Java Spec web pages:
http://java.sun.com/docs/Also I extensively used the book DNS and BIND, by Paul Albitz & Cricket Liu.