File handle segfault - c

Implementing a data link protocol. I managed to send the whole file through the virtual serial port - which should be the hard part. The weird thing is I'm getting a segfault on fclose() when trying to save it. The file is being created, which means the open is successful, but nothing it being stored in it. Even changed the implementation to buffer all the file into memory before saving it.
int app_rx(const char* outputFile){
file_data_t fileData;
if(!receive_ctrl_pckt(&fileData)){
printf("Could not receive control packet\n");
return FAILURE;
}
printf("Receiving file [%s]\nFile size: %d\n", fileData.fileName, fileData.fileSize);
unsigned char fileBuffer[fileData.fileSize];
int fileIndex = 0;
int totalBytes = 0;
int stop = 0;
size_t sqNo = 0;
int bytes;
FILE* out = fopen(outputFile, "w");
do{
activeBuffer = (activeBuffer + 1) % 2;
printf("Receiving packet %lu\n", sqNo);
bytes = llread(BUFFERS[TMP_BUFFER]);
if(bytes == DUP_ERR){
printf("Duplicate data. Discarding packet\n");
}
else if (bytes == WH_ERR){
printf("Invalid header. Discarding packet\n");
}
else if (bytes == WD_ERR){
printf("Corrupted data. Awaiting retransmission\n");
}
else{
printf("Packet %lu successfully received\n", sqNo);
int retrieveRes = retrieve_payload(sqNo);
switch(retrieveRes){
case CTRL_END: {
stop = 1;
break;
}
case FAILURE: {
printf("Unknown error\nExiting...");
exit(1);
}
case SQ_ERR:{
printf("Unsynchronized packets\nExiting");
exit(1);
}
default:{
for(int i = 0; i < retrieveRes; i++){
fileBuffer[fileIndex] = BUFFERS[activeBuffer][i];
fileIndex++;
}
sqNo = (sqNo + 1) % 255;
totalBytes += bytes;
break;
}
}
}
}while(!stop);
printf("file index: %d\n", fileIndex);
fwrite(fileBuffer, sizeof(unsigned char), fileIndex, out);
printf("here\n");
fclose(out);
if(totalBytes == fileData.fileSize){
return SUCCESS;
}
else{
return FAILURE;
}
}
Stdout:
Packet 9 successfully received
Receiving packet 10
Asserting data integrity
Packet 10 successfully received
Receiving packet 11
Asserting data integrity
Packet 11 successfully received
file index: 10968
here
make: *** [Makefile:35: run_rx] Segmentation fault (core dumped)
Giant method, I know. Just trying to get it under before refactoring properly. Can't for the sake of nothing figure out what's going on. I know this works because I've copied the exact same file using this method with a simple copyfile.c test driver which mimics the cp command.
Any ideas? I find it particularly odd that it creates the output file, but doesn't write anything on it.
EDIT: managed to get it going by opening the file right before writting to it. Still don't quite understand what happened

There is a potential buffer overflow risk for array fileBuffer, except that retrieveRes is guaranteed smaller or equal than fileData.fileSize, if there is a buffer overflow, pointer out may be overwritten and caused a segment fault when call fclose. The buffer overflow can be verified by print the value of out before do/while loop and call to fclose.

Related

C: sockets: can't read the whole server response

I'm programming in C an IRC chat client. everything it's working well except I can't read the whole answer sent by the server. here's the code:
char buffer[2048];
write_on_screen(current_page(), "LOG COMMAND", command);
write(sockfd, command, strlen(command)); //write to socket
bzero(buffer, sizeof(buffer));
read(sockfd, buffer, sizeof(buffer));
write_on_screen(current_page(), "RESPONSE", buffer);
return buffer;
most of the time buffer will contain just a piece of the response (which is shorter than 2048 bytes) and other times it contains nothing. in both cases if I do another read() after the first one, it returns me the rest of the answer or another small piece (and then I've to do another read() again). if I put a sleep(1) between write() and read() I get the whole answer, but I'm sure this not a good pratice.
Is there some way I can avoid this?
thank you in advance
You're making the usual mistakes. It is impossible to write correct network code without storing the result of read() or recv() into a variable. You have to:
Check it for -1, and if so look at errno to see whether was fatal, which it almost always is except for EAGAIN/EWOULDBLOCK, and if fatal close the socket and abandon the process.
Check it for zero, which means the peer disconnected. Again you must close the socket and abandon the process.
Use it as the count of bytes actually received. These functions are not obliged nor guaranteed to fill the buffer. Their contract in blocking mode is that they block until an error, end of stream, or at least one byte is transferred. If you're expecting more than one byte, you normally have to loop until you get it.
According to RFC-1459, a single line of text in IRC can contain up to 512 characters and is terminated by a CRLF (\r\n) pair. However:
You're not guaranteed to receive exactly 512 bytes each time. For example, you might receive a comparatively short message from someone else one in the channel: Hi!
Related to the above: A group of 512 bytes might represent more than one message. For example, the buffer might contain a whole line, plus part of the next line: PRIVMSG <msgtarget> <message>\r\nPRIVMS
Given that you could have zero-or-more complete lines plus zero-or-one incomplete lines in your buffer[] at any time, you could try doing something along the lines of:
char buffer[2048];
while(keep_going)
{
char **lines;
int i, num_lines;
// Receive data from the internet.
receiveData(buffer);
// Create an array of all COMPLETE lines in the buffer (split on \r\n).
lines = getCompleteLines(buffer, &num_lines);
removeCompleteLinesFromBuffer(buffer);
// Handle each COMPLETE line in the array.
for (i = 0; i < num_lines; ++i) { handle_line(lines[i]); }
freeLines(lines);
}
This would allow you to handle zero or more complete lines in one go, with any incomplete line (i.e anything after the final \r\n pair) being kept around until the next call to receiveData().
You need to loop around read() until a CRLF had been detected.
A possible way to do this would be:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
ssize_t read_until_crlf(int sd, char * p, size_t s, int break_on_interupt)
{
ssize_t bytes_read = 0;
ssize_t result = 0;
int read_cr = 0;
int read_crlf = 0;
while (bytes_read < s)
{
result = read(sd, p + bytes_read, 1);
if (-1 == result)
{
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
{
continue;
}
else if (EINTR == errno)
{
if (break_on_interupt)
{
break;
}
continue;
}
else
{
perror("read() failed");
break;
}
}
else if (0 == result)
{
break; /* peer disconnected */
}
if ('\r' == p[bytes_read])
{
read_cr = 1;
}
else if (('\n' == p[bytes_read]) && read_cr)
{
read_crlf = 1;
break; /* CRLF detected */
}
else
{
read_cr = 0;
}
++bytes_read;
}
if (!read_crlf)
{
result = -1; /* Buffer full without having read a CRLF. */
errno = ENOSPC; /* ... or whatever might suite. */
}
return (0 >= result) ?result :bytes_read;
}
Call it like this:
#include <stdio.h>
ssize_t read_until_crlf(int sd, char * p, size_t s, int break_on_interupt);
int main(void)
{
int sd = -1;
/* init sd here */
{
char line[2048] = "";
ssize_t result = read_until_crlf(sd, line, sizeof line, 0);
if (-1 == result)
{
perror("read_until_newline() failed");
}
printf("read '%s'\n", line);
}
return 0;
}

Send/Read using a TCP socket, anomalies in the byte sizes

I'm trying to implement a working HTTP Client-Server application just to make practice with network programming.
The 2 programs have to follow this basic algorithm:
CLIENT - send a GET request
SERVER - send "+OK\r\n"
SERVER - send file size in bytes
SERVER - send file
CLIENT - send ACK
I'm having a lot of troubles in the reading part, probably because i perform some dirty read on the stream.
These are the 2 reading function that i'm using:
/* Reads a line from stream socket s to buffer ptr
The line is stored in ptr including the final '\n'
At most maxlen chasracters are read*/
int readline (SOCKET s, char *ptr, size_t maxlen)
{
size_t n;
ssize_t nread;
char c;
for (n=1; n<maxlen; n++)
{
nread=recv(s, &c, 1, 0);
if (nread == 1)
{
*ptr++ = c;
if (c == '\n')
break;
}
else if (nread == 0) /* connection closed by party */
{
*ptr = 0;
return (n-1);
}
else /* error */
return (-1);
}
*ptr = 0;
return (n);
}
and:
int readNumber(SOCKET s, long *num, int maxRead)
{
size_t n;
ssize_t nread;
int totRead;
long number=0;
for (n=1; n<maxRead+1; n++)
{
nread=recv(s, &number, sizeof(number), 0);
if (nread == sizeof(number))
{
totRead+=nread;
*num = number;
}
else if (nread == 0) /* connection closed by party */
{
*num = 0;
return (n-1);
}
else /* error */
{
printf("nread = %d\n", nread);
return (-1);
}
}
return (totRead);
}
this is the snippet of the main where i receive the +OK message and then the file size:
memset(rbuf,0,sizeof(rbuf)); //rbuf is the buffer where is store the read
printf("waiting for response...\n");
result = readline(s, rbuf, sizeof(rbuf)); //reading function is above
printf("Byte read(okMsg) = %d\n", result);
if (result <= 0)
//ERROR MANAGEMENT
{
printf("Read error/Connection closed\n");
closesocket(s);
SockCleanup();
exit(1);
}
else
{
long fileLength=0;
unsigned char *fBuf;
//RECEIVE OK
if(!strcmp(rbuf,"+OK\r\n"))
{
puts("+OK\n");
//RECEIVE FILE LEN
int nw = readNumber(s, &fileLength, 1); //reading function is above
printf("Byte read(fDim) = %d\n", nw);
printf("File is %ld bytes long\n", fileLength);
if(nw >0)
{
// RECEIVE FILE
}
}
}
When i send the "+OK\r\n" string the server tells me that it sends 8 bytes, but when i read i find the '\0' char only after 6 bytes.
By the way it reads correctly the message, but when i try to read the file size (that is a long) it gives me back a wrong number.
My opinion is that the stream buffer is dirty, and that i'm reading 2 bytes that are not part of the file size, but i'm not understanding why this happens.
Please ask me more info if i'm not clear enough.
SOLVED:
Thank you all for your answers!!!
You put me in the right mindset to understand what was wrong.
Look like the problem was this declaration in the server:
char *okMsg = "+OK\r\n";
instead of
char okMsg[] = "+OK\r\n";
that lead me to an undefined behavior.
long number=0;
for (n=1; n<maxRead+1; n++)
{
nread=recv(s, &number, sizeof(number), 0);
You forgot to design and implement a protocol to carry the data between your server and your client. Because TCP provides a stream of bytes, your protocol should be defined as a stream of bytes.
How many bytes convey this number? Is "however many bytes a 'long' happens to occupy on my platform" a good answer? What's the semantic meaning of the first byte? Is "whatever the first byte of a 'long' happens to mean on my platform" a good answer?
A good answer would be, "The size shall be conveyed as a 4-byte unsigned integer in little-endian byte order". Then make absolutely sure your code sends and receives in that format.

Writing send_all and recv_all functions for sockets in C

I am a new C programmer and so you will have to excuse my lack of knowledge. I am trying to use sockets in C on a windows machine to send data back and forth between a client and server. I am using the tools of cygwin with the codeblocks IDE. Simple send and receives were not working and so after some searching I was under the impression my problem was I needed a send_all and recv_all function. I have written the following two functions but receive seems to always get stuck in an infinite loop. I am not really sure why.
void send_all(int socket, void *buffer, int length) {
size_t i = 0;
for (i = 0; i < length; i += send(socket, buffer, length - i, 0)){
printf("Completed: %d bytes \r", i);
}
printf("Send Completed: %d bytes \n", length);
}
void recv_all(int sockfd, void *buffer, int length){
size_t i = 0;
for (i = 0; i < length; i+= recv(sockfd, buffer + i, length - i, 0)){
printf("Completed: %d bytes \r", i);
}
printf("Receive Completed: %d bytes \n", length);
}
I am wondering if it is because the receive doesn't know how many bytes the send is sending it. All advice is appreciated but please keep it constructive. Thanks.
recv() actually returns a signed value (int in Winsock, ssize_t in POSIX). Its return value can be a negative number if a read error occurred, OR if the socket is in non-blocking mode and no data is available. Its return value is zero if the socket was closed gracefully (this would cause an infinite loop in your code).
You will need to check the return value before you add it to your byte counter, to detect both of these conditions.
If your socket is in blocking mode (the default), your code will block indefinitely until the required amount of data has been received, or an error occurs (once you add code to check for that). Given the name of your function this seems to be the behavior you want. If so, your general approach is sound.
ssize_t bytesRead = 0;
while (bytesRead < length)
{
ssize_t rv = recv(/* ... */);
if (rv == 0)
{
printf("Socket closed gracefully before enough data received\n");
break;
}
else if (rv < 0)
{
// if your socket is non-blocking, check for EAGAIN which
// would mean no data is currently available; in this case you
// could do something like call select() on the socket to
// go to sleep until more data comes in
printf("Read error occurred before enough data received\n");
break;
}
bytesRead += rv;
}

Missing Bytes in Client Server application in C

I have created a Client/Server application in C by using the SSL library. the issue i am facing is each time i send a file there are some bytes missing in the start of file.
let suppose the text file which i am sending contains
123456789
and when the client receive the file it would contains
56789
Server-Code
void sendFile(SSL* ssl)
{
char response[2048] = {0};
int read = 0;
FILE* fd;
fd = fopen("snt.txt","rb");
if (fd == NULL)
{
printf("file loading failed\n");
return;
}
while ((read=fread(response,sizeof(char),1024,fd)) > 0)
{
SSL_write(ssl,response,read);
printf("read :%d\n",read);
//puts(response);
//printf("***Data Sent***\n");
memset(response,0,1024);
}
printf("***Data Sent***\n");
fclose(fd);
}
Client Code
FILE *ft;
char filebuf[2048];
int read = 0;
int error_check=0;
ft = fopen("rcv.txt","ab");
if (ft == NULL)
{
printf("Can not open file to write\n");
return -1;
}
memset(filebuf,0,2048);
int cnk=1;
while ((error_check=BIO_read(bio,&read,sizeof(int)))>0)
{
//printf("%d read\n",read);
if (error_check==0)
break;
if (read==0)
break;
BIO_read(bio,filebuf,read);
printf("%d Chunk Recieved\n",cnk++);
//puts(filebuf);
fwrite(filebuf,sizeof(char),strlen(filebuf),ft);
memset(filebuf,0,2048);
}
printf("***File Recieved***");
fclose(ft);
the other issue is client side is not terminated, control doesn't get away from the while-loop, kindly guide me how can i tackle these issues
Assuming size(int) is 4, I'd say the 1st 4 bytes are read by this line:
while ((error_check=BIO_read(bio,&read,sizeof(int)))>0)
That leaves the rest of the data sent to this line:
BIO_read(bio,filebuf,read);
The latter reads it into filebuf which then is written to the file rcv.txt.

socket connection getting closed abruptly with code 141

What im trying to do is connect to a remote server , read contents from a file on the local machine and send it over to the server. Then capture the server response and save it. I put the GET command in a text file and am trying get the results of the same. Here is some part of the code. Im doing this using sockets and C.
if ( inet_pton(AF_INET,ip, &(nc_args->destaddr.sin_addr.s_addr)) <= 0 )
printf("\n\t\t inet_pton error");
if (connect(sockfd, (struct sockaddr *) &nc_args->destaddr, sizeof(&nc_args->destaddr)) < 0)
{
printf("\n\t\t Connection error");
exit(1);
}
puts("\n\t\t Connection successful to ...");
// file parameter is taken from command line and passéd to this function
fp = fopen(file,"rb");
if ( fp == NULL)
{
printf("\n\t\t File not found");
exit(3);
}
else
{
printf("\n\t\t Found file %s\n", file);
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
rewind(fp);
//allocate memory to the buffer dynamically
buffer = (char*) malloc (sizeof(char)*file_size);
if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}
for (i=0 ; i<sizeof(buffer); i++)
{
printf("\n\t\t %s", buffer);
}
printf("\n\t\t File contains %ld bytes!\n", file_size);
printf("\n\t\t Sending the file now");
}
while (1)
{
bytes_read = fread(buffer,1, file_size, fp);
printf("\n\t\t The bytes read is %zd", bytes_read);
if (bytes_read == 0) // We're done reading from the file
{
printf("\n\t\t The bytes read is %zd", bytes_read);
break;
}
if (bytes_read < 0)
{
printf("\n\t\t ERROR reading from file");
}
void *p = buffer;
while (bytes_read > 0)
{
ssize_t bytes_written = send(sockfd, buffer, bytes_read,0);
if (bytes_written <= 0)
{
printf("\n\t\t ERROR writing to socket\n");
}
bytes_read -= bytes_written;
p += bytes_written;
printf("\n\t\t Bytes %zd written", bytes_written);
}
}
printf("\n\n\t\t Sending complete.");
What is happening here is that i get the message "connection successful", then it displays "sending the file now" and then the program quits unexpectedly. if i do echo $? i get 141 as the exit code. I am trying to connect from my server to a different server at work and get the results. These two can communicate correctly, and i can run the GET command from command line without issues. Its just not working from the code. Can someone let me know what the issue could be ?
On Linux, and probably other Unixes, the return code encodes a signal that the process received. Here it is 141 - 128 so 13 which corresponds to SIGPIPE.
If you don't want that signal to be raised because you capture the error return of send, anyhow, on Linux you can use MSG_NOSIGNAL in the flags argument to send to inhibit that signal. On other platforms you might have to program more complicated signal handlers to deal with that situation.
sizeof(&nc_args->destaddr) is the wrong thing to pass to connect. It wants the size of the address, not the size of a pointer to the address.
And this loop:
for (i=0 ; i<sizeof(buffer); i++)
{
printf("\n\t\t %s", buffer);
}
is baffling. buffer is a pointer, as we can see from when it was assigned a vlue returned by malloc. So its size is going to be 4 or 8 bytes on 32-bit and 64-bit architectures respectively; not related to the size of the malloc'ed object it points to. The loop runs 4 or 8 times, and prints... the same thing each time. Why?

Resources