CHAT SERVER PROTOCOL ver 0.03, CLIENT AND SERVER NOTES

CHAT SERVER PROTOCOL ver 0.03
Working Document

This is just a working document and should not be taken as the final version of the protocol. This document is subject to change though largely backward compatibility will be maintained.
            The document describes the text based protocol used in the communication to the chat server we developed. A few things to keep in mind before going on to the command list.
            The protocol is text based, you may telnet to the server and issue these commands through an VT100 terminal and see these work. The server is currently on IP 203.197.150.179 and port 6500.

Notes
            Every line of text that is sent to the server that represents a complete commend is to be terminated by a CRLF combination. The parser at the server looks for CRLF to detect end-of-command before it responds. The server has an input buffer of 1000 bytes. If this buffer is exceeded ie single block of data with no CRLF in that length, the buffer shall max out and the server shall disconnect you with a warning message.
            Every name on the server (user name, room name, message name etc) is limited to 30 chars (subject to change). If this length is exceeded the server shall return an error code. For safety sake the recommended command length is about 800bytes and name length is 25 bytes.
            The server uses a simple space-based parser. Things separated by white spaces are taken as separate entities. If a single entity such as a message heading is to contain white spaces, it must be enclosed in double quotes. If double quotes are to be preset in a double-quoted block they must be prefixed with a backslash. Thus the standard C conventions \” and \\ apply within “strings” .
            Every command that you send to the server is specifically replied to prefixed by either a “@ret” or a “@status”. Messages that are sent to you but are not expected by your client (for example a message sent to you from another user, when you were waiting for the reply to some command you issued) are prefixed by a “@mess”.

 

The Commands
            The following are the commands that the client is to issue to communicate through the chat server. These should be considered in respect of the above notes.

The description describes what you send to the server and what the server is expected to reply with.

Login commands
#login regd <username> <password>
    to login as a registered user
#login anon <username>
    to login as a anonymous user
return:
@status <status no>
    Refer to error_def.h for meanings of status no. 0 is NO_ERROR. registered users, currently validation is done from file regdusers. Each line in this file contains username and password for each user. Change cserv_command.cpp to change regd users code. On login you are part of room 'Home' by default. The mention of the password in this case is that actual text based password. Later it shall be changed to mean a encrypted password string.

None of the following commands will work unless the user has logged in successfully.

#rmlogin
returns:
    @status <no>
To delete your current login. Only for registered users.

#changepass <new password> <old password>
returns:
    @status <no>
Change your current login’s password. Only for registered users.

#createlogin <name> <password> <real name> <email id>
returns:
    @status <no>
Create a registered login.

#whoami
returns:
    @ret #whoami <username> <current room name> <users in current room> <current group name> <group id>
    Retrieve information about your current position, this entire message is returned as one line to the user. Every user joins the ‘Home’ room by default. If no group has been joined (message group), this is returned as name = “-“ and id = 0.

Room related commands

#listrooms
returns:
    @ret #listrooms <no of rooms>
    <name of room> <owner of room> <no of users> <secs for room to expire> <pub/priv> <anon/regd>
    ... (above data is repeated for each room)
    retrieves information about each room. If there are 3 rooms, there will be three lines of text following the @ret line. If the room is occupied, secs for expiry set as 0. Room 'Home' never expires. Type is priv or pub, for private or public rooms.

#listusers
return:
    @ret #listusers <no of users>
    <user name> <type>
    ... (above data is repeated for each user)
    The above command retrieves information about every user in the room. type maybe anon or regd or none (none for users yet to login).

#createroom <new room name> [room password]
return:
    @status <status no>
    creates a new room, you will be the owner of the room. The room password is to be given if you want to make a private room.

#rmroom <room name> [room password]
return:
    @status <status no>
    Deletes a room. Will succeed only if you are the owner of the room.

#changeroom <room name> [room password] [anon/regd]
return:
    @status <status no>
    will change you to an existing room. if it is a private room a password is to be given.  Default is anon

#broadcast "<text>"
return to all users in users current room
    @mess #broadcast <uname> "<text>"
    the broadcast message is causes the text to be send to all the users in the users room. they all receive the same message. The message contains the name of the broadcasting user

#sendto <uname> "<text>"
return:
    @status <status no>
return to user uname:
    @mess #sendto <sending uname> "<text>"
    use this to send private messages to any user in your room. You get a return status and the other user (if exists) gets the message.

#peer2peer <uname> <my listening port> <my ip string>
return:
    @status <no>
return to user uname
    @mess #peer2peer <sending uname> " <port name> <ip address>"
    use this to enable peer to peer connectivity. If you have a listening port, you may transmit this and your ip to any user. The server sends you a no depending on if the message was send to the user. How he responds is entirely up to him. If he wishes, he can then connect to you at the port and ip. The server assumes no responsibility once the data has been transmitted - this is entirely up to the clients.

Status commands
    The server maintains 3 status numbers that a client can query. These maybe queried according the clients wishes and is can be used to check if any changes on the server need be reflected for the client.

#archstatus
return:
    @ret #archstatus <no>
    the number changes every time a room is added or deleted. if the client maintains a display of the rooms names, he may execute a #listrooms, if the no returned is different from the one he got when last queried #archstatus.

#roomstatus
return:
    @ret #roomstatus <no>
    no changes every time any user goes in or out of any room in the server.

#userstatus
return:
    @ret #userstatus <no>
    the number changes every time a user enters or leaves the room that the user is a part of. Thus the client can query the room for the new list using #listusers .

 

 

Message Posting Related Commands

#listgroups
return:
    @ret #listgroups <no of groups>
    <name of group> <owner name> <group no> <no of messages> <no of users> <terminate time> <pub/priv> <anon/regd>
    ...
    use this to see the available message groups. A message group is place where you can post and read messages. Users can create group and it is recommended that groups are made for specific purposes. Groups expire after a duration which can be user specified. When a group expires all messages in it are deleted. Group expiry will be suspended till all users leave the group.

#creategroup <group name> [password] [anon/regd] [terminate time]
return
    @status <no>
    will create a new group. Anon if specified will allow access for anon users also. Regd allows only regd users, no anon. if password is provided list groups will return priv, or else pub. Default is public  and regd. Ffor no password and anon, specify #creategroup <gname> "" anon

#joingroup <gname> [passwd]
or
#changegroup <gname> [passwd]
return:
    @status <no>
    join a group. You can then post and read messages there. This will automatically make you leave any other group you were a part of.

#leavegroup
return:
    @status 0
    leave any group you had joined. (possible bug in code here)

#listmessages [parent no]
return:
    @status <no>
    if there is an error else
    @ret #listmessages <message no>
    <message name> <owner> <id> <parent id> <no of replies> <terminate time>    
    ...
    a useful command. If no parent no is specified it returns all the messages in the group. If specified it will return all messages with parent no as specified. All top level messages have parent no as 0. All messages that are replies have parent no as the no of the message they are a reply to. If a message has any replies it is accounted for. All top level messages have non zero terminate times. This is the no of seconds before the server deletes the message. All reply messages are deleted recursively when the parent message terminates.

#getmessage <mess no>
return on error:
    @status <no>
else
    @ret #getmessage <mess name> <parts> <no> <parent no> <replies> <terminate time>
    <text of message>
    Retrieves a message when its number is given, the parts parameter denotes how many lines of text the server is going to return.

#postmessage <name> [parent] [parts] [terminate time]
<text>
return:
    @status <no>
    post a message to the current group. If parent is non zero, terminate time is 0.If any parameters are not specified, default values are taken. Default parent id is 0, parts is 1. The parts parameter denotes how many lines of text will be posted to the server.

 

Status commands

#messagestatus
return
    @ret #messagestatus <status no>
    changes every time no of messages on the current group changes

#groupstatus
return
    @ret #groupstatus <no>
    Changes every time a group is added or removed.
   

Description of the error codes returned by @status

            This is a copy of the error_def.h file that is part of the server source. It has been annotated.

 

#define NO_ERROR                           0

#define UNKNOWN_ERROR            (-1)

#define NOMEMORY_ERROR          (-2)

            The server ran out of memory. This is a rare case.

#define NOTFOUND_ERROR           (-3)

            Some item that was expected to have been found was not. For example you tried to send a private message to a user name that did not exist.

#define INVALIDNAME_ERROR      (-4)

            The name you have used if not valid. This maybe due to invalid characters or invalid length. Try stick to text and length <30 bytes.

#define NOTEMPTY_ERROR            (-5)

            You attempted to delete or cause some other change to at item that was not empty. Example a room where there are users.

 

 

//Access Errors

#define ACCESS_NO_LOGIN                                   3500

            You are issuing commands without logging in.

#define ACCESS_NO_ANON                                   3501

            This item is not accessible by anonymous users

#define ACCESS_WRONGCMD                               3502

            No such command, the server did not recognize the command you sent.

#define ACCESS_DELETIONSET                             3503

            You tried to access at item that is invalid because it has been marked for deletion; such an item will delete at the next server refresh and cannot be used.

 

//Message Errors

#define MESSAGE_NO_GROUP                               3200

            You issued some message command without joining any group.

#define MESSAGE_WRONGPASSWD                     3201

            The password supplied for joining the message group is wrong.

 

 

//ChatRoom related errors

#define ROOM_WRONGNAME                                3100

            You specified an invalid room name or one that does not exist.

#define ROOM_WRONGPASSWD                           3101

            Wrong password for the room you chose to join.

#define ROOM_NAME_USED                                   3102

            You attempted to create a room with a name that is already used by another room.

#define ROOM_NOTOWNER                                   3103

            You attempted an operation on a room that only the room’s owner has access to.

 

//LOGIN errors

#define LOGIN_NO_USER_TYPE                 3000

            Your login command did not specify a login type regd or anon.

#define LOGIN_REGD_WRONGNAME                   3001

            No such registered user.

#define LOGIN_REGD_WRONGPASSWD   3002

            Wrong password.

#define LOGIN_ANON_USED                                  3003

            The name you requested is already being used by another anonymous user.

#define LOGIN_REGD_USED                                    3004

            The name you requested is reserved for a registered user.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CHATTER CLIENT

                        Chatter client encompasses all the basic features of a regular chat service and instant messaging service incorporating the concept of groups, rooms, direct chatting and posting messages. It provides with an ‘easy to use’ and efficient means of communication with a group of people as desired. Chatting can be directed to a set of friends or to everybody in a room. Also a private chat is supported, where messaging is with one user only. Multiple direct chats are allowed. Rooms and groups can be created by any user (anon/regd). They can be marked as public/private and like wise permit entries to regd/anon users.

 

Implementation

            Chatter client has the heart of its implementation in an event queue which holds all the events that have occurred and are awaiting completion. On logging in an EVENT_LOGIN is pushed into the queue. Everytime a packet arrives in the OnReceive() function , the queue is peeked to find the event and the corresponding handle is called .In the above case, an OnHandleLogin() is called.

            Similarly, there are events pre-defined for all packets requested. Examples are   EVENT_CREATEROOM, EVENT_CHANGEROOM, EVENT_GETMESSAGE, EVENT_SENDTO etc. The queue prevents the clash and undesired jumbling of packets especially in cases where the next packet arrives before the previous is handled, which may be because of varying network speeds and excessive load.

            The OnReceive() function sets a flag on entering it and resets it before leaving it. Next time OnReceive() is entered , if the flag is set then the function waits until it is reset. This waiting is nothing but waiting for the completion of the handling of the previous packet received. Once the handling of a particular event is handled, the corresponding event is popped from the queue.

 

            Timers are used to monitor and update the room users, group users and group messages periodically.

 

 

 

 

More About Rooms

 

            By default, every user logs into the Home room. Depending on his privileges he may/may not be allowed entry into a room.

On entering a room, the user is listed along with the other users as anon/regd depending on his login status. Message is sent by default to all users in the room. A user can mark out the desired users as friends, and then direct messages to friends only. He can choose to ignore a particular user, in which case, he doesn’t receive any messages sent from that particular user.

            A user can also start a private chat (direct messaging) with one user. In this case, he receives all messages from that particular user in a private chat dialog box. If the other user also starts a private chat with this user, then he too receives messages from this user in a private chat dialog box which is apart from the common room chat. On a broader aspect, this form of private chatting is indeed an instant messaging scheme.

 

More About Groups

 

          By default, a user is not in any group. If he chooses to join a   group he may/may not be permitted, just like the case with rooms. On entering a group, the user sees all the messages posted to this group. Message groups thus, form another important aspect of the chatter client. It facilitates easy communication between a pre decided group of people, handling privacy and security.

            In a group, the user can view the messages (their content), reply to a message or post new messages.

In case where a trust group is formed, this form of posting and reading messages becomes very useful.

 

If not used for some period of time, the rooms and groups are timed out by the server and the client keeps track of all such updates.

 

 

 

Limitations

Peer to peer connectivity supported by the chatter server is not implemented in the current version of chatter client.

CONCLUSIONS

 

This project can is best described in our opinions as a strangle with programming. In some senses we were not able to dedicate too much time to this project or have it as complete as we would have liked it to have been. On the other hand much has been achieved. We now have an understanding of the MSN protocol and how commercial quality messaging services work.

Though we did not manage to complete work on these, rather extensive ground work has been done on the Yahoo Messenger protocol, Rediff Bol and ICQ. This should serve as an excellent base to others who wish to pursue work in this line. Anyone wishing to continue work in this line should feel free to contact us.

The chat server we developed and its corresponding client is envisaged to be used in the future as Model Engineering Colleges official chat/communications service. This in many ways is a welcome change and a base for new standards and new concepts to take root which can be developed on by students of this college.

The source for the various project archives especially the server and its client should be available from the MEC server called www.meconline.org  atleast for the near future.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

REFERENCES

Here are lists of sources that we feel useful.

            Firstly there is nothing better than having an intelligent person you can run to with those killer problems. Further, it really helps to have staff who help you and a great Head of department.

            To the more conventional sources, firstly we would like to mention WPE written by Olivier Pasqualini. WPE is the Windows Packet editor, which turned out to be a great packet sniffing tool. Also in this category is Socket Spy by WinTECH software which provided a great API level debugger for windows socket calls to winsock.dll.

            On the development side, nothing greater that Visual C++. Those guys have really got it going. Also a special mention of Rhide. Rhide is a Turbo C++ style IDE originally developed for DJGPP under dos. It has now been ported to linux. Rhide is great development environment under linux.

            Also thanks to the endeavors of Richard Stallman who gave us gcc and the Open Source community for a practical free unix.

            Thanks to George Anescu for his implementation of AES encryption and to the maintainers of CodeProject (www.codeproject.com) for the great source archives they maintain.

            Special thanks to a Venkat for his curious site about protocol specifications at www.venkydude.com .

 

 

=======================================================================

 

 

 

APPENDIX

CHAT SERVER

       Calling this a chat server is actually a misnomer, because in effect it does a few things more than just providing the chat facilities. We felt this appendix to be necessary to fully understand the scope and expanse of this project and also to give an insight into the intricacies of writing such an application. The server is relatively small application of around four thousand lines of c++ code, but is virtually an exercise into concurrency management and resource allocation.

            In this documentation we will only be covering some aspects of the server that we feel might prove interesting to anyone working on a similar project and do not plan to elaborate on the whole application.

 

Functionality

            The server (in its current version) provides support for the following:

Users

            Users for the service are of two kinds

-         Registered

-         Anonymous

Registered are those have a login and password on the server, these are identifiable people who have specific rights on the server. Anonymous users can choose any free name, they have access to only certain services.

 

Chat

Chat Rooms

                        These maybe public (for everyone) or private (password protected). Users also have the option of creating rooms only registered users. Users in a room can send messages to each other or to all users.

            There are presently 3 kinds of messages supported

-         Public messages that go to everyone in that room

-         Private messages that go only to a specific user

-         Peer to Peer connectivity where 2 conforming clients can contact each other through the server

Rooms self delete themselves if they are not used for by anyone for a certain period.

 

Messages

            The server lets you post messages (like email) to the server (unlike email which is maintained on a per user basis). These are maintained by the server and can be read by other users that log onto the server. You may post replies to existing messages and thus the gives the functionality of message/discussion threads.

            Messages can be organized into Message Groups. Users are free to create their own message groups. Groups maybe only for registered users or for everyone. Also you may create private message groups.

            Self deletion also applies to messages, in which case they delete all their reply messages recursively. Reply messages get deleted when their parent message deletes and have no deletion of their own. Message Groups also self delete in which case they destroy all the messages within them also.

 

Error Tolerance

The most difficult aspect of writing applications that are meant to be reliable is when their environments are often unreliable. To safe guard against unexpected power failures, the server runs multiple threads that monitor the status of the current room architecture, message groups and the messages of each group. These threads are sleeping most of the time and awaken periodically and save their relative parts if any changes are detected.

 

Security

            This is at best a difficult concept to describe so let us tread carefully. There are two sides of security that are considered.

-         The data maintained by the server on its disks (passwords and such)

-         The sensitive data transferred across the network.

The data on the server is currently being saved in encrypted format. This presently uses AES encryption. The Rijndael encryption (a.k.a. AES) is a symmetric key recoverable encryption. Encryption on the server is maintained at 128 bit at the time of this writing.

The sensitive data transferred across the network, passwords etc, have rather difficult situation. This will be described later but for now it will suffice to mention that it is using non-recoverable Unix MD5 encryption.

 

 

Implementation Quirks

            A brief mention of some aspects of the implementation that deserve some thought. Some of the features described here are not yet fully enabled at the time of this writing, but will be by the time this document is available for public access.

 

Encryption

Data on the Server

            The data on the server is in Rijndael 128 bit encrypted. The problem is where should the key be maintained? The key is maintained within the server executable. This might come as a surprise to most who believe that having source code gives you absolute predictability of the behavior of the application.

            The key is ‘injected’ into the server executable. The injection code looks for certain character patterns in the executable and then inserts the encryption key into it. The server on next startup notices a fresh key and accordingly patches its executable code to move the key to other places after modifying it a bit. Thus standard file compares on different the server executables will gives mismatches but none of those will directly disclose the key.

Data across the network

            Everything across TCP/IP is track-able, no security there. Any recoverable encryption can be broken in time by a persistent hacker. The alternative is to use a non recoverable encryption.

            In our scheme we found that the best is to send the client a random string. The client concatenates the string and the password and MD5 encrypts it. This is transferred across the network. The server does the same process at his end and compares the results. The concatenation was required so that the same password looks different on every login, else a hacker just needs to replicate the bytes even if he doesn’t understand what they are. This is similar to the process followed by Microsoft for its msn login.

 

Application Architecture and Threads

            The application is our first attempt at writing UNIX based code, so there are some unfinished loop holes. It relies on the Posix -thread support provided by its host operating system. The current version was developed on a Redhat Linux 7.1 system. The server uses a plain text based protocol and can be connected and interfaced to by a regular telnet application.

            The application has a main thread that listens on port 6500 for connections. At the time of this writing the server is up and working on the MEC server which is currently 203.197.150.179. When a connection is received two threads branch off (per user) from the main thread. One of these is the receive thread that receives data sent by the user and the other is the send thread. The receive thread of the user connection has the task of ‘talking’ to the other parts of the server to get its tasks done. The send thread is contacted by other threads of the server as well the users receive thread to send information to the user.

            The application is has two major objects (c++ objects) that start on startup. These are ChatRoomManager and the MessageGroupManager. Another not so important object is the UserManager .

The ChatRoomManager is responsible for the creating a maintaining Rooms and to manage the flow of users between the rooms. This object runs threads for saving the rooms. This object also loads saved rooms on startup. Threads also run for each room which checks if the particular room is to self delete.

            The MessageGroupManager loads saved message groups. It maintains the save-thread that saves of the list of active message groups.  Each message group has its own thread that checks for its time out (for self deletion) as well as for saving the current messages.

 

Concurrency

            The extensive use of threading in the application gives rise to many concurrency related issues in the server such as resource sharing and deadlocks. These are similar to the discussions by Andrew Tanenbaum in his OS text. The only one we chosen to discuss here is the SetSendBuff issue.

The SetSendBuff

            Every client connected to the server has 2 dedicated threads. Of these the send thread sends the data to the user. This thread simply a function that sits in a loop that exits when the connection terminates. The loop’s purpose is to send data to the user whenever it is available.

            This gives rise to the classical producer consumer problem, with the additional quirk that there are many producers here and any of these or the consumer (the send thread) may go invalid at any point.

            The send thread checks a flag to see if data is set in a buffer. If the flag is found to be true, it sends the data. The issue comes in to maintain integral data in this buffer when many threads are trying to write into it and one is trying to read from it.

            The solution is by the use of a mutex to lock access to the flag and the buffer. That does not solve the problem, if multiple locks are set on the mutex, 2 threads consecutively locked to send data will not be able to so as the second one will find the flag set and the send thread is unable to access the data as the mutex has locked it out.

            What has been done in our implementation is a push-ahead-in-the-queue case. Assume that multiple locks on a mutex act as a queue of threads waiting for processing. Each producer writes locks the mutex, if the flag is not set, sets it and writes the data into buffer and unlocks the mutex. Every thread that finds the flag set knows that it cannot ever send the data unless the send thread sends the data. It also knows that the send thread is waiting behind in the queue to accomplish this. 

The solution is that every producer thread that finds the flag set merely unlocks the mutex and relocks it, repeatedly till the flag is unset. This has a an interesting effect on the mutex queue, the thread has effectively placed itself at the end of the mutex queue thus letting the send thread’s lock ahead of it. As each one does the same thing, the send thread will eventually have access to the buffer. It will send the data and then unset the flag. The next thread line will then have access to the buffer. And so on.

 

 

 

 

 

 

Notes

            The server had been, in its original implementation, done in about 5 or 6 days. The development still continues with little tweaks everyday and is slowly maturing. Some of these are recommended as worth taking a look at.

 

Among the acknowledgements for this development, I would like to mention George Anescu for his post of visual c++ code on Rijndael encryption at www.codeproject.com

 

Also thanks to the official maintainers of the MD5 encryption algorithm and its code, Mordechai T. Abzug.

 

Development tools used were gcc as the compiler and rhide as the IDE. A special mention and thanks to Robert Hohne for RH-IDE, which was a blast of fresh air compared other cryptic standard IDEs provided.  Rhide is a tc (under dos) like IDE that gives very good project options and file navigation and session maintenance features that seamlessly integrates with gcc.