ftp/ftpc.c
author Madhusudan.C.S <madhusudancs@gmail.com>
Mon, 18 Jan 2010 17:21:39 +0530
changeset 1 47438813ede2
parent 0 30d751ac6d49
permissions -rw-r--r--
Added support for handling binary files. The problem was I was using XDR strings for reading data, storing it and transferring to the client from the server. But since this is no better than null-terminated string, whenever data had \000 the data used to become corrupt from that point. So now I changed all data to be integer arrays so there is no question of corruption.

#include <rpc/rpc.h>
#include <stdio.h>
#include <string.h>
#include "ftp.h"

extern __thread int errno;

/*
 * Gets the requested file from the server by calling the
 * remote procedure in a loop
 */
int get_file(char *host, char *name)
{
    CLIENT *clnt;
    int bytes = 0, write_items;
    readfile_res *result;
    request req;
    FILE *file;

    /*
     * Initialize the request with the file name 
     */
    req.name = name;

    /*
     * 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);
    }

	/*
	 * Open the file for writing on the client machine
	 */
    file = fopen(name, "wb");

    /*
     * Call the remote procedure retrieve_file on the server.
	 * During each iteration of the loop remote procedure is
	 * called and only 1024 bytes of data is read and returned
	 * by the server. The loop terminates when the data returned
	 * from the server is less than 1024 bytes
     */
    while (1) {
        /*
	 * Specifies the byte position where the next read should be
	 * started in the server.
	 */
	req.start = 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);
        }

        /*
         * 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 and update the
	 * total bytes of data read till now.
         */
	write_items = fwrite(result->readfile_res_u.chunk.data, sizeof(int), result->readfile_res_u.chunk.items, file);
	bytes += result->readfile_res_u.chunk.items * (sizeof(int));
	if (result->readfile_res_u.chunk.items < MAXLEN) 
	    break;
    }

    fclose(file);

    return 0;
}

/*
 * Stores the file on the server by calling the remote
 * procedure in a loop
 */
int put_file(char *host, char *name)
{
    CLIENT *clnt;
    int *result;
    filechunk data;
    chunksend chunk;
    FILE *file;

    /*
     * 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);
    }

    /*
     * Open the file that should be stored on the server
     */
    file = fopen(name, "rb");

    /*
     * Initialize the chunk to be sent with the name
     * of the file
     */ 
    chunk.name = name;

    /*
     * Call the remote procedure readdir on the server
     * in a loop sending only 1024 bytes of data in each
     * iteration. The loop terminates once the data less
     * than 1024 bytes is sent.
     */
    while (1) {
  	chunk.items = fread(chunk.data, sizeof(int), MAXLEN, file);
        result = send_file_1(&chunk, 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 != 0) {
            /*
             * A remote system error occurred.
             * Print error message and stop.
             */
            errno = *result;
            perror(name);
            exit(1);
        }

        /*
         * Successfully got a chunk of the file.
         * Write into our local file.
         */
	if (chunk.items < MAXLEN) 
	    break;
    }

    fclose(file);

    return 0;
}

/*
 * Handles commands read on the command line and calls
 * the appropriate function to handle the command
 */
int read_command(char *host)
{
    char command[MAXLEN];

    printf("> ");
    fflush(stdin);
    gets(command);

    if (strncmp(command, "get", 3) == 0) {
	return get_file(host, command+4);
    } else if(strncmp(command, "put", 3) == 0){
 	return put_file(host, command+4);
    } else if(strncmp(command, "exit", 4) == 0){
	exit(0);
    } else {
	return -1;
    }
}

int main(int argc, char *argv[])
{
   int result;

   if (argc != 2) {
        fprintf(stderr, "usage: %s host\n", argv[0]);
        exit(1);
   }

   /*
    * Command handling loop
    */
   while(TRUE) {
       result = read_command(argv[1]);
   }

   return 0;
}