#include #include #include #include #include #include #include #include #include #include #include #include #include #include "nfsclient.h" #include "myrpc/mount.h" #include "myrpc/nfs_prot.h" #define MAX_REQUEST_SIZE 1000 #define MAX_SERVERNAME_SIZE 50 #define MAX_DIRNAME_SIZE 150 #define QUEUE_LENGTH 10 #define NF 256 // Number of files #define NFS_MOUNT 1 #define NFS_OPEN 2 #define NFS_READ 3 #define NFS_CLOSE 4 #define TMD TheMountedDirectory // For convenience #define fsize diropres_u.diropres.attributes.size #define PRINTOUT 0 // Guess what? Since I moved the NFS functions into this file, EVERYTHING // is done with global variables. Woo hoo for global variables! static diropargs * TheMountedDirectory; // This represents the mounted directory in // the field "dir". "name" useful? static diropres * diropres_table[NF]; // We'll need a diropres{ults} for each one -- // that's the "fhandle" and the "fattr" // static int file_offset_table[NF]; // No longer used... I think static int being_used_by[NF]; // Number of clients using file static int entry_is_valid[NF]; // Whether the entries are still valid static int file_is_cached[NF]; // Whether the file is locally cached static char * known_file_names[NF]; // Names of cached files static int last_used[NF]; // Time the file was last used static int first_empty_slot = 0; // The address of the first empty slot static char * server; // The server we mounted from static char * TMDname; // The name of the mounted directory static CLIENT * client; // The NFS RPC client (not the mounting client) static char * cache_dir_name; // The name of the directory in which we cache static int cache_size; // The size of the cache static int amount_in_cache; // How many bytes are already in the cache static int current_timestamp; // The current timestamp (used for LRU) static int rpccalls; // For tracking server load static int socketsends, socketrecvs; static long socketsendbytes, socketrecvbytes, rpcbytes; int main(int argc, char * argv[]) { int listening_socket, new_socket; // int = socket descriptor int returncode, addrlen; int * boot; int bindsize, i; struct sockaddr listening_address; // Local socket struct sockaddr new_address; // For child process char * syscallstring; char * tempfilename; FILE * tempfile; rpccalls = 0; socketsends = 0; socketrecvs = 0; socketsendbytes = 0; socketrecvbytes = 0; rpcbytes = 0; boot = (int *) malloc (100 * sizeof(int)); server = (char *) malloc (MAX_SERVERNAME_SIZE * sizeof(char)); TMDname = (char *) malloc (MAX_DIRNAME_SIZE * sizeof(char)); // cache_dir_name = (char *) malloc (MAX_DIRNAME_SIZE * sizeof(char)); current_timestamp = 1; for (i=0; i name != NULL) { if (PRINTOUT) printf("NFSClient (handle_connection): NFSClient result diropargs.name is: "); if (PRINTOUT) printf("%s\n", (char *)(TheMountedDirectory->name)); } else { // if (PRINTOUT) printf("NFSClient (handle_connection): NFSClient result has no diropargs.name.\n"); } } else { if (PRINTOUT) printf("NFSClient (handle_connection): Dog! Couldn't mount that.\n"); } break; // Okay, mounting works fine. Now say we want to open a file. // The luser will give us a filename, which we will assume is // in the directory that luser wanted to mount. (It may include // subdirectory paths.) We have to return a FILE *. Fortunately // luser cannot luse it as a regular FILE, he can only luse it in // calls to my very own NFSread and NFSclose. So, I can use the // internal structure of FILE as anything I want. // // We'll get the API part to fake up the FILE * on the fly. All // it needs for that is the file descriptor. We don't even bother // to pass that in, since it's just an index that is determined // out here. // // We pretty much need to send this function every variable we // have, since we're not doing this in an object-oriented language. // // The result is 0 for a new file opened, 1 for found the filename // in the cache. The only difference is whether we set new values // in file_is_cached and being_used_by. (known_file_names is set // inside the function, and are we violating information hiding // enough?) case NFS_OPEN: if (PRINTOUT) printf("NFSClient (handle_connection): NFSopen called\n"); // And make the function call. We pass the args, // the socket, the mounted directory, a pointer // to a FILE * and a diropres * for our results, // and the server name, which we need to make // the RPC call. if (PRINTOUT) printf("NFSClient (handle_connection): server name is %s\n", server); if (PRINTOUT) printf("NFSClient (handle_connection): TMD name is %s\n", TMDname); // returncode = do_NFSopen (temp, the_socket, // TheMountedDirectory, first_empty_slot, // being_used_by, file_is_cached, // known_file_names, cache_dir_name, // diropres_table[first_empty_slot], // server, TMDname, client); returncode = do_NFSopen (temp, the_socket); if (PRINTOUT) printf("NFSClient (handle_connection): Ok, NFSopen return code is %d.\n", returncode); if (returncode == 0 || returncode == 1) { if (PRINTOUT) printf("NFSClient (handle_connection): That indicates success.\n"); } else { if (PRINTOUT) printf("NFSClient (handle_connection): I'm afraid that is an error.\n"); } break; // Okay, well, it would seem we have open working. After a file is opened, it // is stored in our big tables as a diropres (containing its actual file handle) // and as an int representing its logical position. // // Thus, if we want to read from a file, all we need is its file descriptor, // which our API will pass us as an int, which do_NFSread will parse. So // what do we pass in? The pointer to the table of "diropres"es, and the // pointer to the table of offsets. Oh, and of course the server name. We // actually shouldn't need the currently mounted directory, as the fhandle // ought to be all we need to access the file. case NFS_READ: // if (PRINTOUT) printf("NFSClient (handle_connection): NFSread called\n"); returncode = do_NFSread (temp, the_socket); // if (PRINTOUT) printf("NFSClient (handle_connection): Ok, NFSread return code is %d.\n", // returncode); if (returncode == 0) { // if (PRINTOUT) printf("NFSClient (handle_connection): That indicates success.\n"); } else { // if (PRINTOUT) printf("NFSClient (handle_connection): I'm afraid that is an error.\n"); } break; // As for closing the file, that is going to be a very simple NFS call. // Note that this is the only function that returns anything besides 0/non0. // It returns -1 on error and the number of the file to close otherwise. case NFS_CLOSE: if (PRINTOUT) printf("NFSClient (handle_connection): NFSclose called\n"); returncode = do_NFSclose(temp, the_socket); if (PRINTOUT) printf("NFSClient (handle_connection): Ok, NFSclose return code is %d.\n", returncode); if (returncode == -1) { if (PRINTOUT) printf("NFSClient (handle_connection): I'm afraid that is an error.\n"); } else { being_used_by[returncode] -= 1; if (being_used_by[returncode] < 0) being_used_by[returncode] = 0; if (PRINTOUT) printf("NFSClient (handle_connection): File %d ", returncode); if (PRINTOUT) printf("is now being used by %d clients.\n", being_used_by[returncode]); // file_offset_table[returncode] = 0; } break; default: socketrecvs--; socketrecvbytes -= returncode; // printf("NFSClient: REPORTING VALUES SIR!\n"); printf(": rpccalls == %d\n", rpccalls); printf(": rpcbytes == %ld\n", rpcbytes); //printf(": socketsends == %d\n", socketsends); //printf(": socketrecvs == %d\n", socketrecvs); //printf(": socketsendbytes == %ld\n", socketsendbytes); //printf(": socketrecvbytes == %ld\n", socketrecvbytes); printf(": rpccalls/cachesize == %.8f\n", (float)rpccalls/(float)cache_size); printf(": rpcbytes/cachesize == %.4f\n", (float)rpcbytes/(float)cache_size); break; } if (returncode < 0) { // if (PRINTOUT) printf("NFSClient (handle_connection): Couldn't fulfill request! D'oh.\n"); } else { // if (PRINTOUT) printf("NFSClient (handle_connection): Request fulfilled.\n"); } // if (PRINTOUT) printf("NFSClient (handle_connection): Freeing buffer.\n"); if (TRY_FREEING_MEMORY) free(buffer); // if (PRINTOUT) printf("NFSClient (handle_connection): Closing.\n"); //shutdown(the_socket, 2); close(the_socket); return(0); } // # # #### # # # # ##### // ## ## # # # # ## # # // # ## # # # # # # # # # // # # # # # # # # # # // # # # # # # # ## # // # # #### #### # # # // int do_NFSmount(char *arguments, int the_socket) { char ** lastposition = &arguments; char * temp; char * temp2; char * message; int bytes_sent; CLIENT * mountclient; fhstatus * result; dirpath * mountpath; int intresult; int i; // Get the host and pathnames temp = (char *) strtok_r(arguments, "\n", (char **) lastposition); if (PRINTOUT) printf("do_NFSmount: temp is %s\n", temp); strcpy(server, temp); temp2 = (char *) strtok_r(arguments, "\n", (char **) lastposition); if (PRINTOUT) printf("do_NFSmount: temp2 is %s\n", temp2); mountpath = &temp2; strcpy(TMDname, *mountpath); if (PRINTOUT) printf("do_NFSmount: server is %s\n", server); if (PRINTOUT) printf("do_NFSmount: *mountpath is %s\n", *mountpath); // Do the mounting mountclient = clnt_create(server, MOUNTPROG, MOUNTVERS, "udp"); if (mountclient == NULL) { if (PRINTOUT) printf("do_NFSmount: Couldn't create the MOUNTING client\n"); clnt_pcreateerror(server); intresult = -1; } else { if (PRINTOUT) printf("do_NFSmount: Created the MOUNTING client\n"); mountclient->cl_auth = authunix_create_default(); result = mountproc_mnt_1(mountpath, mountclient); rpccalls++; rpcbytes += (sizeof(fhstatus) + sizeof(dirpath) + sizeof(CLIENT)); intresult = result->fhs_status; if (PRINTOUT) printf("do_NFSmount: Result status is %d\n", intresult); // Okay, so what have we actually accomplished here? We have // made the RPC call that mounts the directory. That gets us // the first file handle (the handle of the directory we mounted). // The return value (result) of the call is something called an // "fhstatus", which contains, although I don't get unions really: // // An integer which is the status of the call. Zero means success. // An "fhandle" which is the directory we've mounted. // // Apparently we can use the fhandle of the directory to open up // files now. So we'll copy that fhandle into our "diropargs" TMD, // which is TheMountedDirectory, which is state kept by the NFS // client thingie (and wouldn't it be nice to do this in an object- // oriented language?) We also need to pass out the name of the // server. if (intresult != 0) { if (PRINTOUT) printf("do_NFSmount: That indicates some kind of error... sorry.\n"); } else { memcpy(TMD->dir.data, result->fhs_fh, NFS_FHSIZE); } // Okay, we are also going to create an NFS client and pass it back // up, so we don't have to create a new NFS client every time. // // NB: No longer passing up, just using global variable. client = clnt_create(server, NFS_PROGRAM, NFS_VERSION, "udp"); if (client == NULL) { if (PRINTOUT) printf("do_NFSmount: Couldn't create the NFS client"); clnt_pcreateerror(server); exit(1); } else { client ->cl_auth = authunix_create_default(); } } // We do one more thing, which is send a message containg the // return code (0 or -1) to the application that asked us to // make the call. message = (char *) malloc (100 * sizeof(char)); if (intresult == 0) { strcat(message, "0"); } else { strcat(message, "-1"); } bytes_sent = send(the_socket, message, strlen(message), 0); socketsends++; socketsendbytes += bytes_sent; if (bytes_sent < 0) { if (PRINTOUT) printf("Oops -- got error %d trying to use sockets. Quitting\n", errno); perror(" "); exit(1); } if (TRY_FREEING_MEMORY) free(message); if (PRINTOUT) printf("do_NFSmount: Done.\n"); return(intresult); } // #### ##### ###### # # // # # # # # ## # // # # # # ##### # # # // # # ##### # # # # // # # # # # ## // #### # ###### # # // Ok, so what's the simplest, stupidest possible way I could do this? // I'd say -- fetch the entire file upon opening. Then every time it is // opened or read from, just access the local copy instead of going to // the NFS server. Since there is no writing to the file, this will // maintain consistency. // // This will be a little slower than keeping it in memory, but the // process will obviously use up less memory. int do_NFSopen (char *arguments, int the_socket) { char ** lastposition = &arguments; char * temp; char * message; char * dirname; char * lastslash; int bytes_sent; diropres * dirresult; int intresult = -1; int slashfound = FALSE; diropargs * subdir; int mdreturncode; int i, j; FILE * cachefile; char * cachefilename; readargs * thearguments; readres * readresult; int amount_received; int file_size; int first_empty_slot = -1; int slot_to_use = -1; message = (char *) malloc (100 * sizeof(char)); // Get the filename if (PRINTOUT) printf("do_NFSopen: server name is %s\n", server); if (PRINTOUT) printf("do_NFSopen: TMDname is %s\n", TMDname); // if (PRINTOUT) printf("do_NFSopen: arguments is %s\n", arguments); temp = (char *) strtok_r(arguments, "\n", (char **) lastposition); // if (PRINTOUT) printf("do_NFSopen: first token in args is %s\n", temp); // First, make sure there is an argument there. if (temp != NULL) { // First, see if it the name is exactly the same as a previously // fetched file. If it is, we will just return that file descriptor. // The file descriptor is the same as the index into the filename // array. // // This is a fairly naive search, as it just checks every entry. // But there should never be so many entries that it's a problem. // Also, strcmp will return as soon as the first different character // is reached. for (i=0; i= 0 && i < NF) // It was already in there { // If we are in here, it means we have found a matching // file name, and should send the API that file desc, // instead of making all the connections and etc. // Besides sending over the socket, we also need to // inform the NFS client via the return code. being_used_by[i] += 1; last_used[i] = current_timestamp; current_timestamp++; if (PRINTOUT) printf("do_NFSopen: File %d ", i); if (PRINTOUT) printf("is now being used by %d clients.\n", being_used_by[i]); sprintf(message, "%d", i); if (PRINTOUT) printf("do_NFSopen: found file name %s at file number %d\n", known_file_names[i], i); bytes_sent = send(the_socket, message, strlen(message), 0); socketsends++; socketsendbytes += bytes_sent; if (bytes_sent < 0) { if (PRINTOUT) printf("Oops -- got error %d trying to use sockets. Quitting\n", errno); perror(" "); exit(1); } return(1); // This means we found it in cache } else // This should never happen { if (PRINTOUT) printf("do_NFSopen: Problem looking through cache!\n"); if (PRINTOUT) printf("do_NFSopen: Dying horribly.\n"); exit(1); } // If we get down here it means we still have to go get the file. // First, check for /s in the filename. If there are any, we need // to mount another directory. lastslash = strrchr(temp, '/'); if (lastslash != NULL) { slashfound = TRUE; lastslash[0] = '\0'; if (PRINTOUT) printf("do_NFSopen: directory name is %s, filename is %s\n", temp, lastslash + 1); dirname = (char *) malloc ((strlen(TMDname)+strlen(temp)+4) * sizeof(char)); strcat(dirname, TMDname); strcat(dirname, "/"); strcat(dirname, temp); if (PRINTOUT) printf("do_NFSopen: dirname is %s\n", dirname); subdir = (diropargs *) malloc (sizeof(diropargs)); mdreturncode = mountDirectory(dirname, subdir, server); if (PRINTOUT) printf("do_NFSopen: mountdir return code is %d\n", mdreturncode); subdir -> name = lastslash + 1; } else { if (PRINTOUT) printf("do_NFSopen: filename is %s\n", temp); // Put the file name into the diropargs for lookup. if (TMD) TMD -> name = temp; else client = NULL; } } if (temp == NULL) { if (PRINTOUT) printf("do_NFSopen: No arguments found.\n"); } else if (client == NULL) { if (PRINTOUT) printf("do_NFSopen: Couldn't use the client.\n"); if (PRINTOUT) printf("do_NFSopen: Did you remember to mount first?\n"); clnt_pcreateerror(server); } else { // Make the call. This now handles files in sub directories. // Anyway, the call returns a pointer to a "diropres", which holds a // status code and an fhandle, the fhandle being what we actually need. if (slashfound) { dirresult = nfsproc_lookup_2(subdir, client); rpccalls++; rpcbytes += (sizeof(diropres) + sizeof(diropargs) + sizeof(CLIENT)); } else { dirresult = nfsproc_lookup_2(TMD, client); rpccalls++; rpcbytes += (sizeof(diropres) + sizeof(diropargs) + sizeof(CLIENT)); } intresult = dirresult -> status; if (PRINTOUT) printf("do_NFSopen: Lookup status is %d\n", intresult); // We save the filehandle, in case the file is purged from the // cache, or never put there. memcpy(diropres_table[slot_to_use], dirresult, sizeof(diropres)); // Okay, so how big is the file? file_size = dirresult -> fsize; if (PRINTOUT) printf("do_NFSopen: size is %d\n", file_size); if (file_size > cache_size) { // If the file is bigger than the whole cache, we make // no attempt to cache it. file_is_cached[slot_to_use] = 0; if (PRINTOUT) printf("do_NFSopen: Not caching this file.\n"); } else { // We do want to cache the file. But is there room? // While there isn't, we'll remove files. while (amount_in_cache + file_size > cache_size) { purge_LRU_file_from_cache(); } // Okay, now we actually cache the file. First, we open it for writing. // The file will be cache_dir_name/# where # is the file descriptor. cachefilename = (char *) malloc ((strlen(cache_dir_name) + 8) * sizeof(char)); sprintf(cachefilename, "%s/%d", cache_dir_name, slot_to_use); if (PRINTOUT) printf("do_NFSopen: caching file in %s\n", cachefilename); cachefile = fopen(cachefilename, "w"); // Now we make the NFS call to read from the file..... thearguments = (readargs *) malloc (sizeof(readargs)); thearguments -> offset = 0; thearguments -> count = NFS_MAXDATA; thearguments -> totalcount = 0; // We do it as many times as necessary to get the whole file, // since we can only get 8 K at a time. while (thearguments -> offset < file_size) { // if (PRINTOUT) printf("do_NFSopen: Copying the file handle for the call...\n"); memcpy(thearguments -> file.data, dirresult -> diropres_u.diropres.file.data, NFS_FHSIZE); // if (PRINTOUT) printf("do_NFSopen: Trying to read over NFS...\n"); readresult = nfsproc_read_2(thearguments, client); rpccalls++; rpcbytes += (sizeof(readres) + sizeof(readargs) + sizeof(CLIENT)); intresult = readresult -> status; // if (PRINTOUT) printf("do_NFSread: int result is %d\n", intresult); // if (PRINTOUT) printf("do_NFSread: address of data is %d\n", // readresult -> readres_u.reply.data.data_val); if (intresult == 0) { amount_received = readresult -> readres_u.reply.data.data_len; rpcbytes += amount_received; // if (PRINTOUT) printf("do_NFSopen: got %d bytes\n", amount_received); } else break; // if (PRINTOUT) printf("do_NFSread: Here's what we got:\n"); for (i=0; i readres_u.reply.data.data_val)[i]); fprintf(cachefile, "%c", (char) (readresult -> readres_u.reply.data.data_val)[i]); } // if (PRINTOUT) printf("[end]\n"); thearguments -> offset += amount_received; } fclose(cachefile); if (intresult == 0) { file_is_cached[slot_to_use] = 1; amount_in_cache += file_size; if (intresult == 0) if (PRINTOUT) printf("do_NFSopen: cached file name %s for file number %d\n", known_file_names[slot_to_use], slot_to_use); if (PRINTOUT) printf("do_NFSopen: amount in cache is now %d\n", amount_in_cache); } } } // Last, we send the file descriptor to the API. It will do // the work of faking up a FILE *. We do check whether the file // was actually found. if (client == NULL || intresult != 0) { strcat(message, "-1"); } else { sprintf(message, "%d", slot_to_use); } bytes_sent = send(the_socket, message, strlen(message), 0); socketsends++; socketsendbytes += bytes_sent; if (bytes_sent < 0) { if (PRINTOUT) printf("Oops -- got error %d trying to use sockets. Quitting\n", errno); perror(" "); exit(1); } if (TRY_FREEING_MEMORY) free(dirname); if (TRY_FREEING_MEMORY) free(subdir); if (TRY_FREEING_MEMORY) free(message); return(intresult); } // ##### ###### ## ##### // # # # # # # # // # # ##### # # # # // ##### # ###### # # // # # # # # # # // # # ###### # # ##### int do_NFSread (char *arguments, int the_socket) { char ** lastposition = &arguments; char * temp; char * message; int bytes_sent; int filedesc, offset, amount; int argsgood = 1; // Protocol for read is // 3 (meaning read) // filedesc // offset // amount // Get the file descriptor -- should be the first argument. // if (PRINTOUT) printf("do_NFSread: server name is %s\n", server); temp = (char *) strtok_r(arguments, "\n", (char **) lastposition); if (temp == NULL) { if (PRINTOUT) printf("do_NFSread: No arguments found.\n"); argsgood = 0; } else { filedesc = atoi(temp); // if (PRINTOUT) printf("do_NFSread: filedesc is %d\n", filedesc); } // Get the offset -- should be the second argument. temp = (char *) strtok_r(arguments, "\n", (char **) lastposition); if (temp == NULL) { if (PRINTOUT) printf("do_NFSread: Not enough arguments.\n"); argsgood = 0; } else { offset = atoi(temp); if (PRINTOUT) printf("do_NFSread: offset is %d\n", offset); if (offset < 0) { if (PRINTOUT) printf("do_NFSread: which I guess means you didn't want any data.\n"); argsgood = 0; } } // Get the amount -- should be the third argument. temp = (char *) strtok_r(arguments, "\n", (char **) lastposition); if (temp == NULL) { if (PRINTOUT) printf("do_NFSread: Not enough arguments.\n"); argsgood = 0; } else { amount = atoi(temp); if (PRINTOUT) printf("do_NFSread: amount is %d\n", amount); if (amount > 8000) { if (PRINTOUT) printf("do_NFSread: but I'm afraid I can only give you 8000 bytes.\n"); amount = 8000; } else if (amount < 1) { if (PRINTOUT) printf("do_NFSread: which I guess means you didn't want any data.\n"); argsgood = 0; } } if (!argsgood) { message = "-1\n"; bytes_sent = send(the_socket, message, strlen(message), 0); socketsends++; socketsendbytes += bytes_sent; if (bytes_sent < 0) { if (PRINTOUT) printf("Oops -- got error %d trying to use sockets. Quitting\n", errno); perror(" "); exit(1); } } last_used[filedesc] = current_timestamp; current_timestamp++; if (file_is_cached[filedesc]) { return(do_cache_read(filedesc, offset, amount, the_socket)); } else { return(do_network_read(filedesc, offset, amount, the_socket)); } } // # # ###### ##### # # #### ##### # # // ## # # # # # # # # # # # // # # # ##### # # # # # # # #### // # # # # # # ## # # # ##### # # // # ## # # ## ## # # # # # # // # # ###### # # # #### # # # # // When we're reading out of a file, how do we know where in the file // we are? We'll actually use the offset in the FILE *. Since each // calling app has its own faked-up FILE *, we just set the offset // after each read, and then when the FILE * is passed back in for // another read, we'll use it to determine where to read from. // We keep passing in the diropres and all that, in case we don't have // the file in cache. int do_network_read (int filedesc, int offset, int amount, int the_socket) { char * message; int messagelength; int bytes_sent; readres * readresult; readargs * thearguments; int intresult = -1; int i, amount_received; char * filename; char numberstring[8] = "\0\0\0\0\0\0\0\0"; int numberstringlength; // What arguments do we expect this function to need? A file descriptor // (int) saying which file to read from. And an int saying how many bytes // to read. // if (PRINTOUT) printf("do_NFSread/network: server name is %s\n", server); // Check the client if (client == NULL) { if (PRINTOUT) printf("do_NFSread/network: Couldn't use the client.\n"); if (PRINTOUT) printf("do_NFSread/network: Did you remember to mount first?\n"); clnt_pcreateerror(server); } else { // if (PRINTOUT) printf("do_NFSread/network: Allocating readargs structures.\n"); thearguments = (readargs *) malloc (sizeof(readargs)); // logicalposition = file_offset_table[filedesc]; // thearguments -> offset = logicalposition; thearguments -> offset = offset; thearguments -> count = amount; thearguments -> totalcount = 0; memcpy(thearguments -> file.data, (diropres_table[filedesc]) -> diropres_u.diropres.file.data, NFS_FHSIZE); if (PRINTOUT) printf("do_NFSread/network: Trying to read from file number %d\n", filedesc); readresult = nfsproc_read_2(thearguments, client); rpccalls++; rpcbytes += (sizeof(readres) + sizeof(readargs) + sizeof(CLIENT)); intresult = readresult -> status; if (PRINTOUT) printf("do_NFSread/network: int result is %d\n", intresult); // The number of bytes we got is stored in the secret // location readres->readres_u.reply.data.data_len, // right next to the data itself. (Annoying!) if (intresult == 0) { amount_received = readresult -> readres_u.reply.data.data_len; rpcbytes += amount_received; if (PRINTOUT) printf("do_NFSread/network: got %d bytes \n", amount_received); // Craft the response to be sent over the socket sprintf(numberstring, "%d\n", amount_received); numberstringlength = strlen(numberstring); // if (PRINTOUT) printf("do_NFSread/network: numberstring is %d chars long ", // numberstringlength); // if (PRINTOUT) printf("and is \n%s[end]\n", numberstring); message = (char *) malloc ( (10 + amount_received) * sizeof (char)); bzero(message, (10+amount_received)); strcat(message, numberstring); memcpy((message+numberstringlength), readresult -> readres_u.reply.data.data_val, amount_received); messagelength = numberstringlength + amount_received; // if (PRINTOUT) printf("--------------\n"); // if (PRINTOUT) printf("%s\n", message); // if (PRINTOUT) printf("--------------\n"); } } if (client == NULL || intresult != 0) { // message = (char *) malloc (8 * sizeof(char)); // strcat(message, "-1\n"); message = "-1\n"; messagelength = strlen(message); } else { // message = (char *) malloc ((10 + amount_received) * sizeof (char)); // sprintf(message, "%d", amount_received); } bytes_sent = send(the_socket, message, messagelength, 0); socketsends++; socketsendbytes += bytes_sent; if (bytes_sent < 0) { if (PRINTOUT) printf("Oops -- got error %d trying to use sockets. Quitting\n", errno); perror(" "); exit(1); } if (TRY_FREEING_MEMORY) free(thearguments); if (TRY_FREEING_MEMORY) free(message); if (intresult != 0) { return (intresult); } return 0; } // // #### ## #### # # ###### ##### // # # # # # # # # # # # // # # # # ###### ##### # # // # ###### # # # # # # // # # # # # # # # # # # // #### # # #### # # ###### ##### int do_cache_read (int filedesc, int offset, int amount, int the_socket) { char * cachefilename; FILE * cachefile; int amount_read = 0; int ch; char * message; char * numberstring; int numberstring_length; int bytes_sent; message = (char *) malloc((12 + amount) * sizeof(char)); numberstring = (char *) malloc (8 * sizeof(char)); cachefilename = (char *) malloc ((strlen(cache_dir_name) + 8) * sizeof(char)); sprintf(cachefilename, "%s/%d", cache_dir_name, filedesc); if (PRINTOUT) printf("do_NFSread/cache: reading from %s\n", cachefilename); cachefile = fopen(cachefilename, "r"); fseek(cachefile, offset, SEEK_SET); ch = fgetc(cachefile); while (amount_read < amount && ch != EOF) { message[amount_read+10] = ch; ch = fgetc(cachefile); amount_read++; } message[amount_read+10] = '\0'; sprintf(numberstring, "%d\n", amount_read); numberstring_length = strlen(numberstring); memcpy(message+10-numberstring_length, numberstring, numberstring_length); // if (PRINTOUT) printf("do_NFSread/cache: numberstring is %sand its length is %d", // numberstring, numberstring_length); // if (PRINTOUT) printf("do_NFSread/cache: message+10-%d is\n%s\n", // numberstring_length, message+10-numberstring_length); // if (PRINTOUT) printf("do_NFSread/cache: numberstring_length+amount_read is %d\n", // numberstring_length+amount_read); // if (PRINTOUT) printf("do_NFSread/cache: strlen(message+10-numberstring_length) is %d\n", // strlen(message+10-numberstring_length)); fclose(cachefile); // bytes_sent = send(the_socket, message+10-numberstring_length, // strlen(message+10-numberstring_length), 0); bytes_sent = send(the_socket, message+10-numberstring_length, numberstring_length+amount_read, 0); socketsends++; socketsendbytes += bytes_sent; if (bytes_sent < 0) { if (PRINTOUT) printf("Oops -- got error %d trying to use sockets. Quitting\n", errno); perror(" "); exit(1); } if (TRY_FREEING_MEMORY) free(message); return 0; } // // #### # #### #### ###### // # # # # # # # // # # # # #### ##### // # # # # # # // # # # # # # # # // #### ###### #### #### ###### // // NFSclose only figures out the file number to close and passes it // back up. int do_NFSclose (char *arguments, int the_socket) { char ** lastposition = &arguments; char * temp; int filedesc; int bytes_sent; char * message = "0\n"; // Get the file descriptor -- should be the first argument. temp = (char *) strtok_r(arguments, "\n", (char **) lastposition); if (temp == NULL) { if (PRINTOUT) printf("do_NFSclose: No arguments found.\n"); filedesc = -1; } else { filedesc = atoi(temp); if (PRINTOUT) printf("do_NFSclose: filedesc is %d\n", filedesc); } bytes_sent = send(the_socket, message, strlen(message), 0); socketsends++; socketsendbytes += bytes_sent; if (bytes_sent < 0) { if (PRINTOUT) printf("Oops -- got error %d trying to use sockets.\n", errno); perror(" "); exit(1); } return (filedesc); } // ##### ##### ###### ##### ##### # # // # # # # # # # # # // # # # # ##### # # # // ##### ##### # # # # // # # # # # # # // # # # ###### # # # void prettyprintFILE(FILE * fin, const char * prefix) { if (PRINTOUT) printf("%sFile descriptor is %d, logical position is %d\n", prefix, fin->_file, fin->_cnt); } // ###### // # # #### # # # # ##### # # # ##### // ## ## # # # # ## # # # # # # # // # ## # # # # # # # # # # # # # # // # # # # # # # # # # # # # ##### // # # # # # # # ## # # # # # # // # # #### #### # # # ###### # # # // int mountDirectory(char *dirname, diropargs * doaout, char * server) { CLIENT * client; fhstatus * result; dirpath * mountpath; int i, intresult; // Get the host and pathnames mountpath = &dirname; if (PRINTOUT) printf("mountDirectory: server is %s\n", server); if (PRINTOUT) printf("mountDirectory: *mountpath is %s\n", *mountpath); // Do the mounting client = clnt_create(server, MOUNTPROG, MOUNTVERS, "udp"); if (client == NULL) { if (PRINTOUT) printf("mountDirectory: Couldn't create the MOUNTING client"); clnt_pcreateerror(server); return -1; } else { client->cl_auth = authunix_create_default(); result = mountproc_mnt_1(mountpath, client); rpccalls++; rpcbytes += (sizeof(fhstatus) + sizeof(dirpath) + sizeof(CLIENT)); intresult = result->fhs_status; if (PRINTOUT) printf("mountDirectory: Result status is %d\n", intresult); if (intresult != 0) { if (PRINTOUT) printf("mountDirectory: That indicates some kind of error... sorry.\n"); } else { memcpy(doaout->dir.data, result->fhs_fh, NFS_FHSIZE); } return 0; } } // ##### ###### # ###### ##### ###### // # # # # # # # // # # ##### # ##### # ##### // # # # # # # # // # # # # # # # // ##### ###### ###### ###### # ###### int delete_least_recently_used_entry() { int i; int entry_to_delete = -1; int returncode = 34; // First make sure there's one that's not being used. // If there isn't return -1. // If we happen across one that isn't even valid, just // return that. for (i = 0; i fsize; amount_in_cache -= removed_size; if (PRINTOUT) printf("Purge: Okay, I purged file number %d, which had size %d\n", file_to_remove, removed_size); if (PRINTOUT) printf("Purge: The cache now holds %d bytes.\n", amount_in_cache); return 0; }