Development Architecture ======================== Server ====== Server is made as master-slave server so that it should be able to fork a child process based upon a request from the flp client. Client ====== Client will remain in while loop tokeep on reading the commands from the standard input and after that it will parse the command and will check if the command is matching with either of the "library command", if it matches the particular function is called otherwise "Icommand not supported is printed". We can think opf as it is application level structure. How to handle cross-compilers and network byte order =================================================== Netwrk byte order ================ To handle this problem I used ntohs, ntohl and htons,htonl for every data sent accross the network. Cross-compiler ============= I have used only three different type of data as long, Char and unsigned short. So firt of all I defined this types as "#define" and then used given four functions to ship data accross the network. To handle this problem I made four function, I would like to mention that I made one global structure to send data accross Struct command{ unsigned short rpc_command; long data; } Function #1: long writeCmnd(int sock, struct command* cmnd, unsigned short rpc_call, long data) Function : WriteCmnd I/p - int sock pointer to command struct unsigned short rpc_call long data O/p- error number if failed otherwise 0 This function inturn call write_tlv to write data as type, length and value in case of failure it returns the error number "errno" Function #2: long writeTLV(int sock, unsigned short type, char * value) This function is inturn called by WriteCmnd to write tag, length and value individualy Function : WriteTLV : I/p int sock unsigned short type char * value : return value "0" if succesfull else "errno" For an example if I had to send RPC_OPENDIR, I would do three write as follows: write 1 - for type, which would be of "unsigend short" write2 - for length which "sizeof(unsigned short)" write3 - this will have the #define value of RPC_OPENDIR Now we can think of that for this structure we need to do 6 write command. To send "Char BUF", I used again the writeTLV function as it was having a switch statement and based upon the switch i was abl to made a decision as in case of Char Buf the length would be strlen(Buf) and the value of it would be buf only. Important thing to inform here is that I was having first two bytes for the info of the type tag, another two byte for the length and after that actual value will come. Now we need to have opposite function for reading: Function 3# ********** long readCmd(int sock, struct command * cmnd){ This function is opposite of WriteCmnd, it is used to read the read(3) and then based upon the three consecutive read the type, length and value is decided and then based upon that same value is allocated Function : readCmnd : I/P int sock : struct * command Return value : errno if fail othersie "0" means we are done BECAUSE WE KNOW THE BYTES REQUIRED A PARTICULAR TYPE WE CAN AVOID THE CROSS-COMPILER PROBLEM. Function 4# ********** long readBuf(int sock, char *dumy){ This function is used to read CHAR only Function : readBUf : I/P int sock : char * pwd : output "0" if successfull : else "errno" Again as per the aforesaid logic we can allocate the memory based upon the length field. This our the fuction at RPC level, now comes each and every command: I would like to mention few things for all the functions, I am printing errno uting strerror function and it will return. Also server and client execute one command after another in case of failure of some system call at the server's end the server will simply send the errno to the client and will return, now client will print the errno and will also return. In nutshell all the command are synchronous. RPC calls used: RPC_OPENDIR RPC_READDIR RPC_CLOSEDIR RPC_CHDIR RPC_GETWD RPC_GETCWD RPC_UNLINK RPC_WRITEFILE RPC_READFILE RPC_HELP my_ls() ====== This function in turn call three RPC_calls, RPC_OPENDIR after this rpc_call the server is able to succesfully open the the directory using opendir() system call and it NULL then the errno is passed on the client and the client will print it and will return. In case opendir() call is successfull the client will ask for RPC_READDIR and go inside the while loop which would be having a boolean called "NotEndOftheDirectory" so till the server reaches the end of the directory the client will keep on printing the info about the directory. To ship and read a info about the file I have used a function called outputStatInfo(char *filename, struct stat *st, struct command *cmnd) I/P : filename : pointer to stat structure : our standard structure Varous fields of the stat function is accessed to get the info and ship it to client. Please note I am not printing "." and "..". When the server is done it will inform the client and the client will break the while loop and aftre that it will call for RPC_CLOSEDIR which will inturn call closedir() system call. my_pwd() This function will call for RPC_PWD which will inturn call the getcwd() function at the server and will return the current working directory of the server. my_cd() This function will call for the RPC_CHDIR to simply call chdir() system call. my_rm() I have used unlik() system call which will only delete a file not a directory. cp() this function copies a local file to remote file so first it checks if the file is availble in given directory at the client side if it is not avilable then "user is informed as "BADFILENAME" in case file name is true then the file is opened in a read only mode and server is informed about the the file name so it will open th efile in writeonly mode and based upon the success of thses command the process will go further, now client will inform the size of the file and number of blocks it will be transfering and size of the last block, I have used maximumTransferSize as 8192, though it can be changed. So once server has got the information about the blocks and the last block size the actual transfer will take place. For this I have two functions called int receiveBuf(char * fBuf, int msize){ read(3) } int sendBuf(char * fBuf, int msize){ write(3) } these functions will be used with fread and fwrite, say at client side first client will do the fread for the MaxtrasferSize and then will use sendBuf will be used to send the Buf, again note that errno will be checked for the success of thses fucntions. Opposite of this would be at the server side which will first call the receivebuf and then do the fwrite. I have checked these function for transferring the object code and they worked well. scp() This function is opposite of cp, the difference is that the server will open the file is read only mode and then do fread and sendBuf and client will create the file in write only mode and then will do the receiveBuf and then will call the fwrite to write the buf. !command ======= This will simple call the system() call for the local execution. Quit I am using a flag called input_flag which will become 0 when quit is caleed and the close(socket number). At the server side I am catching the SIGHUP signal. Help ==== Help will simple print the command availble to the client.