How would you receive a file sent with 'sendfile'? - c

I'm trying to implement a basic file server. I have been trying to use the sendfile command found here: http://linux.die.net/man/2/sendfile I'm using TCP.
I can have it send fine, but its sending in binary and I'm not sure if thats the hang up.
I am trying to receive the file with recv, but it isn't coming through correctly.
Is there a special way to receive a binary file, and put it into a string?
EDIT:
Asked to supply some code, here it is:
SENDFILE Call (from Server process)
FILE * file = fopen(filename,"rb");
if ( file != NULL)
{
/*FILE EXISITS*/
//Get file size (which is why we opened in binary)
fseek(file, 0L, SEEK_END);
int sz = ftell(file);
fseek(file,0L,SEEK_SET);
//Send the file
sendfile(fd,(int)file,0,sz);
//Cleanup
fclose(file);
}
RECIEVE Call (from Client process, even more basic than a loop, just want a single letter)
//recieve file
char fileBuffer[1000];
recv(sockfd,fileBuffer,1,0);
fprintf(stderr,"\nContents:\n");
fprintf(stderr,"%c",fileBuffer[0]);
EDIT: wrote some code for checking return values. sendfile is giving errno 9 - bad file number. Which im assuming is at my second file descriptor in the call (the one for the file i'm sending). I cast it as an int because sendfile was complaining it wasn't an int.
How should I use send file given the file pointer code I have used above in th sendfile call?

You cannot use sendfile() with a FILE*, you need a file descriptor as given by open(), close() and friends. You cannot just cast a FILE* into an int and thinking it would work.
Maybe you should read the sendfile() manpage for more information.

There is no special way. You just receive with read() or recv().
Probably, you've got your receiving code wrong.

Related

Is it possible to parse pcap packets from buffer

I have a bunch of huge pcap files (> 10GB) that are compressed with lzma. I need to parse them on my machine, and I do not have enough space to uncompress them first. There are many libs that can stream lzma from file. The problem is on libpcap side, I've read it's API several times, and couldn't find any way to parse a buffer. What I see in the libs' source code is that it first reads the magic byte and file header with fread:
amt_read = fread((char *)&magic, 1, sizeof(magic), fp);
...
amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1, sizeof(hdr) - sizeof(hdr.magic), fp);
And then pcap_next_packet also uses fread to read next packet from file. So it looks like it's hard to pass a buffer from lzma stream to it. On the other hand, these functions are stored in pcap_t structure as pointers. So I can implement my own procedures for it, however, this way I will have to duplicate a lot of code from libpcap. Does anybody know how to do it without hacking into libpcap?
Am I missing something in libpcap API?
Update: With #Martin and others help, I managed to make it work. I'll post the implementation, so people who look for a way to do it can use it.
if (check_file_exists("/path/to/file.pcap.xz")) {
return;
}
// first open a pipe
FILE *pipe = popen("xz -d -c /path/to/file.pcap.xz", "r");
if (!pipe) {
// handle error somehow
return;
}
char errbuff[256];
// note pcap_fopen_offline function that takes FILE* instead of name
pcap_t *pcap = pcap_fopen_offline(pipe, errbuff);
struct pcap_pkthdr *header;
uint8_t *data;
while (pcap_next_ex(pcap, &header, &data)) {
// handle packets
}
Particularly for large pcap files, it's preferable not to read the whole thing into memory first anyway. To handle the buffer management correctly, you'd need to understand the pcap format to get lengths correct, etc.
You can stream it with popen, something like:
char* cmd = asprintf("/usr/bin/xz -d -c %s", filename);
FILE* fp = popen(cmd , "r");
free(cmd);
Then read from fp just as if it was uncompressed. You can also make a wrapper function for open returning a FILE* that works out whether to pipe it through a variety of decompressors by extension or just do a plain fopen.
In general I find regular pipes preferable to named pipes where possible as it saves (a) picking a unique name and (b) cleaning them up in all error cases
Or just parse the pcap by hand, the format is fairly trivial, IIRC it's just one header struct, then one per packet.

How to rewind a file descriptor using only system calls?

I have this sample code where I'm trying to implement for my operating systems assignment a program that copies the contents of an input file to an output file. I'm only allowed to use POSIX system calls, stdio is forbidden.
I've thought about storing the contents in a buffer but in my implementation I must know the file descriptor contents size. I googled a little and found about
off_t fsize;
fsize = lseek (input, 0, SEEK_END);
But in this case my file descriptor (input) gets messed up and I can't rewind it to the start. I played around with the parameters but I can't figure a way to rewind it back to the first character in the file after using lseek. That's the only thing I need, having that I can loop byte by byte and copy all the contents of input to output.
My code is here, it's very short in case any of you want have to take a look:
https://github.com/lucas-sartm/OSAssignments/blob/master/copymachine.c
I figured it out by trial and error. All that was needed was to read the documentation and take a look at read() return values... This loop solved the issue.
while (read (input, &content, sizeof(content)) > 0){ //this will write byte by byte until end of buffer!
write (output, &content, sizeof(content));
}

Reading from file in C using fread

I'm learning how to read content from a file in C. And I manage to scrape through the following code.
#include <stdio.h>
#include <stdlib.h>
void read_content(FILE *file) {
char *x = malloc(20);
// read first 20 char
int read = fread(x,sizeof(char),20,file);
if (read != 20) {
printf("Read could not happen\n");
}
else {
printf("the content read is %s",x);
}
free(x);
return;
}
int main(int argc,char *argv[]) {
FILE *fp;
fp = fopen("test.txt","w+");
read_content(fp);
fclose(fp);
return 0;
}
But for some reason (which I'm not able to understand) I see the read bytes count as 0.
The problem is that you open the file with the w+ mode. There are two possibilities:
if the file doesn't exist, it will be created empty. Reading from it immediately gives end of file resulting in fread() returning 0.
if the file does exist, it will be truncated i.e. changed into an empty file. Reading from it immediately gives end of file resulting in fread() returning 0.
If you just want to read from the file (as per your example), open it in mode r. If you want to read and write without destroying its existing content, use mode r+.
Whatever mode you choose, always check that fopen() returns non null and print the error if it returns null (this is not the cause of your problem but is best practice).
From Man Page w+ flag:
Open for reading and writing. The file is created if it does
not exist, otherwise it is truncated.
You are probably trying to open a file which doesn't exist at the path you provided, or is read-only as #WhozCraig suggested in comment. This means a new file is being created, an empty file! hence you are seeing 0 bytes read.
To sum up, The fopen is failing, in that case you need to check the return value if it is equal to -1.
To find what was the error, you can check the errno as it is set to
indicate the error.
If you are only intending to read, open the file with r flag instead of w+
The problem lies within this line of code:
fp = fopen("test.txt","w+")
the "w+" mode, clear the previous content of the file and the file will be empty when you just going to read the file without writing anything to it. Hence, it is printing "Read could not happen" because you are trying to read an empty file.
I would suggest you to use "r+" mode, if you are willing to read and then write into the file. Otherwise, r mode is good enough for simple reading of a file.

Errors when implementing a fwrite to get date from socket

I see a plenty of examples but none addresses what I want to accomplish. I need to read the bytes from a socket and write them in to a file. In this Code Project blog I see where in the client script a while loop iterates through a read call:
while((n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
So I modified the code do that fputs(recvBuff, f1) where f1 is a pointer to a pdf file. A pdf file is also a file I'm fetching from the server so I need to reassemble it, however the fputs operated with a string and corrupts the file, so I need a byte "writer" so fwrite would have been the choice but I can't get fwrite to work. I ended up modifying my code to resemble some of the examples to test it out but to no avail.
If in fwrite the first parameters is the 'data' how would I pass it? I've tried the read() call as in the while loop above but that seem to return an integer rather then a byte stream. Any ideas?
I'm new to programming but am new to C and would appreciate a little push in a right direction. Thanks.
You want something more like this. fwrite doesn't return a stream it returns the number of items (i.e. the 3rd parameter) successfully written. In this case the "item" is a single char and you are attempting to write "bytesRead" number of them. Good form dictates that you should check that the result fread returns is the same as you requested be written but this rarely fails on a disk file so many people skip it in non-critical situations. You may want to add that on yourself.
FILE *f1;
int sockfd;
char recvBuff[4096];
size_t bytesWritten;
ssize_t bytesRead;
while((bytesRead = read(sockfd, recvBuff, sizeof(recvBuff))) > 0)
bytesWritten = fwrite(recvBuff, 1, bytesRead, f1);

fread stalls on socket but fget doesnt?

I'm working on a proxy server in c. I've gotten rather far using a combination of fread and fgets in different places but would like to reconcile and understand the difference. In the following example, I'm trying to use fread in a place i previously used fget successfully. Instead my server now hangs at the fread line. What's the difference and why is my program hanging?
void HandleTCPClient(int clntSocket)
{
FILE *request = fdopen(clntSocket, "r");
char reader[2000];
size_t q; //typo before
while((q=fread(reader, 1, sizeof(reader), request))>0) { //hangs here!
printf("i read something!\n");
}
return;
}
thanks!!
EDIT: so if i make the line "while((q=fread(reader, 1, 1, request))>0) {"
i get "i read something" all over my screen...
not sure what this means. So is it correct that fread will literally do nothing if there isn't at least your buffer's size number of characters present in the stream?
fgets returns when a newline is read while fread will block until requested number of bytes are available in the stream or on EOF. In your case, the call blocks because you do not have 2000 bytes of data ready in the stream.
Using fread() instead of recv() to read on a TCP socket seems strange to me..?
Anyway, fread is blocking as long as there is nothing to read. You should always check that a socket is ready to perform reading or writing, using select() for example on linux.

Resources