Read/Write struct to fifo in C

cfifostruct

I'm trying to pass structs between processes using named pipes. I got stuck at trying to open the pipe non-blocking mode. Here's my code for writing to the fifo:

void writeUpdate() {
    // Create fifo for writing updates:
    strcpy(fifo_write, routing_table->routerName);
    // Check if fifo exists:
    if(access(fifo_write, F_OK) == -1 )
        fd_write = mkfifo(fifo_write, 0777);
    else if(access(fifo_write, F_OK) == 0) {
        printf("writeUpdate: FIFO %s already exists\n", fifo_write);
        //fd_write = open(fifo_write, O_WRONLY|O_NONBLOCK);
    }
    fd_write = open(fifo_write, O_WRONLY|O_NONBLOCK);
    if(fd_write < 0)
        perror("Create fifo error");
    else {
        int num_bytes = write(fd_write, routing_table, sizeof(routing_table));
        if(num_bytes == 0)
            printf("Nothing was written to FIFO %s\n", fifo_write);
        printf("Wrote %d bytes. Sizeof struct: %d\n", num_bytes,sizeof(routing_table)+1);
        }
    close(fd_write);
   }

routing_table is a pointer to my struct, it's allocated, so there's no prob with the name of the fifo or smth like that.
If I open the fifo without the O_NONBLOCK option, it writes smth for the first time, but then it blocks because I'm having troubles reading the struct too. And after the first time, the initial fifo is created, but other fifo's appear, named '.', '..'.
With O_NONBLOCK option set, it creates the fifo but always throws an error: 'No such device or address'. Any idea why this happens? Thanks.

EDIT: Ok, so I'm clear now about opening the fifo, but I have another problem, in fact reading/writing the struct to the fifo was my issue to start with. My code to read the struct:

void readUpdate() {
struct rttable *updateData;
allocate();

strcpy(fifo_read, routing_table->table[0].router);

// Check if fifo exists:
if(access(fifo_read, F_OK) == -1 )
    fd_read = mkfifo(fifo_read, 777);
else if(access(fifo_read, F_OK) == 0) {
    printf("ReadUpdate: FIFO %s already exists\n Reading from %s\n", fifo_read, fifo_read);        
}
fd_read = open(fifo_read, O_RDONLY|O_NONBLOCK);
int num_bytes = read(fd_read, updateData, sizeof(updateData));
close(fd_read);
if(num_bytes > 0) {
    if(updateData == NULL)
        printf("Read data is null: yes");
    else
        printf("Read from fifo: %s %d\n", updateData->routerName, num_bytes);

    int result = unlink(fifo_read);
    if(result < 0)
        perror("Unlink fifo error\n");
    else {
        printf("Unlinking successful for fifo %s\n", fifo_read);
        printf("Updating table..\n");
        //update(updateData);
        print_table_update(updateData);
    }
} else
    printf("Nothing was read from FIFO %s\n", fifo_read);
}

It opens the fifo and tries to read, but it seems like nothing is in the fifo, although in writeUpdate the first time it says it wrote 4 bytes (this seems wrong too). At reading, first time around it prints 'a' and then num_bytes is always <=0.
I've looked around and only found this example, with simple write/read, is there smth more needed when writing a struct?

My struct looks like this:

typedef struct distance_table {
char dest[20];       //destination network
char router[20];     // via router..
int distance;
} distance_table;

typedef struct rttable {
char routerName[10];
char networkName[20];
struct distance_table table[50];
int nrRouters;
} rttable;

struct rttable *routing_table;

Best Answer

"No such device or address" is the ENXIO error message. If you look at the open man page, you'll see that this error is reported in particular if:

O_NONBLOCK | O_WRONLY is set, the named file is a FIFO and no process has the file open for reading. (...)

which is exactly your situation. So the behavior you are seeing is normal: you can't write (without blocking) to a pipe that has no readers. The kernel won't buffer your messages if nothing is connected to the pipe for reading.

So make sure you start the "consumer(s)" before your "producer", or remove the non-blocking option on the producer.

BTW: using access is, in most circumstances, opening yourself to time of check to time of use issues. Don't use it. Try the mkfifo - if it works, you're good. If it fails with EEXISTS, you're good too. If it fails otherwise, clean up and bail out.

For the second part of your question, it really depends completely on how exactly the data you are trying to send is structured. Serializing a random struct in C is not easy at all, especially if it contains variable data (like char *s for example).

If you struct contains only primitive types (and no pointers), and both sides are on the same machine (and compiled with the same compiler), then a raw write on one side and read on the other of the whole struct should work.

You can look at C - Serialization techniques for more complex data types for example.

Concerning your specific example: you're getting mixed up between pointers to your structs and plain structs.

On the write side you have:

int num_bytes = write(fd_write, routing_table, sizeof(routing_table));

This is incorrect since routing_table is a pointer. You need:

int num_bytes = write(fd_write, routing_table, sizeof(*routing_table));
// or sizeof(struct rttable)

Same thing on the read side. On the receiving size you're also not allocating updateData as far as I can tell. You need to do that too (with malloc, and remember to free it).

struct rttable *updateData = malloc(sizeof(struct rrtable));