Version 3.2-en
Introduction
Computer networks are used to transfer information between computers. The information can be anything that can be represented as ones and zeros. One kind of information is text messages of the type "many-to-many" and the application class that handles those messages is called a chat. A chat generally consists of a server component and a client component. The server component receives messages from a client and forwards them to all the clients that are connected to the chat server. The client component sends messages, typed in by the user, and presents the conversation through some interface to the user. If a chat client may connect to several different servers, the chat service can be considered to be distributed. The available chat servers are found through a central name server, to which all the chat servers are registered with.
When a system becomes to complex, abstractions need to be introduced. An abstract object captures some aspects of the system, has one or many interfaces available for use by other objects and hides implementation details. There are two major benefits from composing a system out of abstract objects. The first is that it divides the problem of constructing a large system into small and manageable components. Secondly, it produces a modular design, which makes it much easier to extend and add functionality to the system.
The abstract objects in a network are the protocols. Each protocol defines two interfaces. The service interface which is used by other objects on the same machine that wish to use the services provided by the object, and an interface used for communication with the corresponding protocol on another machine (peer-to-peer interface). Aside from the physical layer, the communication with the corresponding protocol on another machine is indirect, the communication channel is provided by the underlying network protocols. The term protocol has two meanings. It either denotes the service interfaces the protocol provides and sometimes it denotes the object that implements the interfaces. Which meaning is intended is usually obvious when put in context, but if clarification is needed the latter can be referred to by the term protocol specification. When a protocol communicates with its corresponding protocol on another machine the data will be encapsulated in a packet, a PDU (Protocol Data Unit). Transmitting just the data is usually not sufficient for the remote protocol to interpret it properly without additional information. This information is encoded in a header, which is inserted in front of the packet data. The data itself is referred to as body or payload. This encapsulation is repeated for each protocol layer in a network.
In this assignment some components of a distributed chat should be implemented: a chat server and a chat client. The objective is that both components should be able to communicate with a central name server and with the components of the other groups. The chat server should be implemented in C or C++ and the chat client should be implemented in Java and thus be platform independent. The chat client should have a graphical user interface and be implemented as a regular application and not an applet, to avoid any web browser trouble.
This assignment is divided into three difficulty levels. Each level provides different amounts of extra exam credits. All the requirements of level 1 are part of level 2 and so on. Requirements for level 2 and 3 are tagged in this specification as such. The levels are summarized in the section level requirements. When a group has chosen their level, they should at latest April 23 notify which students are part of the group and which level is chosen by writing those down on the list outside Emanuel's office (D426).
Purpose
The general purpose of the assignment is to increase the understanding of data communication and computer networks. The following purposes also exist:
- Exercise socket programming in C/C++ and Java.
- Provide understanding of protocols. Why and how they are utilized, and implementation of protocols.
- Provide understanding of distributed systems and what requirements such systems have on the partial or whole implementer of the system.
- Provide understanding of abstraction in complex systems.
System description
The complete requirements of the system that should be implemented are shown below (note that some requirements are tagged with "level 2" and are not needed for level 1).
The system protocols and the communication between two corresponding protocols on different machines is described below. However, the service interfaces of the protocols are not described in detail, only the required implementation is covered. The design of the service interfaces should be done based on the knowledge of what is communicated between the parties.
The data in all packets, which is described below, should always be stored in network byte order, which is the same as big endian order. All text should be encoded with 8-bit extended ASCII (ISO-8859-1, also known as Latin1). Note that Java uses the UTF-16 encoding for its strings, which should not be used.
Messages may be compressed and encrypted (level 2). The compression should be done before any encryption. Only the client should be able to encrypt/decrypt messages. The server should not perform encryption/decryption.
Application protocol - chat
The chat service is composed of three main components: a client component, a server component and a name server. The assignment covers implementing the first two components. The communication between the chat client and chat server should be done through a single communication channel and a non-blocking communication pattern must be used. This means that handling a message from one chat client must not interfere with incoming messages from other chat clients.
Client
The chat client should have a graphical user interface. There should be a field for entering the name server, a preferred "nickname" (the name the user wishes to be known as in the chat), encryption key and a field for entering text messages. Additionally, the client should have a list of available chat servers populated from the name server. The user should be able to choose between these servers. Incoming messages should be presented in a large text area.
When the chat client is launched the user should enter the address and port of the name server. Following that, the chat client will contact the name server for a list of available chat servers. The name server communication should be over the UDP transport protocol. The list of chat servers should for each chat server contain the IP address, the port number, user count and the current topic (the intended subject of conversation). The chat client should perform name lookups (DNS lookups) of the IP addresses and present the full domain name of the server if available. The user may then choose a nickname, pick a server to connect to and connect to the chosen server. The user can then communicate with other users. The chat server will notify all connected clients that a new client has joined the chat.
The user may now enter messages. Furthermore, the user should be able to select whether the message should be compressed and/or be encrypted and be able to enter an encryption key. This will be covered in detail in the encryption section of the specification. When the message is sent to the chat server, the server should fill in the nickname of the client that sent the message and timestamp it. The chat server should then distribute the message to all the connected clients. When the chat client is terminated a quit message should be sent to the chat server the chat client is connected to. The server should notify all connected clients about the disconnection. The communication with the chat server should be done with the TCP transport protocol.
Server
When the chat server is launched it should register itself with the name server. It will be assigned a positive ID number which it will use when sending Alive messages to the name server in 30 second intervals. The chat server has two responsibilities, to track the chat clients that are connected to it and their information including nick names, addresses and connection time, and to track received messages to process and distribute them to all the connected chat clients.
A maximum of 255 chat clients should be able to connect to the chat server. The server should for each client track its address, nickname and the time the client connected to the chat. During run-time the chat server will wait for an incoming message from any of the chat clients. When this occurs, the chat server will read the message and look up which client sent it. The nickname of that client will be filled into the message together with a time stamp which tells when the message arrived at the server. The server will then send the message to all connected chat clients (including the chat client that sent the message). The server can also send messages itself. This happens when:
- Someone changes the topic
- Someone sends malformed messages to the server and gets disconnected
- The server is terminated
The server will send those messages to all the connected chat clients. The convention is that messages with no nickname and a NICKLEN field of 0 are system messages from the chat server. The client may present these messages in some special way, for example by changing the color it presents the message with to distinguish it from regular chat messages. Malformed messages should be discarded and the connection to the broken client should be closed. Furthermore should as earlier mentioned a system message be sent to all chat clients by the chat server to notify them of this.
The server should notify all connected clients every time a client connects or disconnects from the chat, and send a message with a list of all connected users to the chat.
Name Server
Even though the implementation of this component is not part of the assignment, certain information will be provided about the name server. This is to ease the communication with the name server.
All chat servers should register themselves with a name server so that chat clients may locate them. The name server tracks all active chat servers continuously. Each active chat server should send Alive messages every 30 seconds to the name server. If no alive message is received the chat server is considered missing and will be removed from the list of active chat servers after a short time period. Chat clients may obtain the active chat server list from the name server.
A central name server will be hosted on vega.cs.umu.se on port 1337. This server should be used when the implementation is nearing completion, in order to not disturb the work of other groups through broken servers and clients. For test runs and debugging the name server binary is available (Solaris) or (Linux).
The central name server also has a web interface which will display the current server list. It is reachable at http://vega.cs.umu.se:8080/.
Protocol description: Application
Each protocol will be described in the form of a PDU or a message (not to be confused with chat messages sent in the actual chat). The PDU's can look something similar to this:
The above convention and format will be used for all PDU's. Fields labeled ''Pad'' are used for padding and shall only contain zeroes.
In many of the messages a field labeled ''OP:'' followed by an operation will be used. The header file named: opcodes.h has definitions for the different operation codes one should use.
An important note to remember is that all numbers in the protocol, for example port number, shall be unsigned, in other words, not sign and always positive.
Protocol description: Name Server communication
Name Server (NS) and Chat Server (CS) communication
CS -> NS: Register
The following message is sent to the name server when the chat server wants to register. The field Topic length is the length of the topic string calculated in bytes. The last field
in the message contains the actual topic string, it must have a length which is dividable in to even four bytes intervals. For example, the topic ''HEJ'' would be sent as 4 bytes where the
last byte would be a zero. Note that the field Topic length would contain the number 3. All packages containing data of dynamic length will follow the above mentioned approach.
TCP-port is the port number on which the chat server is listening.
NS -> CS: Confirmation
This message is sent from the name server to the chat server to confirm that some information has been received properly. An ID-number is sent with the message, th ID-number is
sent with all messages except the Register-message. The ID-number is used for identifying the chat server.
CS -> NS: I am alive
The alive message is sent once every 30 second, from the chat server to the name server, to confirm that the chat server is still running. Included in the alive package is the ID-number that
was assigned earlier from the name server.
CS -> NS: Change topic
The change topic message is sent from the chat server to the name sever when a user changes the topic. The topic length field containts the
actual length of the topic string and the field ''Topic'' must have a length evenly dividable by 4.
NS -> CS: Not registered
The not registered message is sent from the name server to the chat server if the chat server is trying to communicate with the name server without beeing
registered.
Name Server and Chat Client communication
CK -> NS: Fetch server list
The fetch server list message is sent from the chat client to the name server when the chat client wants to inform the
name server that it wants a list with all the active chat servers.
NS -> CK: Server list
The "server list" message is sent from the name server to the chat client to report the active chat servers. The message begins with a header which describes how many servers will follow. For each server the address, port, client count, the topic length and the topic text (padded to four byte alignment) is sent. All the above is sent in a single message.
An UDP datagram however has the limitation that it may not be larger than 65507 bytes, which has the result that the name server will send the remaining information in subsequent datagrams if needed. The name server will not split messages at exactly 65507 bytes, instead it will split the message at the boundary between servers. A message segment will never be larger than 65507 bytes.
Messages in the system
"Register" and "alive" messages are sent from the chat server to the name server, if everything is fine an "ack" message will be sent in response. If a chat server can not be registered with the name server or if an "alive" message is received from an non-registered chat server, a "not registered" message will be returned. The "fetch server list" message is sent from a chat client to the name server, which will reply with a "server list" message (see opcodes.h). All communication with the name server must use the UDP protocol.
The image above additionally shows the messages exchanged between a chat server and a chat client as well (see below for a further description).
Communication protocol for the chat server and a chat client
CS <-> CK: Message
The "message" message is sent from a chat client to the chat server when the user has typed something and wishes to send it to the chat. In the chat server the message will be processed and distributed to all connected clients. Note that the same message type is sent in both directions.
The "message type" field in the message determines how the message should be interpreted according to this table:
- 0: Plain text
- 1: Compressed text
- 2: Encrypted text
- 3: Compressed and encrypted text
These message types are defined in the header file msgtypes.h. Note that if the message type is 3, the message should be compressed before encryption and should thus be unpacked in the reverse order. Also note that all messages orginating from the chat server (those with 0 in the "nick length" field) must not be compressed or encrypted. Those messages are always sent as plain text. Clients should ignore messages with an unsupported type.
The nick length field should always be 0 when sent to the chat server. The chat server will fill out that field and append the nickname padded to four byte alignment to the message. This is to increase security.
The "checksum" should contain a checksum of the whole PDU. More information on how it is calculated is in the section checksum calculation.
The "message length" field will contain the true length of the message like all other fields with dynamic length. The "message" field must be padded to four bytes alignment.
The "timestamp" field should like the "nick length" field also be set to 0 when a message is sent from a client to the chat server. The chat server will fill the field with the current Unix time (seconds since 1970-01-01 00:00:00). That number may be acquired through the function "gettimeofday()". This is to be able to determine when the message was sent. When the server has amended the message with the nickname and timestamp, it should distribute the message to all connected chat clients.
CS <-> CK: Quit
The "quit" message is sent from a client to the chat server when the client disconnects from the server or terminates the chat application. The server will notify all the remaining clients through an "user parted" message. If the chat server must terminate for some reason, it should send a "quit" message to all clients to avoid abrupt disconnections.
CK -> CS: Connect
The "connect" message is sent from a client to the chat server when the client wants to connect to the chat. The message contains the preferred nickname (padded to four bytes alignment) and the true length of the preferred nickname. The server will verify the uniqueness of the preferred nickname and if it's taken, modify it with some kind of counter. If there's already a client with the name "Charlie" the next client should get something along the lines of "Charlie1" or similar. The server should then broadcast a message to the chat that "Charlie1" has connected. The server should be _case insensitive_ when comparing nicknames.
The chat server should also store the time the client connected and which IP address of each client. A client that hasn't sent a connect message should _not_ be able to send anything to the chat. If a client misbehaves and does that, the message should be discarded and the connection should be closed.
For level 3 this PDU has a slightly different format. See the section on levels for further information.
CS -> CK: Nicknames
When a client has connected to the server through the "connect" message, the server will respond with a "nicknames" message. This message contains the nicknames of all connected clients, starting with your own assigned name. The names are separated by \0 characters and the last name in the list is also terminated by a \0. This has the consequence that the last four bytes in the message may be all zero. The "length" field contains the true number of bytes of the names, including the terminating \0 while the "nicknames" field is padded to four bytes alignment.
CK -> CS: Request user information (Level 2)
The "request user information" message may be sent by a client to the chat server to request more information on some client. The "nickname" field will contain the nickname of the sought for client padded to four bytes alignment.
CS -> CK: User information (Level 2)
The "user information" message is sent from the chat server to the client that requested the client information through a "request client information" message. The message will contain the address and connection time of the sought for client (which is stored on the server). It is up to the client to resolve the IP address if friendly names are needed. The time should be the Unix time (seconds since 1970-01-01 00:00:00) when the client connected.
For level 3 this PDU has a slightly different format. See the section on levels for further information.
CS -> CK: Someone connected
When the server receives a connection from a client the server should notify all connected clients of that through a "someone connected" message. The message contains a timestamp and the name of the new client. The "length" field contains the true number of characters in the name, any pad bytes are not included in the length.
CK -> CS: Someone parted
When a client parts from the server the other clients will be notified by the chat server with a "someone parted" message. The message contains the timestamp and the name of the client that parted. The "length" field contains the true number of characters in the name, any pad bytes are not included in the length.
CK -> CS: Change nickname (Level 2)
A client should naturally be able to change their nickname. The client should send a message to the chat server requesting a nick change, upon which the chat server should handle the new nickname just like a new client connection. The connection timestamp should however not be modified, only the nickname should be processed to ensure uniqueness.
CS -> CK: Someone changed nickname (Level 2)
When a user has changed their nickname all connected clients should be notified with a "someone changed nickname" message. The message contains a timestamp, the old name and the new name. The "length" fields contain the true lengths of the names. Both names should be individually padded to four bytes alignment.
CK <-> CS: Change topic (Level 2)
The "change topic" message is first sent from a client to the chat server, notifying the server that it should change the current topic (the intended field of conversation). The "topic length" field contains the true length of the text as usual while the dynamic "topic" field is padded to four bytes alignment.
The server should change the topic, notify the name server of the change and notify all connected clients of the new topic.
Protocol descriptions: Utility protocols (Level 2)
This section covers the functionality of the two helper protocol in depth. Text messages may be as earlier mentioned both compressed and encrypted. This should be done according to the figure below. Note that it only illustrates the case where a text message is to be both compressed and encrypted.
The client types a text message into the client, which will be compressed. The compressed text will be wrapped in an compression header. The compressed message and its header will then be encrypted and wrapped in an encryption header. This forms the payload of the "message" message that will be sent to the chat server.
As previously mentioned, messages from the chat server itself (system messages) should be in plain text and should thus not be fed through the helper protocols.
Compression and decompression protocol
Compression is generally used to reduce the bandwidth requirements in a system. For this assignment though, the purpose is mostly to provide understanding of how to stack several layers and protocols in an application. The compression used will be gzip, which has an implementation in the Java API. Since the chat server never needs to decrypt or decompress anything, no C implementations are needed.
Compressing the message
The length of the plain text the user types in is stored in the "message length not compressed" field. The message is then fed through a gzip stream to compress it. The true length of the compressed data is stored in the "message length compressed" field and the compressed data in the field "message", padded with zeroes to four bytes alignment.
A client receiving this message follow this algorithm in reverse and should feed the data through a decompressing stream.
The "algorithm" field denotes the compression algorithm used. In this assignment gzip will be used, which is indicated by a zero in this field.
The "checksum" field should contain a checksum for the whole PDU. More information on how to calculate the checksum is shown further below.
Encryption and decryption protocol
Encryption is used to make it harder for eavesdroppers to intercept the messages. As with the compression the important part is the understanding of the concepts involved and thus the encryption algorithm used will be a trivial variant of XOR. It is implemented in Crypt.java. The algorithm requires an encryption key, which should be a string. By default the string foobar should be used as the encryption key. It should be possible to provide another key in the chat client, which should be used for both incoming and outgoing messages. This means that two users can share a key through a secure channel and then talk about secrets in the chat. The chat client should have a interface field to enter the key in, which has been mentioned earlier.
Encrypting the message
The length of the data provided by the user or retrieved from the compression algorithm should be stored in the "message length not encrypted" field. The data is then encrypted, upon which the true length of the encrypted data is stored in the "message length encrypted" field and the encrypted data itself is stored in the "message" field, padded as usual to four bytes alignment.
The "algorithm" field indicates which encryption algorithm is used. In this assignment a variant of XOR is used, which is indicated by a zero in this field.
The "checksum" field should contain a checksum for the whole PDU. More information on how to calculate the checksum is shown further below.
The checksum should be calculated using the same algorithm as the IP protocol uses (IP, UDP and TCP has the same algorithm), with the difference that only eight bits are used here. IP uses 16 bits for the checksum. Each byte are added together in 1-complement arithmetic and finally the 1-complement of the sum is used as the checksum value. The result of this is that when the receiver adds all bytes, including the checksum, the final result will be all ones. Examples:
10001011
11100010
-----------
01101101 (with 1 in carry)
With 1-complement arithmetic:
01101110 (1 added to the least significant bit)
Finally the 1-complement is taken of the sum:
10010001
The receiver will add the three bytes (two data and one checksum):
10001011
11100010
-----------
01101101 (with 1 in carry) => 01101110
01101110
10010001 (checksum)
-----------
11111111
To make your work easier and to ensure that implementations are compatible, code will be provided for checksum calculation in C and Java (checksum.c, Checksum.java).
The assignment is divided into three levels and the chosen level determines the amount of bonus credits for the written examination. It is up to you to decide on which level you intend to achieve. The report will be graded with either a G (accepted) or O (incomplete). If you get a G you will receive credits according to your chosen level. If you get an O you have one opportunity to correct your report and still get the credits for the chosen level. If the corrected report gets an O you may only get graded according to level 1, assuming that all the requirements for level 1 are satisfied. The flowchart below shows how the grading process progresses. Each level encompasses increasingly more of the problem domain (for more information on bonus credits, see Bonus credits).
Level 1
This level has the baseline requirements everyone must satisfy to complete the assignment. The following components must be implemented and function:
- Functioning chat.
- All PDUs except WHOIS, UINFO, CHNICK and both of the CHTPC.
- Compression and encryption should not be implemented at this level, those should be handled by discarding them.
- Checksum handling should be correct.
- A level 1 implementation should in general handle any unknown messages without crashing so that it is compatible with the higher levels.
This level includes a complete report as detailed by the section Presentation.
Level 2
A level 2 implementation must satisfy the level 1 requirements as well as:
- Handle all PDUs.
- Encryption and compression.
- The server must cope with malicious clients. In order to determine if your solution satisfies this requirements you may download a Solaris binary which will test your server. The test will perform the following tests:
1. Trivial reference case.
2. Flooding test and checksum verification.
3. Long corner case nicknames and topics.
4. 150 concurrent clients.
5. Slow clients and fragmented messages - the server should cope with very slow clients without affecting other clients as well as handling packet fragmentation. This will be tested by sending messages in bursts of a few bytes with a delay in between.
A level 2 solution will not be accepted unless all the level 1 functionality is properly implemented as well.
Level 3
A level 3 implementation must satisfy the level 2 requirements as well as:
- File sharing:
This component will require some modification of the Client->CS JOIN and the CS->Client UINFO messages. Instead of padding with zeroes these pads should contain the port number which clients should use for peer-to-peer communication. The port number is two bytes wide and in JOIN there are just two pad bytes and those will be replaced with the port number, in UINFO the two last pad bytes should be replaced. (Note! Port 0 means that the client in question only supports level 1 or 2.)
- The file sharing should be peer-to-peer and does not require any server-side changes except for the aforementioned changes.
- The chat client should present a selection of available files through searching. (The searching may be done either locally or on the sharing node.)
- The peer-to-peer protocol may be completely different from the regular protocol.
- The file transfer may be done either in-band or out-of-band (see for example the section on FTP in the course literature).
- The client should be capable of handling both chat, sending a file and receiving a file concurrently. Any more advanced solutions are allowed.
- Together with another level 3 group you should design a protocol together. Your implementation is required to communicate properly with the other group and you will present your assignments simultaneously.
- An important part of level 3 is the design of the protocol. A discussion of the protocol with design motivations should be covered in the report.
A level 3 solution will not be accepted unless all the level 2 functionality is properly implemented as well.
Assignment
The assignment is to implement the system described above (apart from the name server). As mentioned earlier the chat server should be implemented in C or C++ and the chat client in Java. The goal is that the solutions of all groups should be able to communicate with each other without problems. To help achieve this goal, a name server will be provided.
It is quite helpful to test your system against the systems of other groups before the presentation to ensure that you have interpreted the specification the same way. It's important that you clearly document any ambiguities in your report and preferably discuss them with the TA:s. If you feel you have to modify a protocol, run the change by us first to ensure that it is allowed.
The server and the client must build and be executable on both the Solaris and the Linux systems.
Presentation
The assignment should be presented in a complete report (one per group) and a live demonstration with a TA. The report should contain, apart from other relevant sections, a system description describing the implementation and interaction of the different components. We do not want a system description of all the methods/member functions/functions in the system, that information should be deducible from the well commented and well written source code. Instead, describe clearly how the system is designed and what parts are done in parallel, threaded and so on. Also describe the development environment you have used and how the applications work. You should furthermore provide some kind of test protocol showing how you have tested your solutions.
All the files of your solution should exist in the directory ~/edu/dod/lab2/.
Finally the report should contain discussions around the following points:
- How scalable is the system? What scales well? What scales badly?
- Reflect around the security of the system from different approaches.
- Discuss the advantages and disadvantages with coding in Java versus C and C++.
- Reflect on why the languages specified for the different components were chosen.
- Comment on the protocols. What advantages and disadvantages are there with a binary protocol as opposed to a text-based protocol?
The report should be handed in at latest Friday 23/5, 17:00. The live demonstrations will be done on Wednesday 21/5, 13-17 (preliminary time). A registration form will be available outside Emanuel's office (D426) around a week before the demonstration.
Files
The following files are given to the student as is and are to be used in this assignment.
Limitations
The protocols mentioned have a few limitations, among others, the following:
- A nickname can not be longer than 255 characters.
- A topic can not be longer than 255 characters.
- A name server can not handle more that 65535 chat servers.
- A chat server can not handle more than 255 clients.
- A message can not be longer than 65535 characters.
- The timestamp will only work up to the year 2036.
Try to avoid to further burden down the protocols. If unsure about the above mentioned limitations, come in and discuss with the teaching assistant.
Tips and Tricks
When assignments are starting to become as large as this one it's important to test each component of the system individually since the testing complexity increases very fast. Furthermore, it is beneficial to test and experiment any new functionality/commands separately before incorporating them into the system.
We recommend strongly that you should utilize pen and paper before implementing. Begin by trying out the basic concepts and when you feel you have a command of the basics, drop the keyboard and grab a pen instead. From there, write down a detailed algorithm for each component and implement that. If the algorithm does not yield the expected result, go back to the drawing board and update the algorithm there instead of hacking randomly. Trial and error coding takes significantly more time!
Keep in mind that the length (in bytes) of all dynamic packets must be a multiple of 4.
When the checksum should be calculated of a message and the message has a checksum field, then that field should be zeroed out before calculating the checksum.
When the client is compressing a message before sending it is preferably done with the help of a GZIP-stream (java.util.zip). A good strategy is to connect one of those streams to a ByteArrayOutputStream (java.io), in order to pack the compressed data into a byte array for further processing.
When the client is decompressing a message it's wise to reverse the above routine and connect a ByteArrayInputStream to the array containing the compressed data. From that stream the data can then be decompressed through a GZipInputStream.
FAQ
Hey, a process can only have 64 open sockets!?
Each client will by necessity have a corresponding socket open in the chat server. This means that the chat server must be able to open 255 sockets which each use a file descriptor. Some systems impose limits on the number of sockets a process may open, for example on the old Solaris systems (which do not exist anymore), a limit of 64 file descriptors per process exists. This is not an issue on the new Solaris and Linux systems which allow for many more descriptors. You will not need to circumvent any file descriptor limitation in your solution for systems with lower limits, just mention it as a solution limitation in the report.
To determine and adjust the limits of a system the command limit may be used.
Is the ID number provided by the chat server always positive? I have a function which would return the ID on success and -1 or -2 as failure conditions. In this case, getting a -1 from the name server would be bad.
The name server will assign the first server in the list ID 0 and will increment this to give the next server ID 1 and so forth. A chat server can never be assigned a negative ID.
I have a short question about the name server. I have implemented my chat server in a way that it will send an ALIVE message every n:th second (30 according to the specification, a bit shorter at the moment) and after sending the message the server will wait for an ACK message from the name server.
Assume that the name server will fail while I'm preparing to send an ALIVE message. When I send that message and wait for an ACK, I will never receive any response since the name server never got my ALIVE and when it resumes, it will not be aware that it has missed anything.
Is it allowed to after a certain timeout period to assume that the name server is dead (even though it may be alive but unreachable) and notify the users of this and terminate the chat server? Or should one make recvfrom non-blocking (that's doable, right?) and wait for a short while and send a new ALIVE message? Or what do you think one should do?
When the name server comes back all messages will be responded to with an NOTREG message since the list of chat servers is empty. The best thing to do is to send a new REG message to the chat server and wait for an ACK.
If the name server doesn't come back, no response will be received. You should therefore have a timeout on your recvfrom and when it expires you should attempt to send another ALIVE. If no ACK is received after x attempts the server could be assumed to be down. You should NOT terminate the chat server just because the name server is not responding, since your clients are capable of chatting just fine without the name server.
It would be neat if the chat server would notify the clients in the chat with a system message that the name server is down.
After a period of time, you could attempt to resume contact with the name server since it may have recovered by then.
Server applications should in general be as robust as possible to external and internal problems, in order to provide a good quality of service for the clients. Failures should be gracefully recovered instead of just calling exit(-1) and disconnect all clients.
I'd like to ask a question. Assume that a client sends a WHOIS message for an unused nickname. Currently our solution is the respond with a USERINFO containing the 0.0.0.0 IP address and a timestamp with value zero. The client will then interpret this message as that there is no client with this nickname and will notify the user with a suitable error message.
There will be a problem if another client implementation connects to the server and receives that kind of message and will most likely encounter problems when resolving the IP 0.0.0.0. A friendlier alternative would probably be to respond with a system message which will be output into the chat window instead.
Your initial solution (albeit good) will as you say not work reliably for any other clients than your own since it's not covered by the specification. The scenario is not considered at all, and thus the best solution would likely be to send a regular text message to the client from the server and inform the user that there is no client with that nickname!
|