I've been breaking my head for the past few days over the following: I want to send a file of any size/type over SunRPC. On client side I read the file into a linked list, with each node containing a buffer of size 1024. If I print all the buffers before sending it over RPC, I get the correct output (i.e. the whole file is printed). However, when I send it over RPC and print all the buffers on the server's side, the last node is printed incorrectly, as if it is not transferred correctly.
I've tested my code with a large .txt file (100,5kB) and here it does seem to work. However with a .pdf file (7,9kB) it does not.
Here is my (relevant) code:
.x file:
struct node {
string buf<>;
long bytes;
struct node* next;
};
struct paper {
string author<>;
string title<>;
struct node* file;
struct paper* next;
};
typedef long add_out;
program PAPERSERVER_PROG {
version PAPERSERVER_VERS {
add_out ADDPAPER(paper) = 1;
} = 1;
} = 0x20001234;
paperclient.c: (when i print all the buffers at the end of this function, the output is correct)
#define BUF_SIZE 1024
void add_paper(char** argv, CLIENT* cl) {
struct paper in;
add_out *out;
struct node* tmp;
struct node* tmp2;
struct node start;
char buf[BUF_SIZE];
size_t read;
// Open the file
FILE *fp = fopen(argv[5], "rb");
if (fp == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
in.author = strdup(argv[3]);
in.title = strdup(argv[4]);
in.file = &start;
in.next = NULL;
bzero(buf, BUF_SIZE);
read = fread(buf, 1, BUF_SIZE, fp);
if (ferror(fp)) {
perror("fread error");
exit(2);
}
tmp = &start;
tmp->buf = calloc(BUF_SIZE, 1);
if (tmp->buf == NULL) {
perror("malloc tmp->buf");
exit(2);
}
tmp->bytes = read;
tmp->buf = memcpy(tmp->buf, buf, read);
// Cycle until end of file
while (!feof(fp)) {
bzero(buf, BUF_SIZE);
tmp->next = (struct node*) calloc(sizeof(struct node), 1);
if (tmp->next == NULL) {
perror("malloc tmp->next");
exit(2);
}
tmp = tmp->next;
read = fread(buf, 1, BUF_SIZE, fp);
if (ferror(fp)) {
perror("fread error");
exit(2);
}
printf("read:%zu\n", read);
tmp->buf = calloc(BUF_SIZE+1, 1);
if (tmp->buf == NULL) {
perror("malloc tmp->buf");
exit(2);
}
tmp->bytes = read;
tmp->buf = memcpy(tmp->buf, buf, read);
}
tmp->next = NULL;
out = addpaper_1(&in, cl);
if (out == NULL) {
printf("Error: %s\n", clnt_sperror(cl, argv[1]));
} else {
printf("%ld\n", *out);
}
clnt_destroy(cl);
}
paperserver.c (Here the output is wrong)
add_out* addpaper_1_svc(paper* in, struct svc_req* rqstp) {
static add_out out;
struct node* file;
long written;
file = in->file;
char* buf;
while (file != NULL) {
buf = calloc(BUF_SIZE + 1, 1);
buf = memcpy(buf, file->buf, file->bytes);
written = fwrite(buf, 1, file->bytes, stdout);
if (ferror(stdout)) {
perror("fwrite error");
exit(2);
}
file = file->next;
}
out = 0;
return &out;
}
EDIT:
To specify more about my expected output. I expect the file I send over the server to be output exactly the same as if I would've called cat <filename>
. However, the output seems to be in the wrong order. The last buffer seems to be overwritten with some of the contents of the beginning of the file. This is with one .pdf file is used. With another .pdf it DOES work, with .txt it DOES work, but with a .jpg it did not. When I get the md5sum
of the output, it changes with every call. This makes me think it prints bytes not actually initialized by my program. Furthermore when I use valgrind I get the following errors (only with the files that don't work correctly):
==2375== Invalid read of size 8
==2375== at 0x4C2F790: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2375== by 0x400D3E: addpaper_1_svc (paperserver.c:38)
==2375== by 0x40128D: paperserver_prog_1 (paperserver_svc.c:76)
==2375== by 0x4F626D0: svc_getreq_common (svc.c:534)
==2375== by 0x4F6281D: svc_getreq_poll (svc.c:460)
==2375== by 0x4F65BFE: svc_run (svc_run.c:96)
==2375== by 0x401437: main (paperserver_svc.c:114)
==2375== Address 0x527af48 is 392 bytes inside a block of size 394 alloc'd
==2375== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2375== by 0x4F64D04: xdr_string (xdr.c:788)
==2375== by 0x401487: xdr_node (paperserver_xdr.c:13)
==2375== by 0x4F656B7: xdr_pointer (xdr_ref.c:84)
==2375== by 0x40155C: xdr_paper (paperserver_xdr.c:31)
==2375== by 0x401268: paperserver_prog_1 (paperserver_svc.c:72)
==2375== by 0x4F626D0: svc_getreq_common (svc.c:534)
==2375== by 0x4F6281D: svc_getreq_poll (svc.c:460)
==2375== by 0x4F65BFE: svc_run (svc_run.c:96)
==2375== by 0x401437: main (paperserver_svc.c:114)
==2375==
==2375== Invalid read of size 8
==2375== at 0x4C2F79E: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2375== by 0x400D3E: addpaper_1_svc (paperserver.c:38)
==2375== by 0x40128D: paperserver_prog_1 (paperserver_svc.c:76)
==2375== by 0x4F626D0: svc_getreq_common (svc.c:534)
==2375== by 0x4F6281D: svc_getreq_poll (svc.c:460)
==2375== by 0x4F65BFE: svc_run (svc_run.c:96)
==2375== by 0x401437: main (paperserver_svc.c:114)
==2375== Address 0x527af50 is 6 bytes after a block of size 394 alloc'd
==2375== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2375== by 0x4F64D04: xdr_string (xdr.c:788)
==2375== by 0x401487: xdr_node (paperserver_xdr.c:13)
==2375== by 0x4F656B7: xdr_pointer (xdr_ref.c:84)
==2375== by 0x40155C: xdr_paper (paperserver_xdr.c:31)
==2375== by 0x401268: paperserver_prog_1 (paperserver_svc.c:72)
==2375== by 0x4F626D0: svc_getreq_common (svc.c:534)
==2375== by 0x4F6281D: svc_getreq_poll (svc.c:460)
==2375== by 0x4F65BFE: svc_run (svc_run.c:96)
==2375== by 0x401437: main (paperserver_svc.c:114)