I am having some trouble understanding why I am getting a segmentation fault in my homemade web server. I am trying to correctly label the content type for .html and .txt documents. I can open an .html file in my web browser just fine when my server is running. However, my server is closing on a segmentation fault when I try to open a .txt document. The code below is where I am getting the issue.
void* thread_runner(void* sockfd)
{
char buffer[256];
int n;
int sock = *(int*)sockfd;
bzero(buffer,256);
char filename[256];
bzero(filename,256);
n = read(sock,filename,255);
if (n < 0) error("ERROR reading from socket");
FILE *fp;
char file[4096];
char* word = strtok(filename, " ");
word = strtok(NULL, " ");
word++;
printf("filename = \"%s\"\n", word);
fp = fopen(word, "r");
if (fp == NULL) {
printf("file pointer is NULL\n");
return 0;
}
char string[4096];
char* extension;
bzero(string, 4096);
bzero(file, 4096);
char* word2;
word2 = strtok(word, ".");
while ((word2 = strtok(NULL, ".")) != NULL)
{
extension = word2;
}
printf("File Extension: %s\n", extension);
if (strncmp(extension, "html", 4096) == 0) {
printf("HTML FILE FOUND\n");
strcat(string, "HTTP/1.1 200 OK\nContent-Type: text/html\nContent-Length: 4096 \nConnection: keep-alive\n\n");
}
else if (strncmp(extension, "txt", 4096) == 0) {
printf("TXT FILE FOUND\n");
strcat(string, "HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: 4096\nConnection: keep-alive\n\n");
}
the error occurs in this loop.
I have used bzero on 'string'.
while (fgets(file, 4096, fp))
{
strcat(string, file);
}
//printf("Sending text:%s", string);
printf("The requested file was: %s.%s\n",word,extension);
n = write(sock,string,4096);
printf("file contents are %s\n", string);
fclose(fp);
if (n < 0) error("ERROR writing to socket");
if (n == 0)
{
close(sock);
}
You're writing past the end of string. string only has 4096 characters in it, but your loop tries to read the entire file into it when it keeps calling strcat() in a loop.
Instead of concatenating the entire file into a variable and then writing it all, use fread() to read the file in chunks and immediately write them to the socket. There's no need to read line by line.
size_t in;
while ((in = fread(file, 1, sizeof file, fp) > 0) {
int n = write(sock, file, in);
if (n < in) {
error("ERROR writing to socket");
}
}
close(sock);
fclose(fp);
Related
In here I am sending file name first then sending the file in chunks, then trying to read the received message but it is just freezing. No respond. But after loop if I shutdown the WR shutdown(connfd,SHUT_WR); It is working fine. Though I should be able to send message again, if I do this I can not do that.
CLIENT.C
write(sockfd, fname,100);
FILE *fp = fopen(fname,"rb");
if(fp==NULL)
{
printf("File opern error");
exit(1);
}
int hi = 0;
while(1)
{
/* First read file in chunks of 256 bytes */
unsigned char buff[1024]={0};
int nread = fread(buff,1,1024,fp);
/* If read was success, send data. */
if(nread > 0)
{
hi++;
//printf("Sending \n");
write(sockfd, buff, nread);
}
if (nread < 1024)
{
if (feof(fp))
{
printf("File transfer completed!\n");
}
if (ferror(fp))
printf("Error reading\n");
break;
}
}
char fname2[100];
// cant read
read(sockfd, fname2, 100);
printf("File Name: %s\n",fname2);
SERVER.C
FILE *fp;
int bytesReceived = 0;
char recvBuff[1024];
char fname[100];
char fname2[100];
read(newsockfd, fname, 100);
//strcat(fname,"AK");
printf("File Name: %s\n",fname);
printf("Receiving file...");
fp = fopen(fname, "ab");
if(NULL == fp)
{
printf("Error opening file");
}
long double sz=1;
/* Receive data in chunks of 256 bytes */
printf("\nCompleted.\n");
int hi = 0;
while((bytesReceived = read(newsockfd, recvBuff, 1024)) > 0)
{
hi++;
sz++;
fwrite(recvBuff, 1,bytesReceived,fp);
}
printf("Not pring this this!");
if(bytesReceived < 0)
{
printf("\n Read Error \n");
}
write(newsockfd, "SayGee",100);
I had to send the size of the file, then check from the other side inside loop. It was in deadlock.I found the solution. So thanks anyway!
I'm sending a file from the client to the server.
Client sends filename
Server receives filename
Client sends file size
Server receives file size
Client sends file contents
Server receives file contents
When I print out the file size that I sent, it is the exact number of bytes as the file I wish to send so that's fine. The issue is that the server (receives) doesn't seem to exit the while loop when writing to the new file. I know this because the final print statement printf("The server has received the requested document\n"); is never reached and it just hangs. What could be causing this?
Client snippet (sends):
else if(strcmp(shortCommand, "put") == 0){
char *tmp = buf + 4;
char filename[MAX_BLOCK_SIZE];
size_t size, bytes_read, bytes_written;
int x;
strcpy(filename, "filename ");
strcat(filename, tmp);
FILE *fp;
printf("File name: %s\n", tmp);
fp = fopen(tmp, "rb");
if(fp == NULL){
printf("ERROR: Requested file does not exist.\n");
}
else{
printf("Client sending filename...\n");
if ((x = write(sd, buf, sizeof(buf))) < 0){ //sending the file name to the client first
printf("Error sending client's filename.\n");
}
printf("Client sending file...\n");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("Sending file size\n");
if((write(sd, &size, sizeof(size))) < 0){ //sending filesize
printf("error sending file size\n");
}
printf("Sending file\n");
while((bytes_read = fread(buf, 1, sizeof(buf), fp)) > 0){ //sending file contents
if ((bytes_written = write(sd, buf, bytes_read)) < 0){
printf("Error sending client file.\n");
}
}
printf("bytes written: %ld\n", bytes_written);
fclose(fp);
}
}
Server snippet (receives):
if(strcmp(shortCommand, "put") == 0){
char *tmp = buf + 4;
char filename2[MAX_BLOCK_SIZE];
size_t filesize;
size_t total_bytes_read = 0;
ssize_t bytes_read = 0;
size_t error;
FILE *fp;
strcpy(filename2, tmp);
printf("Server receiving file name...\n"); //filename is received on the first read before this IF
fp = fopen(filename2, "wb");
if(fp == NULL){
printf("File could not be opened.\n");
exit(1);
}
printf("Server receiving file size...\n");
if((error = read(sd, &filesize, sizeof(filesize))) < 0){ //receiving file size
perror("Error reading filesize\n");
exit(1);
}
printf("Filesize is: %ld \n", filesize);
while(total_bytes_read < filesize){
while((bytes_read = read(sd, buf, sizeof(buf))) > 0){ //receving file contents and writing to file
fwrite(buf, 1, bytes_read, fp);
total_bytes_read += bytes_read;
if(ferror(fp)){
perror("error");
fclose(fp);
}
}
}
printf("The server has received the requested document.\n");
fflush(stdout);
fclose(fp);
}
After I exit the program by force, I can actually see that the file has been copied. Just doesn't exit that while loop to let me go back to the client.
Time for some basic debugging. I'd suggest changing your read loop to something like this:
while (total_bytes_read < filesize) {
printf("DEBUG A: total=%zu, size=%zu\n", total_bytes_read, filesize);
while ((bytes_read = read(sd, buf, sizeof(buf))) > 0) {
printf("DEBUG B: read=%zd\n", bytes_read);
fwrite(buf, 1, bytes_read, fp);
total_bytes_read += bytes_read;
printf("DEBUG C: total=%zu\n", total_bytes_read);
if (ferror(fp))
printf("DEBUG D\n");
perror("error");
fclose(fp);
}
printf("DEBUG E\n");
}
printf("DEBUG F\n");
}
printf("DEBUG G\n");
Then run it, piping the output through less or some other pager, it should then hopefully become clearer what's actually happening.
Feel free to post the output of this modified code (in a comment, or in the actual question), we'll no doubt be able to help with the analysis.
I am doing a class project right now and it requires me to send data and image using socket. So far I have finished most of it. Data gets sent correctly, small images get sent correctly, but when it comes to large images, only half of it is shown. I checked the characters sent and all of them got sent. So I am not sure where I got wrong. This my function to handle get request. I have tested sending data and it worked, so I think most of this function works but probably just some small details I missed. Please help...thanks!
void handle_get(int sock, const char* url) {
FILE* pFILE;
int file, i;
//file = open(url, O_RDONLY);
pFILE = fopen(++url, "r");
char response_message[1024];
char buffer[1024];
char c;
char *header_type, *file_type;
long file_size;
//char *buffer;
if (pFILE == NULL){
snprintf (response_message, sizeof (response_message), not_found_response_template, url);
write (sock, response_message, strlen (response_message));
error("ERROR opening requested file");
}
file_type = strrchr (url, '.');
//return pointer to the last occurrance of '.'
if (!file_type)
file_type = "html";
else
file_type++;
if (strcasecmp (file_type, "jpg") == 0 || strcasecmp (file_type, "jpeg") == 0)
header_type = "image/jpeg";
else if (strcasecmp (file_type, "gif") == 0)
header_type = "image/gif";
else if (strcasecmp (file_type, "png") == 0)
header_type = "image/png";
else
header_type = "text/html";
snprintf (response_message, sizeof (response_message), ok_response, header_type);
write (sock, response_message, strlen (response_message));
puts(response_message);
int n = 0;
bzero(buffer, 1024);
while (n=fread(buffer, sizeof(char), 1024, pFILE)){
printf("n is %d\n", n);
send (sock, buffer, n, 0);
//write(sock, buffer, n);
bzero(buffer, 1024);
}
fclose (pFILE);
}
I was trying to implement FTP Server as a part of an assignment and I wrote the following code to implement GET Command, which essentially reads file1 from server and stores it in file2.
int getCommandImpl(int clientSocket, char *file1, char *file2){
char *messageContent;
char buffer[256], userCommand[256], *tempString ;
int messageHead, endOfTransfer =0;
int messageLength;
sprintf(userCommand, "GET %s", file1);
messageLength = write(clientSocket,userCommand,strlen(userCommand));
if(messageLength <0){
perror("Error sending data to server in RETR");
return 0;
}
FILE *fp;
fp = fopen(file2, "w");
if(fp==NULL){
printf("%s Can not be created\n", file2);
return 0;
}
printf("Writing to file %s\n", file2);
while(!endOfTransfer){
messageLength = read(clientSocket, buffer, strlen(buffer)-1);
if(messageLength == -1){
perror("GET: Error in read() ");
break;
}
//puts(buffer);
printf("Buffer is %s with len %d\n", buffer, strlen(buffer));
tempString = strdup(buffer);
messageHead = atoi(strtok(tempString, " "));
messageContent = strtok(NULL, " ");
if(messageHead == 0 && strlen(messageContent)==0){ //End of file transfer
endOfTransfer = 1;
break;
}
fwrite(messageContent, sizeof(char), sizeof(messageContent), fp);
memset(buffer,0,sizeof(buffer));
printf("Buffer is %s with len %d\n", buffer, strlen(buffer));
}
fclose(fp);
return 1;
}
While running it, I am always getting the error "GET: Error in read() : Bad address". If I remove the statement
memset(buffer,0,sizeof(buffer));
I am getting a segmentation fault. I am assuming that the error has something to do with the string buffer being empty from the second iteration.
Any help to solve this will be highly appreciated.
I'm trying to send files using TCP from a windows client to a Linux server in C.
The size of the buffer I use to send the data is 65535. When the size of the file exceeds this value, I get an error saying 'connection reset by peer' or the error code 10054. When the size of the file is less than 65535 bytes, the server receives only a part of it (usually 2760 bytes).
I just want to send files with a maximum size of 50 MB.
This is the part of the windows client that I use to send data:
char *fileName; // pointer to filename
char buf[65535]; // buffer
int fileSize; // # bytes to send
for(i = 0; i < ARRAYSIZE; i++) {
if(selectList[i] != NULL) {
// select file
fileName= selectList[i]; // get path and filename from selectList
printf("=============================================\nSending: %s\n", fileName);
filefd = fopen(fileName, "rb"); // open file
if(filefd == NULL) {
printf("File %s not found\n", fileName);
exit(1);
}
// read and send file
memset(buf, '\0', 65535);
while((fileSize= fread(buf, sizeof(char), 65535, filefd)) > 0) { // read file
if((numberOfBytes = send(sockfd, buf, fileSize, 0)) < 0) { // send buffer
printf("send: %s (Error: %d)\n", filename, WSAGetLastError());
break;
}
printf("#bytes = %i \n", numberOfBytes);
memset(buf, '\0', 65535);
}
printf("File %s send!\n", filename);
// close file after sending it
if(fclose(filefd) < 0) {
printf("fclose: %i", WSAGetLastError());
}
} else if(selectList[0] == NULL) {
printf("no files selected");
}
}
The selectList contains multiple strings such as: C:\Windows\test.txt
The recieve part of the Linux server:
char* fr_name = "/home/MtFS/UploadedFiles/public/testFile.gif";
FILE *fr = fopen(fr_name, "wb");
if(fr == NULL)
printf("[Open_File]file %s cannot be created\n", fr_name);
else {
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
while((fr_block_sz = recv(nsockfd, revbuf, LENGTH, 0)) > 0) {
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if(write_sz < fr_block_sz) {
error("[Write] error\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
}
if(fr_block_sz < 0) {
if (errno == EAGAIN) {
printf("[Receive] time out\n");
}
else {
printf("[Receive] error\n");
exit(1);
}
}
printf("[Receive] succesfull\n");
fclose(fr);
}
What am I doing wrong?
Your problem are those 3 lines of code. That's not the correct way to know that you're done:
if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
Also you check against 512 instead of LENGTH. But only 0 means that you're done (assuming your connection is not NONBLOCKED.)
As a side note: you do not have to clear your buffers (bzero, memset) before using them with a read since the read/recv will overwrite the content of the buffers anyway.
I think the culprit is this line in your server
if (fr_block_sz == 0 || fr_block_sz != 512) {
fr_block_sz cab be anything between 1 to 65535 - the size block that you sent.
In your code, when its not 512 so your server is terminating the connection.