Issue with program involving sockets and client-server communication in C - c

I am working on a program in C that involves client-server connections and communication between the two parties.
The program involves the client sending a letter to the server and the server getting the letter. The server then searches through the current file directory (in linux) for a file beginning with that letter and sends the client the number of bytes of the file and the text of the file.
The overall program is very long and for the assignment the instructor already did much of the code such as setting up the sockets and creating the entire program for the client side of operations.
For the server side I had to write code for:
getting the file descriptor from the passed memory and casting it
-getting the letter from the client
-Attempting to open the current directory
-Iterating through the directory looking for a file that starts with the letter
-Attempting to open the file and sending the size of the file and number of bytes of file to the client in network endian
-Closing the file and directory after finishing
-Error checking: there are error checking statements if the directory cannot be opened, the file cannot be opened, or no matching file is found
The following is my code with comments
void* handleClient (void* vPtr
)
{
// I. Application validity check:
int fd = *((int *) vPtr);
//casting vPtr to an int//
free(vPtr);
// II. Handle the client:
char buffer[BUFFER_LEN+1];
read(fd, buffer, BUFFER_LEN+1);
//read the letter into a buffer//
const char* dirNamePtr = ".";
DIR* dirPtr = opendir(dirNamePtr);
// Open the current directory
if (dirPtr == NULL)
{
int toSend = htonl(CANT_READ_DIR_CODE);
write(fd,&toSend,sizeof(toSend));
printf("Cannot read directory\n");
return(NULL);
}
// If current directory cannot be opened, it sends a error message in network // endian to the client
struct dirent* entryPtr;
char path[BUFFER_LEN];
struct stat statBuffer;
//implements struct dirent to get info on the directory
//iterates through the directory
while ((entryPtr=readdir(dirPtr)) != NULL)
{
stat(entryPtr->d_name, &statBuffer);
//puts in metaddata of the current directory into statbuffer
if (!S_ISREG(statBuffer.st_mode))
continue;
//if the entry is not a file, continue
// if the first letter of the file is not the character received from the //client, send an error mesage
if(entryPtr->d_name[0]!=buffer[0]) {
int toSend2 = htonl(NO_MATCH_CODE);
write(fd,&toSend2,sizeof(toSend2));
printf("No matching file\n");
return(NULL);
}
int ab;
int numRead;
int numBytes;
char buffer[BUFFER_LEN];
//open the file and send bytes of file and file size to client
if (entryPtr->d_name[0]==buffer[0] &(S_ISREG(statBuffer.st_mode)))
{
ab=open(entryPtr->d_name,O_RDONLY,0660);
if(ab<0) {
int toSend3 = htonl(CANT_READ_FILE_CODE);
write(fd,&toSend3, sizeof(toSend3));
printf("Cannot read <filename>\n");
return(NULL);
}
numBytes=htonl(statBuffer.st_size);
write(fd, &numBytes, sizeof(numBytes));
printf("Sending %s, %d bytes\n",entryPtr >d_name,statBuffer.st_size);
while((numBytes=read(ab,buffer,BUFFER_LEN))>0)
{
printf("We read %d bytes\n", numBytes);
write(fd, buffer, numBytes);
}
//close the fiel
close(ab);
}
break;
//leave the loop
}
// III. Finished:
//
closedir(dirPtr);
return(NULL);
}
My code compiles but does not send the file to the client when I try running it. I have tried several different letters and it has not worked for any of them. I do not quite know what the issue is which makes it difficult to fix my mistakes.
I am not asking for the answer or anything, just help in seeing where I am wrong. I appreciate any help.

Your logic for when to send vs. when to send no-file status seems wrong. I think it should be like this (fair warning, I didn't test this, or even compile it beyond basic syntax checking, but you should get the idea):
void* handleClient(void* vPtr)
{
// I. Application validity check:
int fd = *((int *) vPtr);
free(vPtr);
// II. Handle the client:
char buffer[BUFFER_LEN+1];
read(fd, buffer, BUFFER_LEN+1);
//read the letter into a buffer//
const char* dirNamePtr = ".";
DIR* dirPtr = opendir(dirNamePtr);
// Open the current directory
if (dirPtr == NULL)
{
int toSend = htonl(CANT_READ_DIR_CODE);
write(fd,&toSend,sizeof(toSend));
printf("Cannot read directory\n");
return(NULL);
}
struct dirent* entryPtr;
char path[BUFFER_LEN];
struct stat statBuffer;
//implements struct dirent to get info on the directory
//iterates through the directory
while ((entryPtr=readdir(dirPtr)) != NULL)
{
stat(entryPtr->d_name, &statBuffer);
//puts in metaddata of the current directory into statbuffer
// if this isn't a regular file OR the first char doesn't match...
if (!S_ISREG(statBuffer.st_mode) || entryPtr->d_name[0]!=buffer[0])
continue;
int ab;
int numRead;
int numBytes;
char buffer[BUFFER_LEN];
//open the file and send bytes of file and file size to client
ab = open(entryPtr->d_name,O_RDONLY,0660);
if(ab<0) {
int toSend3 = htonl(CANT_READ_FILE_CODE);
write(fd,&toSend3, sizeof(toSend3));
printf("Cannot read <filename>\n");
closedir(dirPtr);
return(NULL);
}
numBytes=htonl(statBuffer.st_size);
write(fd, &numBytes, sizeof(numBytes));
printf("Sending %s, %d bytes\n",entryPtr >d_name,statBuffer.st_size);
while((numBytes=read(ab,buffer,BUFFER_LEN))>0)
{
printf("We read %d bytes\n", numBytes);
write(fd, buffer, numBytes);
}
//close the file and leave
close(ab);
break;
}
// if this is NULL it means we dind't send anything. we break the loop
// when a file to send it discovered.
if (entryPtr == NULL)
{
printf("No matching file\n");
int toSend2 = htonl(NO_MATCH_CODE);
write(fd, &toSend2, sizeof(toSend2));
}
// III. Finished:
closedir(dirPtr);
return(NULL);
}

Related

Fail to read/write struct to fifo recursively in C

In an exercise problem, I am required to build a client program (write first) that opens a .txt file, put each line and the total bytes of each line into a struct variable and then send it out to the server program (read first). Right after this is done, the client program will also receive a struct file (similarly only has char * and int attributes) from the server program.
// Below are global variables in both programs
#define BUFSIZE 1024
struct info_pack
{
char line[BUFSIZE]; // the line to receive messages
int bytes; // the bytes of data transferred
};
char fifo_path[] = "./my_fifo";
struct info_pack info_w; // the info_pack for writing each line in text.txt
struct info_pack info_r; // the info_pack for reading feedback info_pack sent from the server program
First is the client program:
// the main() in the client program
int main()
{
int fd;
int i = 0, index = 1, bytes = 0, line_length, fifo_read;
char *file_path = "/home/text.txt";
FILE *fd2;
mkfifo(fifo_path, 0666);
if ((fd2 = fopen(file_path, "r")) < 0)
{
perror("Opening file");
return -1;
}
else
{
printf("Successfully open the target file\n");
while (fgets(info.line, BUFSIZE, fd2) != NULL)
// the "segmentation fault" error appears right after this line
{
info_w.bytes = strlen(line);
fd = open(fifo_path, O_WRONLY);
printf("The %d th line sent out is: %s\n%d bytes are sent\n\n",
index, info_w.line, info_w.bytes);
write(fd, &info_w, sizeof(info_w) + 1);
close(fd);
fd = open(fifo_path, O_RDONLY);
fifo_read = read(fd, &info_r, sizeof(info_r));
close(fd);
if (fifo_read > 0)
{
printf("Feedback: %s\nand %d bytes are returned\n", info_r.line, info_r.bytes);
}
}
printf("All data is successfully transfered\n");
}
return 0;
}
Then is the server program
// the main() in the server program
int main()
{
int fd, fifo_read;
int line_length;
char *feedback = "SUCCESS";
strcpy(info_w.line, feedback);
info_w.bytes = strlen(feedback);
// define a constant info_pack variable to send to the client program
if (mkfifo(fifo_path, 0666) < 0)
{
perror("client end: ");
exit(-1);
}
while (1)
// This server program will wait for any one single client's message
// This server program can only be terminated by manually input signals (like ^\)
{
fd = open(fifo_path, O_RDONLY);
printf("waiting for client's message\n");
fifo_read = read(fd, &info_r, sizeof(info_r));
close(fd);
if (fifo_read > 0)
// if receive the struct variable, print all of its attributes
{
if (info_r == NULL)
printf("Found no lines sent from the client\n");
else
printf("Read from fifo:\n %s\n(in info)%d bytes read (actually)%d bytes read\n", info_r.line, info_r.bytes, fifo_read);
}
else
{
sleep(1);
printf("Fail to read data from the client\n");
}
// Because of the error in client program this server program
// always pause here
fd = open(fifo_path, O_WRONLY);
printf("Now writing feedback to the client\n");
write(fd, info_w, sizeof(info_w));
close(fd);
}
}
Could anyone explain why the segmentation fault error appears in the client program? Then I can test if the both the client and the server can co-op properly.By the way, I read this post already but, in this post, it is a one-time data stream and I cannot find any hints in it.

implementing internet radio: trying to open '.au' file in c

I am trying to implement an 'internet radio' in C. This requires a server that keeps on playing an audio file continuously and whenever a client request arrives, the server creates a thread that delivers the audio file to the user. The server , when started, spawns a thread that keeps on writing from an audio file onto a global buffer space and the user corresponding buffers keep on reading from the global buffer space and keep on sending the audio file in 'chunks' to the user. And the user tries to play the audio file through the help of '/dev/audio' (I am using ubuntu).
The problem is that when I try to open a '.au' file using 'open' function on the server, a file descriptor of 0 is assigned. So, I am unable to pull the contents out of the audio file and send it to the client(Rather whatever I type on the terminal is sent to the client).
Is there some way of open '.au' files with the 'open' function in C?? If not, then what file extensions does 'open' function support and what can I do, i.e., what type of file extension should I use to make the 'open' function open the file and send to the user?
assure you are using open file mode of binary - IE. given_mode = "rb" where r means read and b means binary - following code reads a binary file and outputs the first few bytes - enjoy
// gcc -o read_binary_au_file read_binary_au_file.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main() {
const char * given_mode = "rb";
const char * given_filename = "/home/scott/Documents/data/audio/sample.au";
FILE * fh;
fh = fopen(given_filename, given_mode);
if (fh == NULL) {
fprintf(stderr, "ERROR - failed to open file %s in mode %s\n",
given_filename, given_mode);
return (-2);
}
// --- identify file size --- //
off_t file_size;
struct stat stat_struct; // data structure to be returned from call to fstat on file descriptor
int fd = fileno(fh); // get file descriptor from file handle
if ((fstat(fd, & stat_struct) != 0) || (! S_ISREG(stat_struct.st_mode))) {
fprintf(stderr, "ERROR - failed to stat file");
return (-3);
}
file_size = stat_struct.st_size;
printf("file_size %lu\n", file_size);
// --- now read data from the binary file --- //
unsigned long MAX_READ_CHARS = 4096;
unsigned long desired_num_bytes_to_read = (file_size > MAX_READ_CHARS) ? MAX_READ_CHARS : file_size;
char * mem_buffer = malloc(sizeof(char) * desired_num_bytes_to_read);
unsigned long num_bytes_actually_io = 0;
// read initial bytes into memory buffer
num_bytes_actually_io = fread(mem_buffer, sizeof(char), desired_num_bytes_to_read, fh);
if (fclose(fh)) {
fprintf(stderr, "ERROR - failed to close file\n");
return (-4);
}
if (num_bytes_actually_io != desired_num_bytes_to_read) {
fprintf(stderr, "ERROR - failed to read desired_num_bytes_to_read %lu ... instead num_bytes_actually_io %lu\n",
desired_num_bytes_to_read, num_bytes_actually_io);
return (-1);
}
printf("num_bytes_actually_io %lu\n", num_bytes_actually_io);
// ... now do something with mem_buffer which contains data read from binary file
int num_bytes_to_show = 100;
num_bytes_to_show = (num_bytes_actually_io > num_bytes_to_show) ? num_bytes_to_show : num_bytes_actually_io;
printf("\nhere are the first %d characters from given binary file\n", num_bytes_to_show);
printf("-->");
int i = 0;
for (; i < num_bytes_to_show; i++) {
// printf("%c", mem_buffer[i]); // as chars
printf("%x", mem_buffer[i]); // as hex
}
printf("<--");
printf("\n");
free(mem_buffer);
printf("\nprocessing complete\n");
return 0;
}

Program displays strange characters on the screen

I'm developing a client-server program, and this is my server_2 file, who will comunicate with the main server.
The program displays on the screen these lines when is running. I think that those lines after the mkfifo are causing this.
i�e|楬���h�.N=��.8��
i�H��h� ��h� �i���Ǭ��ǬjǬ�dǬ�#��i�P#h�Ǭ���h����h�jǬ��ǬP
Structures
typedef struct request req;
struct request
{
char str[256];
int client_pid;
int login; // In case of client, to identify if is logged
int whois; // To identify who is the client and the server
};
typedef struct answer ans;
struct answer
{
char str[256];
int server_pid;
int type;
int login;
int num_users;
};
Main:
#include "header.h"
int main(int argc, char *argv[])
{
int fifo_1, fifo_2;
struct request req;
struct answer ans;
if(argc == 2) // Check if the command was well prompted
{
if(strcasecmp(argv[1], "show") == 0 || strcasecmp(argv[1], "close") == 0)
{
if(fifo_2 = open("FIFO_SERV", O_WRONLY) == -1)
{
perror("[SERVER_2] Error: on the FIFO_SERVER opening!\n");
sleep(2);
exit(EXIT_FAILURE);
}
if(mkfifo("FIFO_SERV_2", 0777) == -1)
{
perror("[SERVER_2] Error: on the FIFO_SERVER_2 creation!\n");
sleep(2);
exit(EXIT_FAILURE);
}
strcpy(req.str, argv[1]); // Copy the argumento to the structure
write(fifo_2, &req, sizeof(req)); // Write a request to the server
strcpy(req.str,""); // Clean the string
fifo_1 = open("FIFO_SERV_2", O_RDONLY);
read(fifo_1, &ans, sizeof(ans)); //Read an answ
}
//close(fifo_1);
unlink("FIFO_SERVER_2");
sleep(2);
exit(EXIT_SUCCESS);
}
The precedence rules of operators = and == make the line
if(fifo_2 = open("FIFO_SERV", O_WRONLY) == -1)
equivalent to
if(fifo_2 = (open("FIFO_SERV", O_WRONLY) == -1))
which essentially assigns 0 to fifo_2 if open succeeds and 1 if open fails. The values 0 and 1 also happens to be the respective values of the standard input and output file descriptor in POSIX standard library implementations (see File descriptor on wikipedia), so later when you execute
write(fifo_2, &req, sizeof(req)); // Write a request to the server
you are either trying to write to standard input (undefined behavior), or to standard output depending on whether the file could be opened rather than to the server. To fix this, you can replace the open expression with:
if((fifo_2 = open("FIFO_SERV", O_WRONLY)) == -1)
Then, you may have to figure out why you can't open the file (since you are presumably writing to standard output, which means open failed).

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.

Linux device driver, Is it possible to get the minor number using a file descriptor?

I am writing a device driver for Linux. It creates a device with 4 minor numbers. Whenever we attempt to write to the device at minor number 3, we are suppose to kill the device and currently it isn't suppose to do anything else except print it is writing to the booga device. Here is some of my current code and I can post more code if necessary:
Write method:
static ssize_t booga_write (struct file *filp, const char *buf, size_t count, loff_t *f_pose) {
printk("Attempting to write to booga device\n");
/* need to protect this with a semaphore if multiple processes
will invoke this driver to prevent a race condition */
if (down_interruptible (&booga_device_stats->sem))
return (-ERESTARTSYS);
booga_device_stats->num_bytes_written += count;
up(&booga_device_stats->sem);
return count; // pretend that count bytes were written
}
How it is tested:
static void run_write_test(char *device, int bufsize)
{
char *buf;
int src;
int out;
src = open(device, O_WRONLY);
if (src < 0) {
perror("Open for write failed:");
exit(1);
}
buf = (char *) malloc(sizeof(char)*(bufsize+1));
fprintf(stderr, "Attempting to write to booga device\n");
out = write(src, buf, bufsize);
fprintf(stderr, "Wrote %d bytes.\n", out);
free(buf);
close(src);
}
I am wondering if there is a way to get the minor number. I looked in linux/fs.h and saw that the file struct has a member called private_data but whenever I attempt to call this, it will crash my system as it is currently set to null.
Or should I not be trying to get the minor number from the struct file at all and should attempt to keep track of it when I first open the device?
You can get the minor number like so:
iminor(filp->f_path.dentry->d_inode)

Resources