Posix messages Bad adress at mq_open - c

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

Related

mq_receive returns "Message too long" even though msg_len is greater than mq_msgsize

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.

msgsnd no permission error

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.

mq_open giving "too many open files"

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.

Message Passing In C/Printing a char array from a struct in C

I created this program to pass a message to a parent process. I want the parent process to print out the message it receives. I'm not sure if this is an issue with reading the char array or message passing as I am quite new to programming in c. Here is my attempt:
struct msg {
long int mtype; /* message type */
char mtext[1028]; /* message text */
} msg;
int pid, len;
int msgflg = 0;
int msqid;
char *mymsg[1028];
size_t msgsz;
long int msgtyp;
switch(pid=fork()) //fork child process
{//Child process
case 0:
mymsg[1] = "serving for sender\n";
len = strlen(mymsg[1]);
msgsnd(msqid,mymsg[1],len,msgflg);
break;
case -1:
printf("fork failed");
exit(-1);
break;
default:
msg.mtype = 0;
msqid = msgget(IPC_PRIVATE,msgflg);
wait((int *) 0);
msgrcv(msqid,&msg,msgsz,msgtyp,IPC_NOWAIT);
printf("%s",msg.mtext);
msgctl(msqid, IPC_RMID, NULL);
exit(0);
}
My question is, why is the message serving for sending not being displayed when this code is compiled and executed?
You haven't really asked a question, but a couple of issues I can see with the code are:
char *mymsg[1028];
...
mymsg[1] = "serving for sender\n";
Here you have mymsg which is an array of 1028 pointers to char, which is intended to be treated as a string. (By the way, why 1028? Not that it matters, but just so you know 2^10 is 1024). However, this array contains pointers that are not initialized and are pointing to random locations. Important thing is, there is no space allocated for the possible message you want to put in them.
Second issue is that arrays in C start with index 0, so you probably meant to write
mymsg[0] = "serving for sender\n";
That doesn't matter however.
More importantly, you can't copy strings in C using =, you should use strcpy and copy to a memory location that you have already allocated. Here are two ways to do it:
char mymsg[1028][1028]; // if you are sure your messages fit in 1028 chars
...
mymsg[1] = malloc(strlen("serving for sender)*sizeof(char)); // sizeof(char) not really needed
strcpy(mymsg[1], "serving for sender\n");
msgsnd(msqid,mymsg[1],len,msgflg);
free(mymsg[1]);
or
char *mymsg[1028];
...
char str_to_be_printed[] = "serving for sender\n";
mymsg[1] = malloc(strlen(str_to_be_printed)*sizeof(char)); // sizeof(char) not really needed
strcpy(mymsg[1], str_to_be_printed);
msgsnd(msqid,mymsg[1],len,msgflg);
free(mymsg[1]);
Edit: In the second case where you already have the string somewhere (and not in the form of "this is a string"), assigning the pointers is enough and you don't to copy or allocate memory. However, if your situation is more complex than this, and between assignment of mymsg[1] = ... and msgsnd there are other code, you have to make sure the original string stays alive until msgsnd is done. Otherwise, you have a dangling pointer which will cause you problems. Here's the idea:
+-+-+-+-+-+-+-+-+--+
str_to_be_printed ----->|A| |s|t|r|i|n|g|\0|
+-+-+-+-+-+-+-+-+--+
^
mymsg[1]---------------/
If you free the memory of str_to_be_printed, access to mymsg[1] would cause segmentation fault/access violation.
Note that, the code I wrote is just to give you a guideline, don't copy-paste it.
There are few observation related to your code.
When you use system calls (any function which returns any error code) check the return value of the function. In the case of system calls you have used will set errno i.e. error number which can be used to check for error. You can use perror or strerror to see the message (Pointed out by Jonathan Leffler already)
You need to create message queue before using it (Again pointed out by Jonathan Leffler already).
You are sending char * in msgsnd & receiving struct msg type in msgrcv.
You have set the size to be passed in the message queue send & receive calls, for which you are using msgsz but uninitialized. Set value of msgsz to the size you want to send/receive. While sending you seem to sending 17 bytes but while receiving it is not set.
mtype should have a value greater than 0.
Type for pid should be pid_t, which seems do you little good in this case anyway.
Some code sections for your reference:
#include <stdio.h> /*For perror*/
...
/* Create message queue */
msqid = msgget(IPC_PRIVATE, IPC_CREAT);
if( 0 > msqid )
{
perror("msgget");
/* Handle error as per your requirement */
}
...
/* Sending & receiving messages */
...
struct msg {
long int mtype; /* message type */
char mtext[1028]; /* message text */
} sender_msg, receiver_msg;
...
size_t msgsz = 10; /* Send & receive 10 bytes, this can vary as per need. You can receive less than what was sent */
...
switch(fork())
{
case 0: /* Child */
sender_msg.mtype = 1;
strncpy(sender_msg.mtext,"01234567890123", 1027);
/* Sending the whole text size */
if ( 0 > msgsnd(msqid, &sender_msg, strlen(sender_msg.mtext),msgflg))
{
perror("msgsnd");
/* Handle error as per your requirement */
}
break;
case -1:
perror("fork");
exit(-1);
break;
default:
wait((int *) 0);
receiver_msg.mtype = 1;
/* Receive only 10 bytes as set in msgsz */
if( 0 > msgrcv(msqid,&receiver_msg,msgsz,msgtyp,IPC_NOWAIT))
{
perror("msgrcv");
/* Error handling */
}
printf("%s",receiver_msg.mtext);
if (0 > msgctl(msqid, IPC_RMID, NULL))
{
perror("msgctl");
/* Handle error as per your requirement */
}
break;
}
You seem to be using System V message queues APIs here, you can look into the POSIX message queue APIs like mq_open, mq_close, mq_send, mq_receive etc.
For message queue overview see the man pages (man mq_overview)
Use man pages for information about APIs as well.
Hope this helps!
You have several problems:
You need to create the message queue before you call fork(), so that both the parent and child have access to it;
The permissions of the message queue are set from the low-order bits of the second parameter of msgget(), so you need to specify at least read and write permissions for the owner of the message queue. You can use the constant S_IRWXU from <sys/stat.h> here;
You are passing msgsnd() a pointer to a string, but it actually wants a pointer to a message struct like your struct msg.
You should check for msgrcv() failing.
With these issues fixed, the corrected code looks like:
int pid;
int msqid;
msqid = msgget(IPC_PRIVATE, S_IRWXU);
if (msgid < 0) {
perror("msgget");
exit(1);
}
switch(pid=fork()) //fork child process
{//Child process
case 0:
msg.mtype = 1; /* Must be a positive value */
strcpy(msg.mtext, "serving for sender\n");
msgsnd(msqid, &msg, strlen(msg.mtext) + 1, 0);
break;
case -1:
printf("fork failed");
exit(2);
break;
default:
wait(NULL);
if (msgrcv(msqid, &msg, sizeof msg.mtext, 0, IPC_NOWAIT) >= 0)
printf("%s",msg.mtext);
else
perror("msgrcv");
msgctl(msqid, IPC_RMID, NULL);
exit(0);

Different Linux message queues have the same id?

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

Resources