I want to send messages between two processes. But I get a EACCES error when im trying to send a message with msgsnd()
Creating the message queue
const char* MSG_QUEUE = "/tmp/msg_queue";
int file = open(MSG_QUEUE, O_CREAT | O_RDWR | O_APPEND, 0755);
close(file);
key_t key = ftok(MSG_QUEUE, 1);
errno = 0;
msg_queue = msgget(key, IPC_CREAT);
if(msg_queue == -1) {
M_DEBUG("Error %s\r\n", strerror(errno));
}
message struct
struct feld_msg_s {
long id;
char mtext[5];
};
sending a message
struct feld_msg_s a_msg = {1, "Test"};
errno = 0;
int ret = msgsnd(msg_queue, &a_msg, sizeof(a_msg.mtext), 0);
if(ret == -1) {
if(errno == EACCES) {
printf("\r\n NO PERMISSION\r\n");
} else {
printf("msgsnd ERROR!: %s\r\n", strerror(errno));
}
}
in the manpage of msgsnd is written
EACCES The calling process does not have read permission on the message queue, and does not have the CAP_IPC_OWNER capability.
so I've added the following capabilities with the setcap command
sudo setcap CAP_SETFCAP,CAP_IPC_OWNER+epi /home/mvollmer/build-APP-Desktop_Qt_5_6_1_GCC_64bit-Debug/APP
I've checked with getcap if the application got the capabilities. It's fine. But I still receive the No Permission Error.
When execute the application with root rights, its working!
One thing is very strange, altough msgget was succesfull ipcs dont show any message queues.
So where is my fault?
I'm using Linux Mint
Additional Question: Is is possible to use another datatype then char in the msg struct or is a message restricted to strings?
You need to read the man page. Per the POSIX msgget() standard:
SYNOPSIS
#include <sys/msg.h>
int msgget(key_t key, int msgflg); [Option End]
DESCRIPTION
...
The low-order 9 bits of msg_perm.mode shall be set to the low-order 9 bits of msgflg.
Thus, this code
msg_queue = msgget(key, IPC_CREAT);
has the "low-order 9 bits of msgflg" all set to zero. Thus the message queue mode is also all 0 - no permissions for anyone.
Related
I am trying to understand the working of message queues in Linux.
Eventually, I'd want to have a program where I could send and receive stuff between different threads/processes, but to start off, I only create a message queue, and have it block on an input in a queue, but mq_receive() returns Message too long.
Looking at the documentation, this error indicates `msg_len was less than the mq_msgsize attribute of the message queue., but this isn't the case for me.
Sorry if I'm missing something obvious but I couldn't figure it out.
#define MAX_MESSAGES 10
#define MAX_MSG_SIZE 256
#define MSG_BUFFER_SIZE MAX_MSG_SIZE + 10
int main()
{
mqd_t qd_server, qd_client;
char in_buffer [MSG_BUFFER_SIZE];
char out_buffer [MSG_BUFFER_SIZE];
struct mq_attr attr, tmpAttr;
attr.mq_flags = 0;
attr.mq_maxmsg = MAX_MESSAGES;
attr.mq_msgsize = MAX_MSG_SIZE;
attr.mq_curmsgs = 0;
if ((qd_server = mq_open ("/sp-example-server", O_RDONLY|O_CREAT, 0644, &attr)) == -1)
{
printf("%s\n", strerror(errno));
}
if (mq_getattr(qd_server, &tmpAttr) == -1)
{
printf("mq_getattr error");
}
printf("Maximum # of messages on queue: %ld\n", tmpAttr.mq_maxmsg);
printf("Maximum message size: %ld\n", tmpAttr.mq_msgsize);
int iret = mq_receive(qd_server, in_buffer, sizeof(in_buffer), NULL);
if (iret == -1)
{
printf("%s\n", strerror(errno));
}
return 0;
}
Edit:
After running mmq_getattr(qd_server, & tmpAttr), it seems as if attributes were never set which probably is the cause. Now on to why are attributes not set?
// output:
Maximum # of messages on queue: 10
Maximum message size: 8192
The code you've shown us did not create the /sp-example-server message queue.
Instead, some prior process created that queue with the values you see for mq_maxmsg and mq_msgsize. If the queue's creator omitted the attribute specification — that is, passed a NULL struct mq_attr * to mq_open — then the implementation will provide default values. On Linux, these defaults match the values you see.
It seems plausible some early version of your code called mq_open with NULL attributes, and thus O_CREAT'd the queue as you are experiencing it now.
To accommodate this, you might reboot or mq_unlink the queue, forcing the next call to mq_open to re-create it. More defensively, when you do not open the queue O_EXCLusively, then use mq_getattr to validate the queue's attributes.
Problem Summary
I am writing a program that is intended to fork multiple processes, each of which open a unique message queue for receiving messages. Every time I run my program, however, every single forked process encounters the Bad address error when initializing their respective queues with mq_open.
Some Details
My code is intended to generate message queue names dynamically, following the form "/_*, where * is some unique letter (a, b, c, etc.) However, upon trying the same code with the string "/hello"put in place of the dynamically generated names, the program still failed with the same error.
This has led me to believe that the issue is a failure to create a new queue, rather than an issue with the name itself. However, I believe I am passing O_CREAT correctly, so I can't figure out what the problem is.
I did find this previous thread on the subject, but it doesn't seem that that guy was having the same problems. I believe I have included all relevant code below, but please let me know if more is needed. Any help is much appreciated!
My code
Here is the wrapper function that actually calls mq_open:
mqd_t init_queue(char *desc, long m_flags, long m_max, long m_size)
{
mqd_t mq_des;
struct mq_attr attr;
mode_t mode = 0664;
attr.mq_maxmsg = m_max;
attr.mq_msgsize = m_size;
attr.mq_flags = m_flags;
if ((mq_des = mq_open(desc, O_CREAT | O_RDWR, mode, attr)) == -1) {
perror("Error at init_queue");
exit(1);
}
return mq_des;
}
Here is the function that calls init_queue. I've pasted in the relevant macros and helper function (nid) at the top as well, so you can see those:
#define DESCPREF "/_"
#define DESCSIZE 4
#define FIRSTID 97
#define MAXMSGS 200
#define M_SIZE sizeof(struct _message)
char *nid(int id)
{
char *desc = malloc(sizeof(char) * DESCSIZE);
char c = id;
snprintf(desc, DESCSIZE, "%s%c", DESCPREF, c);
return desc;
}
int node(int id, int inc)
{
/* INIT */
proc_info me = malloc(PROCINF_SIZE);
me->id = id;
me->curr = id - FIRSTID + 1;
me->inc = inc;
char *mypath = nid(id);
me->listen = init_queue(mypath, O_NONBLOCK, MAXMSGS, M_SIZE);
/* Do some stuff ... */
close_queue(me->listen);
mq_unlink(mypath);
free(me);
return 0;
}
Finally, the bit of code that forks my individual processes:
int main(){
pid_t pid;
int nodes = TESTNODES;
for (int i = 0; i < nodes; i++) {
if ((pid = fork()) == -1) {
perror("Fork error\n");
exit(1);
} else if (pid == 0) {
node(FIRSTID + i, nodes);
exit(0);
} else {
printf("Forked: %d\n", (int) pid);
}
}
return 1;
}
Expected vs. Actual results
I would expect this code to simply run, printing the pids of forked processes, then exit. Instead I get the following errors (for one example run):
Forked: 27448
Forked: 27449
Error at init_queue: Bad address
Error at init_queue: Bad address
Forked: 27450
Error at init_queue: Bad address
Forked: 27451
Error at init_queue: Bad address
Forked: 27452
Error at init_queue: Bad address
As previously mentioned, I also tried this with the plain string "/hello" used as the input name for mq_open and received the same set of errors (all five failed in that case as well).
You need to pass the pointer to the mq_attr struct like:
if ((mq_des = mq_open(desc, O_CREAT | O_RDWR, mode, &attr)) == -1) {
perror("Error at init_queue");
exit(1);
}
also as per the manual page make sure the values for max messages and msg size make sense otherwise you will get an EINVAL.
EINVAL O_CREAT was specified in oflag, and attr was not NULL, but
attr->mq_maxmsg or attr->mq_msqsize was invalid. Both of
these fields must be greater than zero. In a process that is
unprivileged (does not have the CAP_SYS_RESOURCE capability),
attr->mq_maxmsg must be less than or equal to the msg_max
limit, and attr->mq_msgsize must be less than or equal to the
msgsize_max limit. In addition, even in a privileged process,
attr->mq_maxmsg cannot exceed the HARD_MAX limit. (See
mq_overview(7) for details of these limits.)
I am trying to create a message queue and then send a message to it. Here is what I have tried:
int main(){
int myMsgQueue;
struct msgStruct{
long mtype;
char mtext[LENGTH];
};
struct msgStruct myMsg;
myMsg.mtype = (long)getpid();
strcpy(myMsg.mtext,"Hey there"); //Setting the string of the message
if((myMsgQueue = msgget(IPC_PRIVATE,IPC_CREAT | IPC_EXCL)) == -1) //Creating the message queue
errore(__LINE__);
if(msgsnd(myMsgQueue,&myMsg,sizeof(myMsg) - sizeof(long),0) == -1) //Sending the message
errore(__LINE__);
if(msgctl(myMsgQueue,IPC_RMID,0) == -1) //Deleting the message queue
errore(__LINE__);
}
The function errore simply prints out a string which explains the error using strerror(errno).
However, the code does not seem to work: errore prints "Permission denied" as msgsnd returns -1.
I cannot figure out what is the problem: I am initializing the message queue and an adequate message structure, then creating a message of a type corresponding to the process' pid and of a text corresponding to "Hey there", then sending the message.
What am I missing?
Read the man page man page
A message queue identifier exists for the argument key, but operation
permission as specified by the low-order 9 bits of msgflg would not be
granted;
I created a message queue with following code. First few times it works properly.
int main()
{
mqd_t mqdes;
char mq_name[10] = "/mq";
int oflag = O_CREAT | O_RDWR, ret;
struct mq_attr attr;
attr.mq_maxmsg = 1024;
attr.mq_msgsize = 2048;
mqdes = mq_open(mq_name, oflag, 0766, &attr);
if(mqdes == -1) {
perror("mq_open");
if(errno == EMFILE)
perror("EMFILE");
exit(1);
}
printf("mqueue created, mq_descriptor: %d\n", mqdes);
ret = mq_close(mqdes);
if(ret == -1) {
perror("mq_close");
exit(2);
}
printf(" mq closed successful\n");
return 0;
}
After that, it's giving following error
mq_open: Too many open files
EMFILE: Too many open files
But why i'm getting this error? How can I see possix message queues like ipcs is for system V?
Try to set the resource limits:
#include <sys/resource.h>
struct rlimit rlim;
memset(&rlim, 0, sizeof(rlim));
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
setrlimit(RLIMIT_MSGQUEUE, &rlim);
I had the same issue while trying something. If you have by accident too many open message queues left on your system, you can try deleting your mqueue's in directory /dev/mqueue. This worked for me.
Also you might want to use mq_unlink(const char *name) after the mq_close() to ensure that the queue is removed from the system as described here.
I had the same problem and I solved it by increasing RLIMIT_MSGQUEUE via setrlimit.
If the hard limit (rlim_max) is too low as well (which was the case for me), you will have to give your process the CAP_SYS_RESOURCE privilege so that you can set the hard limit before you set the process limit (rlim_cur). Either run $ setcap 'CAP_SYS_RESOURCE=+ep' /path/to/executable over an executable or edit /etc/security/capability.conf to give CAP_SYS_RESOURCE to a user/group.
I open a mesage queue in a .c file, and upon success it says the message queue id is 3. While that program is still running, in another terminal I start another program (of another .c file), that creates a new message queue with a different mqd_t. But its id also appears as 3. Is this a problem?
server file goes like this:
void server(char* req_mq) {
struct mq_attr attr;
mqd_t mqdes;
struct request* msgptr;
int n;
char *bufptr;
int buflen;
pid_t apid;
//attr.mq_maxmsg = 300;
//attr.mq_msgsize = 1024;
mqdes = mq_open(req_mq, O_RDWR | O_CREAT, 0666, NULL);
if (mqdes == -1) {
perror("can not create msg queue\n");
exit(1);
}
printf("server mq created, mq id = %d\n", (int) mqdes);
and the client goes like:
void client(char* req_mq, int min, int max, char* dir_path_name, char* outfile) {
pid_t pid;
/* get the process id */
if ((pid = getpid()) < 0) {
perror("unable to get client pid");
}
mqd_t mqd, dq;
char pfx[50] = DQ_PRFX;
char suffix[50]; //
sprintf(suffix, "%d", pid);
strcat(pfx, suffix);
dq = mq_open(pfx, O_RDWR | O_CREAT, 0666, NULL);
if (dq == -1) {
perror("can not open data queue\n");
exit(1);
}
printf("data queue created, mq id = %d\n", (int) dq);
mqd = mq_open(req_mq, O_RDWR);
if (mqd == -1) {
perror("can not open msg queue\n");
exit(1);
}
mqdes and dq seem to share the same id 3.
Think of a handle as an array index. An index into an array held by the operating system, one for every process in the system.
When you open a handle (be it for a file, message queue, socket, etc) the operating system records the settings for that object in an array that is unique for your process. The operating system then returns an index into that array to your program.
Every time your program uses that "handle" the operating system is really just looking up a structure in that private array it keeps to find out how to deal with the object related to that "handle".
Linux typically reserves handles 0, 1 and 2 for STDIN, STDOUT, and STDERR respectively. But from then on any handles you open will be numbered 3, 4, and so forth. And your handle 3 might relate to file "/tmp/foo.txt" while another process's handle 3 might relate to file "/tmp/bar.txt". So if two processes are using similar file "handles" it is irrelevant.
By the way, you shouldn't need to know, or care, about what a handle actually contains. In theory it could be anything - a magic number, a pointer, an integer, it doesn't matter. The handle is really a secret token that you just hand to the operating system any time you want access to your system object.
maybe you didn't close the first message queue. because in that situation os gives the same id (index) to the new one.
Message queues are distinguished by the name you give them when you open a message queue using mq_open(3). Message queue descriptors returned by mq_open(3) are only meaningful within a process scope. Put in other words, what another process have as value for message queue descriptor is totally irrelevant to another process. This is completely analogous to file paths and file descriptors. Indeed, Linux is special in the sense that the message queue descriptors are actually file descriptors - see Linux manual page mq_overview(7). This is the explanation for the common value 3 that you see two processes get when opening message queue (in the most typical case 0, 1, 2 having been already opened for the purpose of providing STDIN, STDOUT, and STDERR like PP. already mentions in his answer).