write a SUN RPC based remote file server program to demonstrate its use. Write a
ID: 3639588 • Letter: W
Question
write a SUN RPC based remote file server program to demonstrate its use. Write a single server (server) and two different client (rget and rput) programs.Server:
This is a stateful remote file server. It implements four remote procedures: open, read, write, and close. All files are read from and written into the directory in which the server is running.
rget:
This client implements fetching a remote file. The usage is:
rget remote_host remote_file local_file
The command will open the remote_file and issue one or more read requests to the server, writing the results to local_file.
rput:
This client implements sending a file to the remote server. The usage is:
rput remote_host local_file remote_file
The command will open the local_file for reading, open remote_file for writing, and read bytes from local_file, sending write requests to the server.
Your remote interface (RPC IDL) is defined as follows:
/* filerpc.x - description of remote file access */
const MAXNAME = 128; /* max length of file name */
const MAXBUF = 512; /* max size of read/write buffer */
typedef string filename<MAXNAME>; /* filename type */
typedef int handle; /* remote file handle type */
struct openargs { /* parameters for open */
filename file;
int mode;
};
struct readargs { /* parameters for read */
handle h;
int nbytes;
};
union readresults switch(int status) { /* return values from read */
case 0: opaque buf<MAXBUF>;
case 1: int error;
};
struct writeargs { /* parameters for write */
handle h;
opaque buf<MAXBUF>;
};
union writeresults switch(int status) { /* return values from write */
case 0: int nbytes;
case 1: int error;
};
program FRPC_PROG {
version FRPC_VERS {
handle OPEN(openargs) = 1; /* open file */
bool CLOSE(handle) = 2; /* close file */
readresults READ(readargs) = 3; /* read bytes */
writeresults WRITE(writeargs) = 4; /* write bytes */
} = 1;
} = 0x1NNNNNNN; /* program number goes here */
The only part of this file you should modify is the program number on the last line.
server
Your server implements the remote procedures defined in above IDL file.
open
• The server maintains a table of file descriptors, one for each open file. An open request returns a file handle that is an index into this table. The table is limited to supporting a maximum of ten open files. Any additional open requests should be rejected.
• Open accepts a file name and a mode for opening the file.
o A file name is limited to a maximum of MAXNAME characters (symbol defined in above IDL) and cannot contain the character '/'.This restricts all files to the current directory.
o The mode for open is any of the valid modes for the open system call. Typically these will be O_RDONLY for reading or O_WRONLY|O_CREAT for create & write.
• If there is no free file handle available, the open request will fail immediately, returning a -1.
• If the open system call succeeds, a free table entry in the table of file descriptors is populated with the file descriptor returned by open and the handle (index of the entry) is returned to the requester.
read
• A read request contains a file handle (obtained from open) and a number indicating the maximum number of bytes to read from the file.
• If the file handle is invalid (does not correspond to an open file or is out of range), an error code of 1000 is returned.
• Up to MAXBUF bytes can be read. If the nbytes field is greater than that, MAXBUF bytes will be used instead.
• If the read system call succeeds, then the buffer is returned along with the number of bytes that were actually read (which may be 0 for end of file). The return parameter is a variable sized buffer, so you need to set the buf_len member to the number of bytes and the buf_val member to the buffer. The status element of the return structure is set to 0 to indicate success.
• If the read system call fails, the status element of the return structure is set to 1 to indicate failure. Instead of a return buffer, the error element is set to the value of errno (error code from the last system call; you need to #include <errno.h> in your server code).
write
• A write request contains a file handle (obtained from open) and a variable size buffer containing the bytes to be written to the file. Since this is a variable sized buffer, your client programs will need to set the buf_len member to the number of bytes and the buf_val member to the data to be written.
• If the file handle is invalid (does not correspond to an open file or is out of range), an error code of 1000 is returned.
• If the write system call succeeds, the number of bytes with the number of bytes that were actually written is returned in the nbytes field. The status field of the return structure is set to indicate success.
• If the write system call fails, the status element of the return structure is set to 1 to indicate failure. The error element is set to the value of errno.
close
• A close request contains a file handle (obtained from open) and returns TRUE or FALSE.
• If the file handle is invalid (does not correspond to an open file or is out of range), a value of FALSE is returned.
• Otherwise, the corresponding file descriptor is closed with the close system call and a TRUE is returned.
rget
The rget client fetches a file from the server using the abovementioned remote procedure calls.
• The command accepts three parameters: the name of the host running the server, the remote file name, and the local file name.
• The remote file is opened for reading (O_RDONLY). If this succeeds, the local file is created.
• Data from the remote file is read a block at a time and written to the local file.
rput
The rput client fetches a file from the server using the abovementioned remote procedure calls.
• The command accepts three parameters: the name of the host running the server, the local file name, and the remote file name.
• The local file is opened. If this succeeds, the remote file is then opened for creation (O_WRONLY|O_CREAT).
• Data from the local file is read a block at a time and written to the remote file.
Explanation / Answer
const MAXLEN = 1024; /* * Type for storing path */ typedef string filename; /* * Structure for sending request. Expects the path of the file * and the byte number at which to start reading the file from */ struct request { filename name; int start; }; /* * Type that represents the structute for request */ typedef struct request request; /* * Type for storing a chunk of the file that is being * sent from the server to the client in the current * remote procedure call */ typedef string filechunk; /* * Response sent by the server to the client as a response * to remote procedure call, containing the filechunk for * the current call and number of bytes actually read */ struct chunkreceive { filechunk data; int bytes; }; /* * Type that represents the structure for file's chunks * to be received from the server */ typedef struct chunkreceive chunkreceive; /* * File data sent by the server from client to store * it on the server along with the filename and the * number of bytes in the data */ struct chunksend { filename name; filechunk data; int bytes; }; /* * Type that represents the structure for file's chunks * to be sent to the server */ typedef struct chunksend chunksend; /* * union for returning from remote procedure call, returns * the proper chunkdata response if everything worked fine * or will return the error number if an error occured */ union readfile_res switch (int errno) { case 0: chunkreceive chunk; default: void; }; /* * Remote procedure defined in the Interface Definition Language * of SUN RPC, contains PROGRAM and VERSION name definitions and * the remote procedure signature */ program FTPPROG { version FTPVER { readfile_res retrieve_file(request *) = 1; int send_file(chunksend *) = 2; } = 1; } = 0x20000011; My Server: #include #include #include "ftp.h" extern __thread int errno; readfile_res* retrieve_file_1_svc(request *req, struct svc_req *rqstp) { FILE *file; char data[1024]; int bytes; static readfile_res res; file = fopen(req->name, "rb"); if (file == NULL) { res.errno = errno; return (&res); } fseek (file, req->start, SEEK_SET); bytes = fread(data, 1, 1024, file); res.readfile_res_u.chunk.data = data; res.readfile_res_u.chunk.bytes = bytes; /* * Return the result */ res.errno = 0; fclose(file); return (&res); } int* send_file_1_svc(chunksend *rec, struct svc_req *rqstp) { FILE *file; int write_bytes; static int result; file = fopen(rec->name, "a"); if (file == NULL) { result = errno; return &result; } write_bytes = fwrite(rec->data, 1, rec->bytes, file); fclose(file); result = 0; return &result; } My Client: #include #include #include #include "ftp.h" extern __thread int errno; int get_file(char *host, char *name) { CLIENT *clnt; int total_bytes = 0, write_bytes; readfile_res *result; request req; FILE *file; req.name = name; req.start = 0; /* * Create client handle used for calling FTPPROG on * the server designated on the command line. Use * the tcp protocol when contacting the server. */ clnt = clnt_create(host, FTPPROG, FTPVER, "tcp"); if (clnt == NULL) { /* * Couldn't establish connection with server. * Print error message and stop. */ clnt_pcreateerror(host); exit(1); } file = fopen(name, "wb"); /* * Call the remote procedure readdir on the server */ while (1) { req.start = total_bytes; result = retrieve_file_1(&req, clnt); if (result == NULL) { /* * An RPC error occurred while calling the server. * Print error message and stop. */ clnt_perror(clnt, host); exit(1); } /* * Okay, we successfully called the remote procedure. */ if (result->errno != 0) { /* * A remote system error occurred. * Print error message and stop. */ errno = result->errno; perror(name); exit(1); } /* * Successfully got a chunk of the file. * Write into our local file. */ write_bytes = fwrite(result->readfile_res_u.chunk.data, 1, result->readfile_res_u.chunk.bytes, file); total_bytes += result->readfile_res_u.chunk.bytes; if (result->readfile_res_u.chunk.bytesRelated Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.