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).
Related
So, im trying to start a webserver that uses pipes to comunicate between process.
I was thinking to make a struct named ctx to send other info also.
My code looks like this:
webserver.h
typedef struct
{
int pipefd[2];
} ctx_t;
webserver.c
int main(int argc, char *argv[]){
ctx_t *ctx = {0};
if(pipe(ctx->pipefd) == -1){
perror("ctx pipe error");
exit(EXIT_FAILURE);
}
...
...
}
Output: "ctx pipe error: Bad address"
if instead i declare my program like this, i have no error and the programs continue
webserver.h
int pipefd[2];
webserver.c
int main(int argc, char *argv[]){
if(pipe(pipefd) == -1){
perror("ctx pipe error");
exit(EXIT_FAILURE);
}
...
...
}
Any ideas why i cant open the pipe inside a struct? I still havn't made any forks in the main program.
Thanks.
You're passing a null pointer to a function (system call) pipe() that doesn't accept null pointers. Don't do that!
ctx_t *ctx = {0};
That sets ctx to a null pointer, albeit somewhat verbosely (the braces are not necessary, though they're not harmful). You need to allocate the ctx_t structure somewhere before trying to use it.
Use:
cts_t ctx = { { 0, 0 } };
and:
if (pipe(ctx.pipefd) != 0)
…report error etc…
Using == -1 is also OK.
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);
}
follwing code has written to open a file and write data to terminal using sysyem calls in linux.
To read the value of the file descriptor (fd) it should assign a value. As we know in if else statement, from if part else part or else if part one part will implement at a time. So according to following code fd will have a value only at else if line. But when I pass a file name and run this program it opens the file. File opening is happen in while loop from read(() system call. But while loop is in else part and since file descriptor can't have any value theoretically. So how does the read function get recognize the file exactly? This is confusing me.
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#define SIZE 10
int main(int argc, char *argv[])
{
int fd,n;
char buff[SIZE];
if(argc != 2)
{
printf("USAGE : %s\n",argv[0] );
exit(1);
}
else if ((fd = open(argv[1],0)) == -1)
{
perror("STATUS");
exit(1);
}
else
{
while((n = read(fd,buff,SIZE)) > 0)
{
write(1,buff,SIZE);
}
close(fd);
}
}
Following happens here:
Let's suppose the program is started with xyz.txt on the command line and let's suppose the xyz.txt file does exist:
if(argc != 2)
{
// we don't get here because argc == 2
printf("USAGE : %s\n",argv[0] );
exit(1);
}
else if ((fd = open(argv[1],0)) == -1) // the statement in the if clause will therefore
// be executed, fd will be something different
// from -1 because open succeeded
{
perror("STATUS"); // therefore we dont ge here either
exit(1);
}
else
{ // instead we get here and
while((n = read(fd,buff,SIZE)) > 0) // everything works as expected
{
write(1,buff,SIZE);
}
close(fd);
}
I'm using Intel Edison and SensorTag. In order to get temperature data via BLE, there are a bunch of commands. When I define popen as:
popen(command,"w");
code works fine most of the times. (Crashes other times due to delay issues I assume as I don't control the responses.)
However, when I want to control the command/console responses (such as step into next line when bluetooth connection is established and if not try to connect again etc.), I cannot read the responses. My "data" variable is not changed.
I also tried other modes of "popen" but they give run-time errors.
Here is the code I'm using:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int endsWith (char* base, char* str) {
int blen = strlen(base);
int slen = strlen(str);
return (blen >= slen) && (0 == strcmp(base + blen - slen, str));
}
FILE* get_popen(char* command, int close, int block) {
FILE *pf;
char data[512];
// Setup our pipe for reading and execute our command.
pf = popen(command,"w");
// Error handling
if (block == 1) {
// Get the data from the process execution
char* result;
do {
result=fgets(data, 512 , stderr);
if (result != NULL) {
printf("Data is [%s]\n", data);
}
} while (result != NULL);
// the data is now in 'data'
}
if (close != 0) {
if (pclose(pf) != 0)
fprintf(stderr," Error: Failed to close command stream \n");
}
return pf;
}
FILE* command_cont_exe(FILE* pf, char* command, int close, int block) {
char data[512];
// Error handling
if (pf == NULL) {
// print error
return NULL;
}
fwrite(command, 1, strlen(command), pf);
fwrite("\r\n", 1, 2, pf);
if (block == 1) {
// Get the data from the process execution
char* result;
do {
result=fgets(data, 512 , stderr);
if (result != NULL) {
printf("Data is [%s]\n", data);
}
} while (result != NULL);//
}
// the data is now in 'data'
if (close != 0) {
if (pclose(pf) != 0)
fprintf(stderr," Error: Failed to close command stream \n");
}
return pf;
}
int main()
{
char command[50];
sprintf(command, "rfkill unblock bluetooth");
get_popen(command, 1, 0);
printf("Working...(rfkill)\n");
sleep(2);
sprintf(command, "bluetoothctl 2>&1");
FILE* pf = get_popen(command, 0, 1);
printf("Working...(BT CTRL)\n");
sleep(3);
sprintf(command, "agent KeyboardDisplay");
command_cont_exe(pf, command, 0, 1);
printf("Working...(Agent)\n");
sleep(3);
//Main continues...
You cannot do this with popen, but can build a program using fork, exec and pipe. The last opens two file descriptors, which are related: the parent's connection to a pipe, and the child's connection. To make a two-way connection to a child process, you must use two calls to pipe.
The file-descriptors opened by pipe are not buffered, so you would use read and write to communicate with the child (rather than fgets and fprintf).
For examples and discussion, see
Does one end of a pipe have both read and write fd?
Read / Write through a pipe in C
UNIX pipe() : Example Programs
pipe(7) - Linux man page
6.2.2 Creating Pipes in C
Unfortunately, you can use popen() in one direction only. To get a bidirectional communication, you need to create two anonymous pipes with pipe() for stdin and stdout and assign them to the file handles 0 and 1 with dup2().
See http://tldp.org/LDP/lpg/node11.html for more details.
I'm writing a program that when run from two separate bash sessions as two separate processes, opens a named pipe between the two to allow strings to be sent from one to the other.
When the process is first executed from one terminal, it checks stat(fname, buf) == -1 to see if a file at path fname exists and if not, creates it. The process then assumes that since it was the one to make the FIFO, it is the one that will be sending messages through it and continues accordingly.
After that occurs, the program can then be run from another terminal that should determine that it will be the receiver of messages through the pipe by checking stat(fname, buf) == -1. The condition should return false now, and stat(fname, buf) itself should return 0 because there exists a file at fname now.
But for reasons I am unable to discern, when the second process is run, stat(fname, buf) still returns -1. The variable errno is set to EFAULT. The man page for stat() only decribes EFAULT as "Bad address." Any help determining why the error occurs or what is meant by "Bad address." would be greaty appreciated.
I've verified that the file is indeed created by the first process as intended. The first process waits at the line pipe = open(fname, O_WRONLY); because it can't continue until the other end of pipe is opened.
Edit: The following is a self-contained implementation of my code. I have confirmed that it compiles and experiences the problem I described here.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define MAX_LINE 80
#define oops(m,x) { perror(m); exit(x); }
int main(int argc, char const *argv[]) {
char line[MAX_LINE];
int pipe, pitcher, catcher, initPitcher, quit;
struct stat* buf;
char* fname = "/tmp/absFIFOO";
initPitcher = catcher = pitcher = quit = 0;
while (!quit) {
if (((!pitcher && !catcher && stat(fname, buf) == -1) || pitcher) && !quit) {
// Then file does not exist
if (errno == ENOENT) {
// printf("We're in the file does not exist part\n");
if (!pitcher && !catcher) {
// Then this must be the first time we're running the program. This process will take care of the unlink().
initPitcher = 1;
int stat;
if (stat = mkfifo(fname, 0600) < 0)
oops("Cannot make FIFO", stat);
}
pitcher = 1;
// open a named pipe
pipe = open(fname, O_WRONLY);
printf("Enter line: ");
fgets(line, MAX_LINE, stdin);
if (!strcmp(line, "quit\n")) {
quit = 1;
}
// actually write out the data and close the pipe
write(pipe, line, strlen(line));
close(pipe);
}
} else if (((!pitcher && !catcher) || catcher) && !quit) {
// The first condition is just a check to see if this is the first time we've run the program. We could check if stat(...) == 0, but that would be unnecessary
catcher = 1;
pipe = open("/tmp/absFIFO", O_RDONLY);
// set the mode to blocking (note '~')
int flags;
flags &= ~O_NONBLOCK;
fcntl(pipe, F_SETFL, flags); //what does this do?
// read the data from the pipe
read(pipe, line, MAX_LINE);
if (!strcmp(line, "quit\n")) {
quit = 1;
}
printf("Received line: %s\n", line);
// close the pipe
close(pipe);
}
}
if (initPitcher)
unlink(fname);
return 0;
}
You have this piece of code:
struct stat* buf;
...
if (((!pitcher && !catcher && stat(fname, buf) == -1)
When you call stat(), buf isn't initalized and there's no telling what it points to.
You must allocate some storage for it, so stat() has a valid place to store the result.
The easiest thing is to just allocate it on the stack:
struct stat buf;
...
if (((!pitcher && !catcher && stat(fname, &buf) == -1)
You have not shown your code, but EFAULT means 'bad address'. This indicates that you have not properly allocated (or passed) your buffer for stat or the filename (fname).
buf isn't initialised anywhere. What exactly do you expect to happen?