Pipe "bad address" on pipe open - c

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.

Related

Running a command inside a lxc container using C

'm trying to use the lxc C API to execute a command inside a container, and hopefully later make it to also prints the results of the command on the stdout/stderr. But so far, I can't get further than creating a simple file in /root/a. Each time I run the code, it does nothing inside the container. I can manually create the file, and the container is defined and running during the execution of the code. And also I'm running it as root since I can't access the container otherwise.
#include <sys/wait.h>
#include <stdio.h>
#include <lxc/lxccontainer.h>
int lxc_exec(char *prog, char *argv[])
{
struct lxc_container *c;
lxc_attach_options_t opt = LXC_ATTACH_OPTIONS_DEFAULT;
lxc_attach_command_t cmd;
int ret = -1;
int status;
pid_t pid;
const char *lxc = "/var/lib/container_test/lxc";
const char *name = "container_test";
c = lxc_container_new(name, lxc);
cmd = (lxc_attach_command_t)
{
.program = prog,
.argv = argv
};
ret = c->attach(c, lxc_attach_run_command, &cmd, &opt, &pid);
// this evaluates to true
if (ret >= 0)
pid = waitpid(pid, &status, 0);
return ret;
}
int main(int argc, char *argv[])
{
char program = "/bin/touch";
char *argv[] = {"/home/a"};
int ret;
ret = lxc_exec(program, argv);
// Returns: Return code is 65280;
printf("Return code is %d", ret);
}
So I've found my answer in the end.
argv also needs to contain the program name. Even if I also tried that, there was another small thing I've missed. There needs to be a NULL element in the array to work.
I've edited my function lxc_exec to only accept an char array, and when I'm building the command struct I did:
command.program = argv[0];
command.argv = argv;
When calling the function it's now been called as
char *args[] = {'/bin/touch', '/home/a', NULL};
int ret = lxc_exec(args);

Named Pipe client and server, message truncated on server?

I got a server that is always running, it creates a log file that receives via named pipe one argument and stores it on the log.txt file.
Clients sent a message via argument to the named pipe.
cliente side i guess its ok, if i cat /tmp/talk its there the full message, but on the server its only storing the first char. why is that?
And a simplier question, is there a better way to implement the server cycle to check the pipe?
client
int main(int argc, char const *argv[]){
char *myfifo = "/tmp/talk"; int fd,n;
fd = open(myfifo,O_WRONLY);
write(fd,argv[1],strlen(argv[1])+1); printf("Sent to server: %s \n",argv[1]);
close(fd);
}
server
int main(int argc, char const *argv[]){
char *myfifo = "/tmp/talk";
char buffer[2024];
//char *log = "log.txt";
int fd,n;
mkfifo(myfifo, 0666);
int log = open("log.txt",O_CREAT|O_APPEND|O_WRONLY, 0666);
fd = open(myfifo,O_RDONLY);
while(1) {
if(n = read(fd,buffer,1024)>0) {
write(log,buffer,n);
write(1,buffer,n);
//printf("Client connected sent: %s",buffer);
}
}
}
n = read(fd,buffer,1024)>0
evaluates like
n = (read(fd,buffer,1024)>0)
so 1 is stored in n (instead of the number of bytes read) if read returns a positive value. Use instead:
(n = read(fd,buffer,1024))>0
as conditional, then it should work as expected.

System calls in C (File Descriptor)

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);
}

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).

linux fork socketpair sock_dgram

I'm new to socketpairs and I need my children each to pass information from a structure to the parent.I was told this can be done using SOCK_DGRAM but I don't know how to do it.I looked over the internet but i couldn't find a concrete example.Can you please show for example hoe can you pass to the parent a structure made out of 2 ints and a string maybe ?I just want an example so I can understand how I could build this kind of socketpair and send information through it.Thank you
How about the following:
int sockets[2];
if (socketpair(AF_INET, SOCK_DGRAM, 0, sockets) != -1)
{
int res = fork();
if (res == 0)
{
/* In child process */
/* We only need one socket, so close the other */
close(sockets[0]);
struct some_structure my_struct;
write(sockets[1], &my_struct, sizeof(my_struct));
/* All done */
exit(0);
}
else if (res > 0)
{
/* In parent process */
/* We only need one socket, so close the other */
close(sockets[1]);
struct some_structure my_struct;
read(sockets[0], &my_struct, sizeof(my_struct));
}
}
The above code doesn't check for, or handle, errors. It can't handle structures containing pointers, structures using arrays are okay though.
Assuming that your string is represented as a char* as in
struct data {
int i, j;
char *s;
};
you need to devise some serialization format, because sending a pointer won't work; the pointee is not passed so it won't point to anything useful in the receiver (the parent). A simple format would be to put the integers end-to-end, then directly append the string including its NUL terminator, so you'd get
int senddata(int fd, struct data const *d)
{
size_t msglen = 2 * sizeof(int) + strlen(d->s) + 1;
char *msg = malloc(msglen);
if (msg == NULL)
return -1;
((int *)msg)[0] = d->i;
((int *)msg)[1] = d->j;
strcpy(msg + 2 * sizeof(int), d->s);
ssize_t r = send(fd, msg, msglen, 0);
free(msg);
return r;
}
with a corresponding receive function for the parent. You might want to put some maximum length on the string, because the parent needs to know the size of the message in advance.

Resources