johnny_bravo
johnny_bravo

Reputation: 43

structure of msg in IPC message queues

I am having some trouble while using a custom definition of message struct in message queues. I am building a chat app between a client and a server. The client is sending a message, while the server is receiving the msg and printing it.

This is the server side code -

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>

#define MAX 200
#define SERVER 1L

typedef struct {
    long    gid;
    char    buffer[MAX];
    char    header[20];
    long    pid;
} MESSAGE;

struct msqid_ds buf;
MESSAGE msg;
int mid_server, mid_client;
key_t key1, key2;
int client_id = 0;

int main(){
    //Creating a message queue
    key1 = ftok(".", 'z');
    msg.gid = 1;
    if((mid_server = msgget(key1, IPC_CREAT | 0666))<0){           
        printf("Error Creating Message Queue\n");
        exit(-1);
    }

    //Receiving message from client, throws and error if input is invalid
        if(msgrcv(mid_server, &msg, MAX, SERVER, 0)<0){
        perror("msgrcv");
        exit(-1);
        }  
    //Server displays received message
        printf("SERVER receives: %s\n", msg.buffer);
        printf("SERVER receives---: %s\n", msg.header);
        printf("SERVER receives: %ld\n", msg.pid);                            
}

This is the client side -

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <string.h>

#define MAX 200
#define SERVER 1L

typedef struct {
    long    gid;
    char    buffer[MAX];
    char    header[20];
    long    pid;
} MESSAGE;


int mid_client, mid_server;
key_t key1,key2;
MESSAGE msg;
int client_id = -1;

int main(){
    //Creating a message queue
    key1 = ftok(".", 'z');
    if((mid_server = msgget(key1, IPC_CREAT | 0666))<0){             //server receives here
        printf("Error Creating Message Queue\n");
        exit(-1);
    }
    printf("%d\n", mid_server);
    fgets(msg.buffer, MAX, stdin);
    msg.gid = SERVER;
    strcpy(msg.header, "msg");
    msg.pid = 2;
    if(msgsnd(mid_server, (struct MESSAGE*)&msg, sizeof(msg), IPC_NOWAIT)==-1){
        perror("msgsnd");
        exit(-1);
    }
    printf("message sent\n");  
}

My doubt is that it prints the msg.buffer data on server side alright, but fails to print anything for msg.header and prints 0 for msg.pid. Is this issue because of the structure of MESSAGE. Also, is the "size_t msgsz" parameter in msgsnd correct? TIA

Upvotes: 0

Views: 964

Answers (1)

G. Sliepen
G. Sliepen

Reputation: 7973

According to the manpage, the msgsz parameter is the size of the message buffer minus the mtype. So using sizeof(msg) is not correct, it will cause msgsnd() to read beyond the end of the variable msg. Also, it will cause the server to fail, since the server only expects to receive MAX bytes (again, excluding mtype).

I would avoid adding multiple member variables to struct msgbuf, and instead just add one member that is either a char array big enough to hold whatever data you want to send, or another struct. For example:

#define MAX 200
#define SERVER 1L

struct payload {
    char    buffer[MAX];
    char    header[20];
    long    pid;
};

struct msgbuf {
    long gid;
    struct payload payload;
};

And then you can use it like so in the client:

struct msgbuf msg;

msg.gid = SERVER;
fgets(msg.payload.buffer, sizeof msg.payload.buffer, stdin);
strncpy(msg.payload.header, sizeof msg.payload.header, "msg");
msg.payload.pid = 2;

if (msgsnd(mid_server, &msg, sizeof msg.payload, IPC_NOWAIT) == -1) ...

And like so in the server:

struct msgbuf msg;

if (msgrcv(mid_server, &msg, sizeof msg.payload, SERVER, 0) == -1) ...

Note the similarity in the calls to msgsnd() and msgrcv().

Be aware of alignment restrictions, if you have any member in struct payload that has alignment restrictions larger than those of gid, it might cause payload to not follow immediately after gid. The msgsz parameter should take this into account. However, the above code should be fine.

Upvotes: 1

Related Questions