In my code I am sending sending packets each with a 128 bytes from the text file and need to read in data from a text file (I can't just allocated a buffer and read all of it before sending because the file will be extremely large). For some reason I am getting an Abort 6 error even when I have allocated memory.
SendIndex starts as 0 and it aborts for the first send so that shouldn't be the problem.
The problem occurs during strcpy I just don't know why.
Really confused so I would really appreciate the help.
struct packet packingT;
packingT.header = mpHeaderT;
packingT.data = (char*) calloc(512,sizeof(char));
char* sendString = (char*)calloc(128,sizeof(char));
FILE *file = fopen(receivedStruct->fileTitle, "rb");
if(file == NULL) {
printf("Error - Can't Open File\n");
exit(0);
}
fseek(file, 128*sendIndex, SEEK_SET);
fread(sendString, 128, 1,file);
fclose(file);
// sendString[128] = '\0'; <--- Still don't know if this is needed
packingT.header->seq_num = receivedStruct->nextSeqNum;
strcpy(packingT.data, sendString);
I think all you need to do is replace the final strcpy with memcpy instead. That is, the last line should be memcpy(packingT.data, sendString, 128);
(Edit: The reason being that strcpy determines the length of the thing to be copied by scanning for a zero at the end. You're reading arbitrary data, which may have zeros in the middle, and may not always end in a zero)
(Edit2: please be aware that the content of packingT.data is not terminated, so you can't use string functions on it. Depending on what you're doing, you might need to add a terminator, or ensure one gets written to the file)
Related
I am trying to send a file and its name through a socket in C.
The relevant server code is:
char file[18];
memset(file, 0, 18);
file[17] = '\0';
int recvd = recv(newsock, file, 16, 0);
char local_file_path[200];
memset(local_file_path, 0, 200);
if(recvd == -1 || recv == 0) {
fprintf(stderr, "File name not received");
continue;
}
strcat(local_file_path, "/home/ubuntu/results/");
strcat(local_file_path, file);
FILE* fp = fopen(local_file_path, "wb");
char buffer[4096];
while(1)
{
recvd = recv(newsock, buffer, 4096, 0);
fwrite(buffer, sizeof(char), recvd, fp);
if(recvd == -1 || recvd == 0) {
fclose(fp);
break;
}
}
close(newsock);
}
close(servSock);
The relevant client code is:
char* my_16_long_fname = "filename1234.txt"
int ret = send(sock, my_16_long_file_fname, strlen(my_16_long_fname), 0)
This code, however, has been creating lots of undefined behaviour such as:
1.Receiving garbage filenames filled with garbage
2.Receiving empty files (so a name with nothing inside - could be some other bug but possibly due to this)
I have thought about a few solutions:
1.Diferentiate file types by signature/header and generate a file name on the server side. Besides this being a cheap solution which doesn't teach me how to actually solve the problem, it doesn't work with the logic i'm using, where sometimes I send error codes instead of file names after opening the socket.
2.Iterate over the recv'd buffer on the first call to recv until I encounter a '\0' character. Then write the remainder of the buffer as binary data and keep on receiving data as usual.
Is this the most efficient/simplest and solid solution to this issue, which will prevent any undefined behaviour?
There is no way your current code could possibly work. If the filename is always one character, your code can read too many characters. If your filename is always the same number of characters but more than one character, your code can read too few characters. If the filename is a variable number of characters, your code could read a smaller number than was sent.
So there is no sending protocol for which this could be valid receiving code.
Until you are an expert on writing networking code, always follow these two steps:
Document the protocol.
How many bytes does the filename occupy? Is it a fixed number or a variable number? Is it always followed by a zero byte?
Implement the protocol.
For example, your code reads up to 16 bytes for the filename. But it never checks if it received the whole file name. What if it only received a single byte?
I'm trying to transfer a file from server to client. I first send the name of the file I want to receive to the server, the server opens the file and writes its contents into a buffer and sends it back to the client. The client then copies the contents of that buffer into a newly created file to duplicate the contents of the server file.
When "Receive.txt" is created, only the FIRST word of the file I opened is copied into the file I created. Where am I going wrong?
server.c sending part:
if(checkCommand){
char *tmp = buf + 4;
char data[MAX_BLOCK_SIZE];
FILE *fp;
printf("File name: %s\n", tmp);
fp = fopen(tmp, "r");
if(fp == NULL){
printf("File not found\n");
exit(1);
}
do{
fscanf(fp, "%s", buf);
nw = write(sd, buf, MAX_BLOCK_SIZE);
} while(fscanf(fp, "%s", buf) != EOF);
}
client.c receiving part:
else if(getCommand){
FILE *fp;
write(sd, buf, MAX_BLOCK_SIZE);
read(sd, buf, MAX_BLOCK_SIZE);
fp = fopen("receive.txt", "w");
if(fp == NULL){
printf("File could not be opened.\n");
exit(1);
}
fprintf(fp, "%s", buf);
}
As correctly reported in comments section, the core of your issue consists in fscanf() being called both for reading data and for detecting EOF in order to quit the loop. But the latter actually consume data as well!
If I execute your program passing the following input file
Yesterday
All my troubles seemed so far away
Now it looks as though they're here to stay
and printing the output to stdout with printf("%s\n", buf); (instead of pushing data to a socket), that's what I get:
Yesterday
my
seemed
far
Now
looks
though
here
stay
So I get not only the first word, but one every two words.
Furthermore you write to the socket MAX_BLOCK_SIZE bytes whatever is the number of valid bytes you correctly read from file, so buf will contain MAX_BLOCK_SIZE - strlen(buf) bytes of garbage.
This sending loop will fix most of the issues mentioned above:
while(fscanf(fp, "%s", buf) != EOF)
{
write(sd, buf, strlen(buf));
}
Please note how you still would have something to care about:
are we sure that all words fit a MAX_BLOCK_SIZE big buffer? A word logger than the block will cause out of bound access (and undefined behavior), so a way to limit the number of acquired characters should be implemented
are we sure that all the data is sent in one shot? Probably yes, as the words are relatively short, but generally speaking the return value of the write() function should be checked, and if it is different from the amount of data to be sent the code should manage a way to send the remainder (or even exit the loop if the return value is negative!)
I'm not going to address these issues in this answer, but it was correct mentioning them. What I would like to emphatize, istead, is that sending data in this way will generate an output without whitespaces_. Something like:
YesterdayAllmytroublesseemedsofarawayNowitlooksasthoughthey'reheretostay
Even assuming that you need just a text file transfer, probably it is not what you want. For this reason I suggest implementing a binary trasfer using fread() in this way
#include<stdio.h>
#include <stdlib.h>
#define MAX_BLOCK_SIZE 1024
char buf[MAX_BLOCK_SIZE];
int main(void)
{
char tmp[] = "srcFile.txt";
FILE * fp;
int rd;
printf("File name: %s\n", tmp);
fp = fopen(tmp, "rb");
if(fp == NULL)
{
printf("File not found\n");
exit(1);
}
while(( rd = fread(buf, 1, MAX_BLOCK_SIZE, fp)) > 0)
{
write(sd, buf, rd);
//printf("%s\n", buf);
}
// You can call feof() or ferror() in order to discover if either EOF or an error occurred
return 0;
}
Uncommenting the printf what I get is exactly the input file. Please note how it would not necessary, on Linux environment, to select the binary mode with b, as
The mode string can also include the letter 'b' either as a last character or as a character between the characters in any of the two-character strings described above. This is strictly for compatibility with C89 and has no effect; the 'b' is ignored on all POSIX conforming systems, including Linux. (Other systems may treat text files and binary files differently, and adding the 'b' may be a good idea if you do I/O to a binary file and expect that your program may be ported to non-UNIX environments.)
(the emphasis is mine).
Just some notes about the receiver part:
I cannot comment the initial write(sd, buf, MAX_BLOCK_SIZE); because I'm not sure about the detais of your application, but it look strange. Make sure to send consistent data, in any case.
Always check the return values of read and write! Not only they can fail (and the error, that you can get querying errno, must be properly managed) but they can also read/write from/to socket less bytes than requested
In the general case of a binary file, writing data to the output file with fprintf(fp, "%s", buf); is not safe, as buf could contain bytes that are not printable or, even worse, it won't be NULL-terminated. Be aware that binary data could contain the '\0' character inside it, and that would result in an unexpected truncation. Use fwrite(), instead.
I am reading data from an input file and compressing it with bzip library function calls BZ2_bzCompress in C. I can compress the data successfully. But I cannot write all the compressed data to an output file. Only the first compressed line can be written. Am I missing something here.
int main()
{
bz_stream bz;
FILE* f_d;
FILE* f_s;
BZFILE* b;
int bzerror = -10;
unsigned int nbytes_in;
unsigned int nbytes_out;
char buf[3000] = {0};
int result = 0;
char buf_read[500];
char file_name[] = "/path/file_name";
long int save_pos;
f_d = fopen ( "myfile.bz2", "wb+" );
f_s = fopen(file_name, "r");
if ((!f_d) && (!f_s)) {
printf("Cannot open files");
return(-1);
}
bz.opaque = NULL;
bz.bzalloc = NULL;
bz.bzfree = NULL;
result = BZ2_bzCompressInit(&bz, 1, 2, 30);
while (fgets(buf_read, sizeof(buf_read), f_s) != NULL)
{
bz.next_in = buf_read;
bz.avail_in = sizeof(buf_read);
bz.next_out = buf;
bz.avail_out = sizeof(buf);
printf("%s\n", buf_read);
save_pos = ftell(f_d);
fseek(f_d, save_pos, SEEK_SET);
while ((result == BZ_RUN_OK) || (result == 0) || (result == BZ_FINISH_OK))
{
result = BZ2_bzCompress(&bz, (bz.avail_in) ? BZ_RUN : BZ_FINISH);
printf("2 result:%d,in:%d,outhi:%d, outlo:%d \n",result, bz.total_in_lo32, bz.total_out_hi32, bz.total_out_lo32);
fwrite(buf, 1, bz.total_out_lo32, f_d);
}
if (result == BZ_STREAM_END)
{
result = BZ2_bzCompressEnd(&bz);
}
printf("3 result:%d, out:%d\n", result, bz.total_out_lo32);
result = BZ2_bzCompressInit(&bz, 1, 2, 30);
memset(buf, 0, sizeof(buf));
}
fclose(f_d);
fclose(f_s);
return(0);
}
TL;DR: there are multiple problems, but the main one that explains the problem you asked about is likely that you compress each line of the file independently, instead of the whole file as a unit.
According to the docs of BZ2_bzCompressInit, the bz_stream argument should be allocated and initialized before the call. Yours is (automatically) allocated, but not (fully) initialized. It would be clearer and easier to change to
bz_stream bz = { 0 };
and then skip the assignments to bz.opaque, bz.alloc, and bz.free.
You store but do not really check the return value of your BZ2_bzCompressInit call. It does eventually get tested in the condition of the inner while loop, but you do not detect error conditions there, but instead just success and normal completion conditions.
Your handling of the input buffer is significantly flawed.
In the first place, you set the number of available input bytes incorrectly:
bz.avail_in = sizeof(buf_read);
Since you're using fgets() to read data into the buffer, under no circumstances is the full size of the buffer occupied by input data, because fgets() ensures that a string terminator is written into the array. In fact, it could be worse because fgets() will stop at after newlines, so it may provide as few as just one input byte on a successful read.
If you want to stick with fgets() then you need to use strlen() to determine the number of bytes available from each read, but I would suggest that you instead switch to fread(), which will more reliably fill the buffer, indicate with its return value how many bytes were read, and correctly handle inputs containing null bytes.
In the second place, you use BZ2_bzCompress() to compress each buffer of input as if it were a complete file. When you come to the end of the buffer, you finish a compression run and reinitialize the bz_stream. This will definitely interfere with decompressing, and it may explain why your program (seems to) compress only the first line of its input. You should be reading the whole content of the file (in suitably-sized chunks) and feeding all of it to BZ2_bzCompress(... BZ_RUN) before you finish up. There should be one sequence of calls to BZ2_bzCompress(... BZ_FINISH) and finally one call to BZ2_bzCompressEnd() for the whole file, not per line.
You do not perform error detection or handling for any of your calls to standard library or bzip functions. You do handle the expected success-case return values for some of these, but you need to be rpepared for errors, too.
There are some additional oddities
you have unused variables nbytes_in, nbytes_out, bzerror, and b.
you open the input file as a text file, though whether that makes any difference is platform-dependent.
the ftell() / fseek() pair has no overall effect other than setting save_pos, which is not otherwise used.
although it is not harmful, it also is not useful to memset() the output buffer to all-zeroes at the end of each line (or initially).
Given that you're compressing the input, it's odd (but again not harmful) that you provide six times as much output buffer as you do input buffer.
All,
I'm using MapViewOfFile to hold part of a file in memory. There is a stream that points to this file and writes to it, and then is rewound. I use the pointer to the beginning of the mapped file, and read until I get to the null char I write as the final character.
int fd;
yyout = tmpfile();
fd = fileno(yyout);
#ifdef WIN32
HANDLE fm;
HANDLE h = (HANDLE) _get_osfhandle (fd);
fm = CreateFileMapping(
h,
NULL,
PAGE_READWRITE|SEC_RESERVE,
0,
4096,
NULL);
if (fm == NULL) {
fprintf (stderr, "%s: Couldn't access memory space! %s\n", argv[0], strerror (GetLastError()));
exit(GetLastError());
}
bp = (char*)MapViewOfFile(
fm,
FILE_MAP_ALL_ACCESS,
0,
0,
0);
if (bp == NULL) {
fprintf (stderr, "%s: Couldn't fill memory space! %s\n", argv[0], strerror (GetLastError()));
exit(GetLastError());
}
Data is sent to the yyout stream, until flushData() is called. This writes a null to the stream, flushes, and then rewinds the stream. Then I start from the beginning of the mapped memory, and read chars until I get to the null.
void flushData(void) {
/* write out data in the stream and reset */
fprintf(yyout, "%c%c%c", 13, 10, '\0');
fflush(yyout);
rewind(yyout);
if (faqLine == 1) {
faqLine = 0; /* don't print faq's to the data file */
}
else {
char * ps = bp;
while (*ps != '\0') {
fprintf(outstream, "%c%c", *ps, blank);
ps++;
}
fflush(outfile);
}
fflush(yyout);
rewind(yyout);
}
After flushing, more data is written to the stream, which should be set to the start of the memory area. As near as I can determine with gdb, the stream is not getting rewound, and eventually fills up the allocated space.
Since the stream points to the underlying file, this does not cause a problem initially. But, when I attempt to walk the memory, I never find the null. This leads to a SIGSEV. If you want more details of why I need this, see here.
Why am I not reusing the memory space as expected?
I think this line from the MSDN documentation for CreateFileMapping might be the clue.
A mapped file and a file that is accessed by using the input and output (I/O) functions (ReadFile and WriteFile) are not necessarily coherent.
You're not apparently using Read/WriteFile, but the documentation should be understood in terms of mapped views versus explicit I/O calls. In any case, the C RTL is surely implemented using the Win32 API.
In short, this approach is problematic.
I don't know why changing the view/file size helps; perhaps it just shifts the undefined behaviour in a direction that happens to be beneficial.
Well, after working on this for a while, I have a working solution. I don't know why this succeeds, so if someone comes up with something better, I'll be happy to accept their answer instead.
fm = CreateFileMapping(
h,
NULL,
PAGE_READWRITE|SEC_RESERVE,
0,
16384,
NULL);
As you can see, the only change is to the size declared from 4096 to 16384. Why this works when the total chars input at a time is no more than 1200, I don't know. If someone could provide details on this, I would appreciate it.
When you're done with the map, simply un-map it.
UnmapViewOfFile(bp);
I am read from a file like this:
#include <stdio.h>
int main() {
FILE *fp = fopen("sorted_hits", "r+");
while(!feof(fp)) {
int item_read;
int *buffer = (int *)malloc(sizeof(int));
item_read = fread(buffer, sizeof(int), 1, fp);
if(item_read == 0) {
printf("at file %ld\n", ftell(fp));
perror("read error:");
}
}
}
This file is big and I got the "Bad file descriptor" error sometimes. "ftell" indicates that the file position stopped when error occurred.
I don't know why it is "sometimes", is that normal? does the problem lie in my code or in my hard disk? How to handle this?
perror prints whatever is in errno as a descriptive string. errno gets set to an error code whenever a system call has an error return. But, if a system call DOESN'T fail, errno doesn't get modified and will continue to contain whatever it contained before. Now if fread returns 0, that means that either there was an error OR you reached the end of the file. In the latter case, errno is not set and might contain any random garbage from before.
So in this case, the "Bad file descriptor" message you're getting probably just means there hasn't been an error at all. You should be checking ferror(fp) to see if an error has occurred.
You seem to be mixing text and binary modes when reading the file.
Normally when you use fread you read from a binary file i.e. fread reads a number of bytes matching the buffer size but you seem to be opening the file in text mode (r+). ftell doesn't work reliably on files opened in text mode because newlines are treated differently than other characters.
Open the file in binary mode (untranslated) instead:
FILE *fp = fopen("sorted_hits", "rb+");
If that's really what your loop looks like, my guess would be that you're probably getting a more or less spurious error because your process is just running out of memory because your loop is leaking it so badly (calling malloc every iteration of your loop, but no matching call to free anywhere).
It's also possible (but a lot less likely) that you're running into a little problem from your (common but nearly always incorrect) use of while (!feof(fp)).
Your all to printf also gives undefined behavior because you've mismatched the conversion and the type (though on many current systems it's irrelevant because long and int are the same size).
Fixing those may or may not remove the problem you've observed, but at least if you still see it, you'll have narrowed down the possibilities of what may be causing the problem.
int main() {
FILE *fp = fopen("sorted_hits", "r+");
int buffer;
while(0 != fread(&buffer, sizeof(int), 1, fp))
; // read file but ignore contents.
if (ferror(fp)) {
printf("At file: %ld\n", ftell(fp));
perror("read error: ");
}
}