makrand pawar makrand pawar - 1 month ago 14
C Question

IPC Queue msgsnd error

This is a simple program to send msg to queue but it gives "snd error" as the output.
the queue is created. I checked with ipcs -q.
What have i done wrong?

#include<stdio.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<stdlib.h>
struct msg{
int mtype;
char mtext[1024];

}snd;
void main()
{
int id;
if(id=msgget(1234,IPC_CREAT|0666)<0)
{
printf("ipc error");
}
else{
snd.mtype=1;
scanf("%[^\n]",snd.mtext);
getchar();

if(msgsnd(id,&snd,sizeof(snd.mtext),IPC_NOWAIT)<0){
printf("snd error");
}
else {
printf("msg snd");
}

}

}

Answer

What have i done wrong?

You check the return code of msgsnd, which is good, and this means, you're already ahead of many programmers. But you haven't read the whole manual of msgsnd, which states

RETURN VALUE
On failure both functions return -1 with errno indicating the error,

where errno is the important part.

When you look further, there's also a section named ERRORS, which shows what might go wrong

ERRORS
When msgsnd() fails, errno will be set to one among the following values:

  EACCES The calling process does not have write permission on the
          message queue, and does not have the CAP_IPC_OWNER capability.  

  EAGAIN The message can't be sent due to the msg_qbytes limit for the
          queue and IPC_NOWAIT was specified in msgflg.

...

And still further down, you will find an example section

EXAMPLE

  The program below demonstrates the use of msgsnd() and msgrcv().  

...

Where the usage of msgsnd shows an important idiom: when an error occurs and the specific error is reported in errno, this error may be printed by perror

if (msgsnd(qid, (void *) &msg, sizeof(msg.mtext),
           IPC_NOWAIT) == -1) {
    perror("msgsnd error");
    exit(EXIT_FAILURE);
}

perror will show a message detailing what went wrong with the call to msgsnd. This can also be used with any other system call.


According to the manual "Invalid argument" (EINVAL) means one of

EINVAL msqid was invalid, or msgsz was less than 0.
EINVAL (since Linux 3.14) msgflg specified MSG_COPY, but not IPC_NOWAIT.
EINVAL (since Linux 3.14) msgflg specified both MSG_COPY and MSG_EXCEPT.

Since you don't specify MSG_COPY, the error must be the first one.

  • msgsz is definitely greater than 0
  • So it must be an invalid msqid!

When you look at

if(id = msgget(1234, IPC_CREAT | 0666) < 0)

you see the missing parentheses around (id = msgget(...)). Most likely msgget returns a value > 0, so msgget(...) < 0 is false, id will become 0 (false), and the else branch is taken.

As a consequence, calling msgsnd(0, ...) is most likely the culprit and source of the error.


To fix this, be explicit

id = msgget(1234, IPC_CREAT | 0666);
if (id < 0) {
...
} else {
...
}

or put at least parentheses around the assignment

if ((id = msgget(1234, IPC_CREAT | 0666)) < 0) {
Comments