How to clear a POSIX Message Queue? - c++

I am currently working on a program that does IPC via Posix Message Queues. I now need a function that removes every message of that queue. The problem is: My code deadlocks. Currently I am trying the following:
void clear_mq(std::string queue_name)
{
struct mq_attr mq_attrs = {0, 10, sizeof(uint8_t), 0};
mqd_t mq = ::mq_open(queue_name.c_str(), O_WRONLY | O_CREAT, 00644, &mq_attrs);
if (mq < 0)
{
std::cout << "Error opening Queue" << std::endl;
exit(-1);
}
struct mq_attr num_messages;
if (mq_getattr(mq, &num_messages) == -1)
{
std::cout << "Error!" << std::endl;
exit(-1);
}
while (num_messages.mq_curmsgs > 0)
{
uint8_t buf;
mq_receive(mq, (char *)&buf, sizeof(uint8_t), NULL);
if (mq_getattr(mq, &num_messages) == -1)
{
std::cout << "Error!" << std::endl;
exit(-1);
}
}
mq_close(mq);
}
Can anyone point out what I am doing wrong? I do not understand why the receive is blocking... At that moment when I call clear_mq noone else is in the receive block...

Could be that mq_receive() fails and you end up in a endless loop.
mq_receive() can fail for various reasons, e.g. the buffer provided must at least have the size of the mq-maxsize.
You should check the return value of mq_receive() and exit the loop if it fails.

You IMHO have no deadlock. However, the mq_receive blocks until it receives a message (man mq_receive) because the queue is not open with O_NONBLOCK parameter while mq_open.
Please also ensure you do not neglect the return value of the mq_receive in the loop.

In case someone else has the problem.
When printing the errno I get error 9 (Bad file descriptor), which makes sense cause the message queue is only opened for write but you are trying to read from it. When you open the queue with O_RDWR see mq_open it should work.
A tip for debugging use mq_timedreceive so that you can check the error.

Related

epoll_wait doesn't wake up until pressing on enter

I'm new with epoll.
My code is working fine. The epoll is storing my file-descriptor and wait until file-descriptor is "ready".
But, for some reason it will not wake up until I will press on Enter (even though data has already received to fd, and after enter I will immediately see all data that has been sent before).
After one enter it will work as expected (no enters needed and when fd is ready again it will wake up again).
Here is am essence of my code:
int nEventCountReady = 0;
epoll_event event, events[EPOLL_MAX_EVENTS];
int epoll_fd = epoll_create1(0);
if(epoll_fd == -1)
{
std::cout << "Error: Failed to create EPoll" << std::endl;
return ;
}
event.events = EPOLLIN;
event.data.fd = myfd;
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, 0, &event))
{
fprintf(stderr, "Failed to add file descriptor to epoll\n");
close(epoll_fd);
return ;
}
while(true)
{
std::cout << "Waiting for messages" << std::endl;
nEventCountReady = epoll_wait(epoll_fd, events, EPOLL_MAX_EVENTS, 30000); << Stuck until Enter will be pressed (at first while loop)
for(int i=0; i<nEventCountReady; i++)
{
msgrcv(events[i].data.fd, oIpCMessageContent, sizeof(SIPCMessageContent), 1, 0);
std::cout << oIpCMessageContent.buff << std::endl;
}
}
This
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, 0, &event))
should probably be
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, myfd, &event))
In the first line you tell epoll to monitor fd 0 which is typically the standard input. That's why it waits for it, e.g. for your Enter.
Note that your original code works only by coincidence. It just happens that when you Enter there is data in your myfd (and even if there's none msgrcv blocks). And once you pressed Enter it will wake up all the time since epoll knows that STDIN is ready but you didn't read from it.
Thanks to kamilCuk, I noticed that msgget doesn't return a file descriptor as I thought.
It returns a "System V message queue identifier".
And as freakish said before, System V message queues don't work with selectors like epoll.

socketpair() & creating new child processes after close() of worker socket

First off: this is not a Unix/Linux system. I am working on an IBM AS/400 V7R1 (C++ 98) and do not have access to fork(). Nevertheless, I do have spawnp() to start new child processes and the AS/400 supports the notion of process groups.
In my system, I have a "head" program that starts X number of children. This head calls accept() on incoming connections and immediately gives the socket away to one of the child process via sendmsg(). The children are all sitting on recvmsg(). For the head program, it goes something like this:
rc = socketpair(AF_UNIX, SOCK_DGRAM, 0, pair_sd);
if (rc != 0) {
perror("socketpair() failed");
close(listen_sd);
exit(-1);
}
server_sd = pair_sd[0];
worker_sd = pair_sd[1];
// do some other stuff, set up arguments for spawnp()...
// ...
spawn_fdmap[0] = worker_sd;
for (int i = 0; i < numOfChildren; i++) {
pid = spawnp(spawn_argv[0], 1, spawn_fdmap, &inherit, spawn_argv, spawn_envp);
if (pid < 0) {
CERR << "errno=" << errno << ", " << strerror(errno) << endl;
CERR << "command line [";
for (int x = 0; spawn_argv[x] != 0; ++x) {
cerr << spawn_argv[x] << " ";
}
cerr << ']' << endl;
close(listen_sd);
exit(-1);
}
else {
CERR << "Child worker PID = " << pid << endl;
child_pids.push_back(pid);
}
}
// Close down the worker side of the socketpair.
close(worker_sd);
I've got a reason/scheme to start additional child processes after initial program start. I plan to send the head program some signal which would cause the spawnp() call to execute again. The "close(worker_sd)" has me concerned though. Can I call spawnp() again after I've closed the worker socket? It's just a number, after all. Is it OK to keep the worker_sd open?
Can I call spawnp() again after I've closed the worker socket?
After you called close on that socket, the file descriptor is no longer valid in this process.
You probably want a separate socketpair for each child process, so that messages from different child processes do not get interleaved/corrupted.
I think calling socketpair() for every child is unnecessary, and it means having to keep track of additional sockets on the server side. What I found is that removing the close() on 'worker_sd' allows me to create as many additional child processes as I want. Closing it and creating a child process caused the new child to die when it tried to receive something from the parent. I felt this is what would happen, and it did.

'pcap_loop' is not recording packets and isn't even running

I'm trying to do some simple packet capturing with pcap, and so I've created a handle to listen through eth0. My issue is with the pcap_loop(handle, 10, myCallback, NULL); line near the end of my code. I'm trying to use pcap_loop.
The expected output is supposed to be:
eth0
Activated!
1
2
3
...
10
Done processing packets!
Current output is missing the increments:
eth0
Activated!
Done processing packets!
Currently it's just skipping right through to "Done processing packets!" and I have no idea why. Even if it doesn't go to the callback, it should still be waiting on packets as the ;count' parameter (see documentation for pcap_loop) is set to 10.
#include <iostream>
#include <pcap.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void myCallback(u_char *useless, const struct pcap_pkthdr* hdr, const u_char*packet){
static int count = 1;
std::cout <<count<<std::endl;
count ++;
}
int main(){
char errbuf[PCAP_ERRBUF_SIZE];
char * devName;
char* net;
char* mask;
const u_char*packet;
struct in_addr addr;
struct pcap_pkthdr hdr;
bpf_u_int32 netp;
bpf_u_int32 maskp;
pcap_if_t *devs;
pcap_findalldevs(&devs, errbuf);
devName = pcap_lookupdev(errbuf);
std::cout <<devName<<std::endl;
int success = pcap_lookupnet(devName, &netp, &maskp, errbuf);
if(success<0){
exit(EXIT_FAILURE);
}
pcap_freealldevs(devs);
//Create a handle
pcap_t *handle = pcap_create(devName, errbuf);
pcap_set_promisc(handle, 1);
pcap_can_set_rfmon(handle);
//Activate the handle
if(pcap_activate(handle)){
std::cout <<"Activated!"<<std::endl;
}
else{
exit(EXIT_FAILURE);
}
pcap_loop(handle, 10, myCallback, NULL);
std::cout <<"Done processing packets!"<<std::endl;
//close handle
pcap_close(handle);
}
pcap_findalldevs(&devs, errbuf);
That call isn't doing anything useful, as you're not doing anything with devs other than freeing it. (You also aren't checking whether it succeeds or fails.) You might as well remove it unless you have some need to know what all the devices on which you can capture are.
pcap_can_set_rfmon(handle);
That all isn't doing anything useful, as you're not checking its return value. If you are capturing on a Wi-Fi device, and you want to capture in monitor mode, you call pcap_set_rfmon() - not pcap_can_set_rfmon() - on the handle after creating and before activating the handle.
//Activate the handle
if(pcap_activate(handle)){
std::cout <<"Activated!"<<std::endl;
}
else{
exit(EXIT_FAILURE);
}
To quote the pcap_activate() man page:
RETURN VALUE
pcap_activate() returns 0 on success without warnings, PCAP_WARN-
ING_PROMISC_NOTSUP on success on a device that doesn't support promis-
cuous mode if promiscuous mode was requested, PCAP_WARNING on success
with any other warning, PCAP_ERROR_ACTIVATED if the handle has already
been activated, PCAP_ERROR_NO_SUCH_DEVICE if the capture source speci-
fied when the handle was created doesn't exist, PCAP_ERROR_PERM_DENIED
if the process doesn't have permission to open the capture source,
PCAP_ERROR_RFMON_NOTSUP if monitor mode was specified but the capture
source doesn't support monitor mode, PCAP_ERROR_IFACE_NOT_UP if the
capture source is not up, and PCAP_ERROR if another error occurred. If
PCAP_WARNING or PCAP_ERROR is returned, pcap_geterr() or pcap_perror()
may be called with p as an argument to fetch or display a message
describing the warning or error. If PCAP_WARNING_PROMISC_NOTSUP,
PCAP_ERROR_NO_SUCH_DEVICE, or PCAP_ERROR_PERM_DENIED is returned,
pcap_geterr() or pcap_perror() may be called with p as an argument to
fetch or display an message giving additional details about the problem
that might be useful for debugging the problem if it's unexpected.
This means that the code above is 100% wrong - if pcap_activate() returns a non-zero value, it may have failed, and if it returns 0, it succeeded.
If the return value is negative, it's an error value, and it has failed. If it's non-zero but positive, it's a warning value; it has succeeded, but, for example, it might not have turned promiscuous mode on, as the OS or device might not let promiscuous mode be set.
So what you want is, instead:
//Activate the handle
int status;
status = pcap_activate(handle);
if(status >= 0){
if(status == PCAP_WARNING){
// warning
std:cout << "Activated, with warning: " << pcap_geterror(handle) << std::endl;
}
else if (status != 0){
// warning
std:cout << "Activated, with warning: " << pcap_statustostr(status) << std::endl;
}
else{
// no warning
std::cout <<"Activated!"<<std::endl;
}
}
else{
if(status == PCAP_ERROR){
std:cout << "Failed to activate: " << pcap_geterror(handle) << std::endl;
}
else{
std:cout << "Failed to activate: " << pcap_statustostr(status) << std::endl;
}
exit(EXIT_FAILURE);
}

C++ How to exit out of a while loop recvfrom()

I'm trying to create a UDP broadcast program to check for local game servers, but I'm having some trouble with the receiving end. Since the amount of servers alive is unknown at all times, you must have a loop that only exits when you stop it. So in this bit of code here:
while(1) // start a while loop
{
if(recvfrom(sd,buff,BUFFSZ,0,(struct sockaddr *)&peer,&psz) < 0) // recvfrom() function call
{
cout << red << "Fatal: Failed to receive data" << white << endl;
return;
}
else
{
cout << green << "Found Server :: " << white;
cout << yellow << inet_ntoa(peer.sin_addr), htons(peer.sin_port);
cout << endl;
}
}
I wish to run this recvfrom() function until I press Ctrl + C. I've tried setting up handlers and such (from related questions), but they're all either too complicated for me, or it's a simple function that just exits the program as a demonstration. Here's my problem:
The program hangs on recvfrom until it receives a connection (my guess), so, there's never a chance for it to specifically wait for input. How can I set up an event that will work into this nicely?
Thanks!
In the CTRL-C handler, set a flag, and use that flag as condition in the while loop.
Oh, and if you're not on a POSIX systems where system-calls can be interrupted by signals, you might want to make the socket non-blocking and use e.g. select (with a small timeout) to poll for data.
Windows have a couple of problems with a scheme like this. The major problem is that functions calls can not be interrupted by the CTRL-C handler. Instead you have to poll if there is anything to receive in the loop, while also checking the "exit loop" flag.
It could be done something like this:
bool ExitRecvLoop = false;
BOOL CtrlHandler(DWORD type)
{
if (type == CTRL_C_EVENT)
{
ExitRecvLoop = true;
return TRUE;
}
return FALSE; // Call next handler
}
// ...
SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);
while (!ExitRecvLoop)
{
fd_set rs;
FD_ZERO(&rs);
FD_SET(sd, &rs);
timeval timeout = { 0, 1000 }; // One millisecond
if (select(sd + 1, &rs, NULL, NULL, &timeout) < 0)
{
// Handle error
}
else
{
if (FD_ISSET(sd, &rs))
{
// Data to receive, call `recvfrom`
}
}
}
You might have to make the socket non-blocking for this to work (see the ioctlsocket function for how to).
Thread off your recvFrom() loop so that your main thread can wait for user input. When user requests stop, close the fd from the main thread and the recvFrom() will return immediately with an error, so allowing your recvFrom() thread to exit.

c++ select issue

So I'm trying to build a async server... Here is a summary of what I have so far:
int sockfd;
int max;
fd_set socks;
set<int> conns;
bind();
listen(sockfd);
while(1){
FD_ZERO(&socks);
max = sockfd;
FD_SET(sockfd, &socks);
for(set<int>::iterator it=conns.begin(); it!=conns.end(); it++){
FD_SET(*it, &socks);
if(max < *it){
max = *it;
}
}
int res = select(max+1, &socks, NULL, NULL, NULL);
if(res < 0){
cerr << "ERROR with select" << endl;
break;
}else if(res){
if(FD_ISSET(sockfd, &socks)){
//new connection
int new_sockfd = accept();
conns.insert(new_sockfd);
}else{
for(set<int>::iterator it=conns.begin(); it!=conns.end(); it++){
if(FD_ISSET(*it, &socks){
char buffer[256];
read(buffer, 256, *it);
cout << buffer << endl;
close(*it);
conns.erase(*it);
}
}
}
}
}
What ends up happening is... If I connect a client-1, and then client-2. And then I try and send data using Client-2 and then Client-1... it works...
However, If I connect client-1 and then connect client-2... and then try to send data using client-1. Select() returns a -1...
Help?
Take a look into man pages for select. The important part is :
Under the following conditions, pselect() and select() shall fail and set errno to:
EBADF
One or more of the file descriptor sets specified a file descriptor that is not a valid open file descriptor.
EINTR
The function was interrupted before any of the selected events occurred and before the timeout interval expired.
If SA_RESTART has been set for the interrupting signal, it is implementation-defined whether the function restarts or returns with [EINTR].
EINVAL
An invalid timeout interval was specified.
EINVAL
The nfds argument is less than 0 or greater than FD_SETSIZE.
EINVAL
One of the specified file descriptors refers to a STREAM or multiplexer that is linked (directly or indirectly) downstream from a multiplexer.
errno should tell you what is wrong.
This is just a quess, but when you close the connection, your file descriptor becomes invalid. I guess the error from select should be EBADF
I think your code erasing from the set is suspect. once you call conns.erase(*it), your iterator is invalid (and incrementing it leads to undefined behavior).
Changing your loop to something like the following should resolve the issue:
for(set<int>::iterator it=conns.begin(); it!=conns.end();)
{
set<int>::iterator cur = it++;
if(FD_ISSET(*cur, &socks)){
char buffer[256];
read(buffer, 256, *cur);
cout << buffer << endl;
close(*cur);
conns.erase(*cur);
}
}