Using rpcgen to create a upload-download (client-server) program

Introduction

When we want to write a client server program in C/C++, we need to clutter with huge amount of details like socket creation, configuring the server structure, configuring the client structure etc. Is there any simplification there? The answer is yes. RPC(Rempte Procedure Call) is one of the rescuier (Note: there are several other tools like RMI which is for object oriented system). RPC is a powerful technique for constructing distributed, client-server based applications. Here the notion of local procedure call is extended. Clients can transparently make remote calls through a local procedure interface. In our following example we use rpcgen tool to generates our C code to implement an RPC protocol in ubuntu. Here we developed a Client-Server program using rpcgen which will have 3 services:
(1) Upload a file to server.
(2) Download a file from server.
(3) List out the files in a directory of server.

Requirements:

Here we used Ubuntu 16.04 and rpcgen tool.

Difficulty:

Medium

Time Required:

10 mins max , If you tightly follow the instructions below… Just copy and paste dude…

Installation

Step 1: Installing rpcgen

sudo apt install rpcbind

Step 2: create a directory anywhere (for example: in home directory) and create a file with .x extension there

 

mkdir rpcdir

cd rpcdir

vim up_down.x

Step 3: In up_down.x file type the following and save the file 

 

struct chunk{

char sendBuff[1025];

char dirname[1000];

int flag;

};

program UPDOWN {

version UPDOWN_1 {

struct chunk UD(chunk) = 1;

} = 1;

} = 0x2fffffff;

 

Step4: In the terminal run the following command:

rpcgen -a -C up_down.x

Step 5: We can see that the following extra files are generated:

Makefile.up_down, up_down_clnt.c, up_down_server.c, up_down_client.c, up_down.h up_down_svc.c, up_down_xdr.c

Step 6: We need to change the up_down_client.c and up_down_server.c files.

Step 7: Open the up_down_client.c file and copy-paste the following:

 

#include “up_down.h”

char *

get_file_name_from_path(char *filepath, char *delimiter)

{

char *token = strtok(filepath,”/”);

char *actual_file;

while( token != NULL ){

actual_file = token;

token = strtok(NULL, “/”);

}

return actual_file;

}

void

updown_1(char *host, char *command, char *filepath)

{

CLIENT *clnt;

struct chunk *result_1;

chunk ud_1_arg;

#ifndef DEBUG

clnt = clnt_create (host, UPDOWN, UPDOWN_1, “udp”);

if (clnt == NULL) {

clnt_pcreateerror (host);

exit (1);

}

#endif /* DEBUG */

FILE *fp;

if(strcmp(command,”-upload”) == 0){

ud_1_arg.flag = 1;

fp = fopen(filepath,”rb”);

char *actual_file = get_file_name_from_path(filepath, “/”);

if(fp==NULL)

{

printf(“Sorry the file cannot be opened”);

exit (1);

}

strcpy(ud_1_arg.dirname, actual_file);

while(1){

memset(&(ud_1_arg.sendBuff[0]), 0, sizeof(ud_1_arg.sendBuff)); //clear the whole buffer before sending anything

int nread = fread(ud_1_arg.sendBuff,1,1025,fp); //read from the file

if(nread > 0){//if you read successfully then send this data

result_1 = ud_1(&ud_1_arg, clnt);

}

if (nread < 1025){

if(ferror(fp))

printf(“Error reading\n”);

break;

}

}

//finally close the file

fclose(fp);

}

else if(strcmp(command,”-download”) == 0){

ud_1_arg.flag = 2;

strcpy(ud_1_arg.dirname, filepath);

char *actual_file = get_file_name_from_path(filepath, “/”);

FILE *fp;

fp = fopen(actual_file, “ab+”);

if(fp==NULL)

{

printf(“Sorry the file cannot be opened”);

exit (1);

}

do{

result_1 = ud_1(&ud_1_arg, clnt);

//printf(“%s”, result_1->sendBuff);

fwrite(result_1->sendBuff, 1,strlen(result_1->sendBuff),fp);

}while(result_1->flag!=4);

}

else if(strcmp(command,”-getdir”) == 0){

result_1 = ud_1(&ud_1_arg, clnt);

//puts(result_1->dirname);

char *token = strtok(result_1->dirname,”—“);

while( token != NULL ){

printf( ” %s\n”, token );

token = strtok(NULL, “—“);

}

}else{

printf(“Enter valid command!!!”);

}

//result_1 = ud_1(&ud_1_arg, clnt);

if (result_1 == (struct chunk *) NULL) {

clnt_perror (clnt, “call failed”);

}

#ifndef DEBUG

clnt_destroy (clnt);

#endif /* DEBUG */

}

int

main (int argc, char *argv[])

{

char *host, *command, *path = NULL;

if (argc < 3) {

printf (“usage: %s server_host -getdir \n %s server_host -upload|-download path_of_the_file\n”, argv[0], argv[0]);

exit (1);

}

host = argv[1];

command = argv[2];

if(argc > 3)

path = argv[3];

updown_1 (host, command, path);

exit (0);

}

Step8: Open the up_down_server.c file and copy-paste the following:

 

#include <sys/types.h>

#include <dirent.h>

#include “up_down.h”

struct chunk *

ud_1_svc(chunk *argp, struct svc_req *rqstp)

{

static struct chunk result;

if(argp->flag == 1){//get the data, dump it to a file

FILE *fp;

char *filename = argp->dirname;

char prefix[10] = “uploaded_”;

strcat(prefix,filename);

fp = fopen(prefix, “ab+”);

if(fp==NULL)

{

printf(“Sorry the file cannot be opened”);

exit (1);

}

//printf(“%s”,argp->sendBuff);

fwrite(argp->sendBuff, 1,strlen(argp->sendBuff),fp);

fclose(fp);

}else if(argp->flag == 2){// get a request to send the file

FILE *fp;

fp = fopen(argp->dirname, “rb+”);

if(fp==NULL)

{

printf(“Sorry the file cannot be opened”);

exit (1);

}

memset(&(argp->sendBuff[0]), 0, sizeof(argp->sendBuff)); //clear the whole buffer before sending anything

int nread = fread(argp->sendBuff,1,1025,fp); //read from the file

result = *argp;

if(nread > 0 && nread == 1025){//if you read successfully then send this data

return &result;

}else if(ferror(fp)){

printf(“Error reading\n”);

}else{

result.flag = 4;

return &result;

}

//finally close the file

fclose(fp);

}else{

DIR *dp;

struct dirent *ep;

dp = opendir (“./”);

if (dp != NULL)

{

while (ep = readdir (dp)){

char fname[50];

memset(&(fname[0]), 0, sizeof(fname));

strcpy(fname, ep->d_name);

strcat(fname, “—“);

strcat(result.dirname, fname);

}

}else

perror (“Couldn’t open the directory”);

}

return &result;

}

Step9: compile the files by typing:

make -f Makefile.up_down

You can see two executable file will generates: ./up_down_server and ./up_down_client.

Step10: open another terminal in the same directory.

Step11: Run the server by typing:

sudo ./up_down_server

Step12: In another terminal, for client side, to upload a file to the server

./up_down_client localhost -upload up_down.x

To get the directory listing from the server

./up_down_client localhost -getdir

To download a file(here text file only) from the server side

./up_down_client localhost -download /Desktop/downloadable.txt

Step13: Now take a rest… You did lot of programming.

Trouble shooting: In any case, the server is not able to running, type:

sudo systemctl add-wants multi-user.target rpcbind

Leave a Reply

Your email address will not be published. Required fields are marked *