how to detect eventfd file descriptor close by other program - c++

I have a client/server communicate through eventfd. If either client or server call close(fd) I would like the other end to find out (like file descriptor is closed now). I tried to use select with non-zero timeout, it always return 0 which is timeout. I saw people suggesting use fcntl it doesn't seems to be working either. Any suggestions?
Addtion Details (omitted non important part code, you can see here for how to exchange file descriptor detail code:
It is multi processes application. Server process created eventfd by calling
struct msghdr control_message;
int fd = eventfd(0,0);
*CMSG_DATA(control_message) = fd;
message.msg_control = &control_message;
sendmsg(socket_fd, & message,0); //send this to client
From client side:
recvmsg(socket_fd, & message,0);
//loop using CMSG_NXTHDR(&message, control_message)
int fd = *(int *) CMSG_DATA(contro_message);
Then on server side:
close(fd);
On Client side:
int rc;
rc = dup2(fd,fd);
rc is never invalid.

Checking for a closed file descriptor? How about this?
#include <errno.h>
#include <stdio.h>
#include <string.h>
static void checkit ()
{
int rc;
rc = dup2(2, 2);
if ( rc == -1 )
printf("error %d on dup2(2, 2): %s\n", errno, strerror(errno));
else
printf("dup2 successful\n");
write(2, "still working\n", 14);
}
int main (int argc, char **argv)
{
int rc;
checkit();
close(2);
checkit();
return 0;
}
Running it generates this output:
dup2 successful
still working
error 9 on dup2(2, 2): Bad file descriptor
If this is a multi-threaded application using poll and you want poll to return when the file descriptor is closed by another thread, POLLERR, POLLHUP, or POLLNVAL might help.
Multi-Threaded Version using Poll
And here's a sample that shows how to detect a closed fd with poll (POLLNVAL is the event) in a multi-threaded program:
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static void *run_poll (void *arg)
{
struct pollfd fds[1];
int rc;
fds[0].fd = 2;
fds[0].events = POLLERR | POLLHUP | POLLNVAL;
//
// Poll indefinitely
//
printf("starting poll\n");
fflush(stdout);
rc = poll((struct pollfd *) &fds, 1, -1);
if ( rc == -1 )
{
printf("POLL returned error %d: %s\n", errno, strerror(errno));
}
else
{
printf("POLL returned %d (revents = 0x%08x): %s %s %s\n",
rc,
fds[0].revents,
( ( fds[0].revents & POLLERR ) ? "pollerr" : "noerr" ),
( ( fds[0].revents & POLLHUP ) ? "pollhup" : "nohup" ),
( ( fds[0].revents & POLLNVAL ) ? "pollnval" : "nonval" ));
}
return NULL;
}
int main (int argc, char **argv)
{
pthread_t thread;
int rc;
rc = pthread_create(&thread, NULL, run_poll, NULL);
usleep(100);
printf("closing stderr\n");
close(2);
usleep(100);
return 0;
}
This generates the output
starting poll
closing stderr
POLL returned 1 (revents = 0x00000020): noerr nohup pollnval

Related

Non blocking select for inotify

I try to use inotify in c++ inside a thread
but the select is blocking, so I can never get outside the thread when my application exits
how I create the inotify watch
fd=inotify_init1(IN_NONBLOCK);
// checking for error
if ( fd < 0 )
log->Print("Could not init files listener");
else
{
// use select watch list for non-blocking inotify read
FD_ZERO( &watch_set );
FD_SET( fd, &watch_set );
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
// watch directory for any activity and report it back to me
int wd=inotify_add_watch(fd,folder.c_str(),IN_ALL_EVENTS);
// add wd and directory name to Watch map
watch.insert( -1, folder, wd );
// start listening thread
run(FilesListener::threadBootstrap);
}
here is the function called in my thread loop
void FilesListener::refresh()
{
char buffer[1024];
// select waits until inotify has 1 or more events.
// select needs the highest fd (+1) as the first parameter.
select( fd+1, &watch_set, NULL, NULL, NULL );
// Read event(s) from non-blocking inotify fd (non-blocking specified in inotify_init1 above).
int length = read( fd, buffer, EVENT_BUF_LEN );
if ( length < 0 )
log->Print("Could not read inotify file descriptor");
else
{
....
Check https://github.com/paulorb/FileMonitor it has an easy interface for achieving what you want. It is a port of windows API to Linux using inotify.
Example:
#include "FileMonitor.hpp"
int main(void)
{
int m_EventID = FindFirstChangeNotification("/media/sf_P_DRIVE/FileMonitor/", 0, FILE_NOTIFY_CHANGE_FILE_NAME);
int ret = WaitForSingleObject(m_EventID, 10000);
printf("\nFinish %d", ret);
fflush(stdout);
FindNextChangeNotification(m_EventID);
int ret2 = WaitForSingleObject(m_EventID, 10000);
printf("\nFinish %d", ret2);
FindCloseChangeNotification(1);
printf("\nChangeNotification done");
fflush(stdout);
return 0;
}
If you prefer to do it yourself try to use the poll function, you can use it inside of a thread.
struct pollfd pfd = { th_params->fd, POLLIN, 0 };
int ret = poll(&pfd, 1, 50); // timeout of 50ms
if (ret < 0) {
printf("\failed poll");
}
else if (ret == 0) {
// Timeout with no events, move on.
printf("\nTimeout poll");
}
else {
i = 0;
int lenght = read(th_params->fd, buffer, 1024);
}
void FilesListener::refresh()
{
char buffer[1024];
int length = read( fd, buffer, EVENT_BUF_LEN );
if ( length >=0 )
{
....

Not able to catch SIGINT signal while using select()

I'm trying to handle signals while listen socket in syscall select.
Problem: I have the working loop with select call. select waits for socket descriptor is ready.
There is need to break loop by SIGINT or SIGQUIT and correct close resources and exit the programm.
Below code is
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <error.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
bool bBreakJob = false;
void sig_handler(int sig)
{
switch(sig)
{
case SIGHUP:
//rneed to reload config
break;
case SIGINT:
printf("SIGINT \n");
bBreakJob = true;
openlog("mydaemon", LOG_PID | LOG_CONS, LOG_DAEMON);
syslog(LOG_INFO, "Catched SIGINT");
closelog();
break;
case SIGQUIT:
printf("SIGQUIT \n");
openlog("mydaemon", LOG_PID | LOG_CONS, LOG_DAEMON);
syslog(LOG_INFO, "Catched SIGQUIT");
bBreakJob = true;
break;
case SIGPIPE:
printf("SIGPIPE \n");
break;
}
}
int main(int argc, char** argv)
{
struct sigaction act, oact;
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGPIPE);
sigaddset(&set, SIGQUIT);
sigprocmask(SIG_UNBLOCK, &set, NULL);
act.sa_mask = set;
act.sa_handler = sig_handler;
act.sa_flags = 0;
sigaction(SIGINT, &act, NULL);
sigaction(SIGHUP, &act, NULL);
sigaction(SIGPIPE, &act, NULL);
sigaction(SIGQUIT, &act, NULL);
int fds[0], res, fmax;
fd_set wset;
fd_set rset;
//next line code to open socket
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
int iFlags = fcntl(listen_socket, F_GETFL);
iFlags |= O_NONBLOCK;
fcntl(listen_socket, F_SETFL, iFlags);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(4000);
bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin));
listen(listen_socket, 20);
fds[0] = listen_socket;
FD_ZERO(&wset);
FD_SET(fds[0], &wset);
fmax = fds[0] + 1;
while (FD_ISSET(fds[0], &wset))
{
rset = wset;
res = select(fmax, &rset, NULL, NULL, NULL);
if (res < 0)
{
if (errno == EINTR)
{ //debug message
printf("Loop broken by select's result EINTR");
break;
} else
{
printf("select(...) fails in listed loop. errno %d (%s)", errno, strerror(errno));
exit(1);
}
}
else if (res == 0)
{
//if timeout is handled
}
else if (res > 0)
{
if (FD_ISSET(fds[0], &rset))
{
//Handle socket input
}
}
if(bBreakJob)
{
printf("Loop broken by signal handler");
break;
}
} //while( 1 );
FD_CLR(fds[0], &wset);
if(bBreakJob)
{ //debug message
printf("signal SIGINT is handled ");
}
}
SIGINT never reaches the sig_handler. In IDE QtCreator I've tried to debug. select just interrupted and then return to listen. The condition "if (errno == EINTR)" is not reached even. Ther is no debug messages either in console either no in syslog. And in the same time SIGQUIT works fine: sig_handler is called and the condition "if (errno == EINTR)" is reached too.
As you can see, I've tried to check SIGINT in to ways: with flag from signal handler, and from result of select
I've tried to found answer in topic Not able to catch SIGINT signal while using select(). But cannot found the solution. This problem I meet in other WEB-resources, but there is no solution too.
SIGINT signal is sened from command line: "kill -s 2 (PID)"
UPD Problem has solved. The issue was in debugger. Under debugger SIGINT does not working properly. Running the programm without debugger working fine as expected.
The interaction of select and signals is tricky, because the signal could always arrive right before you call select. Here are two ways to wake up a select loop from a signal handler:
The "self-pipe trick": Create a pipe and add the read end to your select read set. From your signal handler, write one byte to the write end of this pipe, and it will make the select return immediately (because input is ready).
Rather than pass NULL as the final argument to select, pass a pointer to a timeval that is a global variable. Within your signal handler, make the timeval 0 seconds. Hence, if a signal arrives before you call select, select will ask for a 0 timeout and return immediately.

Creating a Bluetooth Server with C++ on Windows

I'm trying to create a Bluetooth Server to run on Windows in my computer. I have been reading information in several pages and following some tutorials, but I'm getting an error creating the Bluetooth sockect.
This is the code I have at the moment.
#include "stdafx.h"
#include <WinSock2.h>
#include <ws2bth.h>
#include <bthsdpdef.h>
#include <BluetoothAPIs.h>
#pragma comment(lib, "Ws2_32.lib")
#include <new>
using namespace std;
//Some defines
#define CXN_SUCCESS 0
#define CXN_ERROR 1
void PrintError(char* ProblemMessage, int ErrorCode);
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
printf("Ha habido un error con wsaData\n");
}
ULONG ulRetCode = CXN_SUCCESS;
LPCSADDR_INFO lpCSAddrInfo = NULL;
TCHAR szThisComputerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwLenComputerName = MAX_COMPUTERNAME_LENGTH + 1;
SOCKET s;
lpCSAddrInfo = (LPCSADDR_INFO) HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(CSADDR_INFO) );
if ( NULL == lpCSAddrInfo ) {
wprintf(L"!ERROR! | Unable to allocate memory for CSADDR_INFO\n");
ulRetCode = CXN_ERROR;
}
if ( CXN_SUCCESS == ulRetCode ) {
if ( !GetComputerName(szThisComputerName, &dwLenComputerName) ) {
wprintf(L"=CRITICAL= | GetComputerName() call failed. WSAGetLastError=[%d]\n", WSAGetLastError());
ulRetCode = CXN_ERROR;
}
}
//
// Open a bluetooth socket using RFCOMM protocol
//
if ( CXN_SUCCESS == ulRetCode ) {
//(AF_INET, SOCK_STREAM, IPPROTO_TCP);
s = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
if (s == INVALID_SOCKET)
{
PrintError("Problem found creating the socket \n",GetLastError());
printf("Error code: %d\n",GetLastError());
exit(1);
}
}
closesocket(s);
WSACleanup();
}
void PrintError(char* ProblemMessage, int ErrorCode)
{
const char* ConnectionString = ": ";
char* CompleteMessage;
LPVOID ReasonMessage;
DWORD ReasonMessageSize;
ReasonMessageSize = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &ReasonMessage, 0, NULL);
CompleteMessage = new(nothrow) char[lstrlen(ProblemMessage) + lstrlen(ConnectionString) + ReasonMessageSize + 1];
if(!CompleteMessage)
return;
lstrcpy(CompleteMessage, ProblemMessage);
lstrcat(CompleteMessage, ConnectionString);
lstrcat(CompleteMessage, (char*)ReasonMessage);
LocalFree(ReasonMessage);
fprintf(stderr, CompleteMessage);
delete[] CompleteMessage;
}
When I lauch this code, I get the error code 10047: Address family not supported by protocol family. In the line:
s = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
What am I doing wrong? I filled the fields like it's said here:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa362910%28v=vs.85%29.aspx
And the rest of the code is based on the sample given in:
http://code.msdn.microsoft.com/windowsdesktop/Bluetooth-Connection-e3263296
Some other information that may be relevant, I'm using:
Windows 7
Microsoft Visual Studio 2010
My computer do accept Bluetooth, actually I connect it to a wireless
printer oftenly
Can anyone tell me what am I missing or what am I doing wrong?
Thanks

Serial Comm using WriteFile/ReadFile

//#include "StdAfx.h"
#include <stdio.h>
#include <windows.h>
#include <winbase.h>
#include <iostream>
#include <tchar.h>
using namespace std;
int main()
{
int com = 'COM2';
string data = "\n 010400 \n";
char output[32];
//unsigned int length = 0;
DCB config = {0};
bool abContinue = true;
DWORD dwBytesWritten;
DWORD dwBytesRead;
int isRead = false;
HANDLE m_hCommPort = ::CreateFile(L"COM2",
GENERIC_READ|GENERIC_WRITE,//access ( read and write)
0, //(share) 0:cannot share the COM port
0, //security (None)
OPEN_EXISTING,// creation : open_existing
0, // we dont want overlapped operation
0// no templates file for COM port...
);
config.DCBlength = sizeof(config);
if((GetCommState(m_hCommPort, &config) == 0))
{
printf("Get configuration port has a problem.");
return FALSE;
}
config.BaudRate = 9600;
config.StopBits = ONESTOPBIT;
config.Parity = PARITY_NONE;
config.ByteSize = DATABITS_8;
config.fDtrControl = 0;
config.fRtsControl = 0;
if (!SetCommState(m_hCommPort, &config))
{
printf( "Failed to Set Comm State Reason: %d\n",GetLastError());
//return E_FAIL;
}
printf("Current Settings\n Baud Rate %d\n Parity %d\n Byte Size %d\n Stop Bits %d", config.BaudRate,
config.Parity, config.ByteSize, config.StopBits);
int isWritten = WriteFile(m_hCommPort, &data,(DWORD) sizeof(data), &dwBytesWritten, NULL);
//memset(output, 0, sizeof(output));
while (abContinue)
{
isRead = ReadFile(m_hCommPort, output, sizeof(output), &dwBytesRead, NULL);
if(!isRead)
{
abContinue = false;
break;
}
}
cin.get();
}
I am having trouble reading from the com port. If I step through the code, it goes into "isRead = ReadFile(m_hCommPort, output, sizeof(output), &dwBytesRead, NULL);" and doesn't come back out.... This is my first try at this with no success.
You might try some code something like this after you've opened the file, but before you try to use it:
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(m_hCommPort, &timeouts))
// setting timeouts failed.
Edit: perhaps it's easier to start with some code that works, and make it do what you want rather than trying to get your code to work. Here's a simple terminal program. It's minimalist in the extreme, but does work (at least well enough to let me see output from my GPS, for one example). It's a long ways from what anybody (least of all me) would call sophisticated, but should give at least some idea of how to get started.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
void system_error(char *name) {
// Retrieve, format, and print out a message from the last error. The
// `name' that's passed should be in the form of a present tense noun
// (phrase) such as "opening file".
//
char *ptr = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
GetLastError(),
0,
(char *)&ptr,
1024,
NULL);
fprintf(stderr, "\nError %s: %s\n", name, ptr);
LocalFree(ptr);
}
int main(int argc, char **argv) {
int ch;
char buffer[1];
HANDLE file;
COMMTIMEOUTS timeouts;
DWORD read, written;
DCB port;
HANDLE keyboard = GetStdHandle(STD_INPUT_HANDLE);
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode;
char port_name[128] = "\\\\.\\COM3";
char init[] = ""; // e.g., "ATZ" to completely reset a modem.
if ( argc > 2 )
sprintf(port_name, "\\\\.\\COM%c", argv[1][0]);
// open the comm port.
file = CreateFile(port_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if ( INVALID_HANDLE_VALUE == file) {
system_error("opening file");
return 1;
}
// get the current DCB, and adjust a few bits to our liking.
memset(&port, 0, sizeof(port));
port.DCBlength = sizeof(port);
if ( !GetCommState(file, &port))
system_error("getting comm state");
if (!BuildCommDCB("baud=19200 parity=n data=8 stop=1", &port))
system_error("building comm DCB");
if (!SetCommState(file, &port))
system_error("adjusting port settings");
// set short timeouts on the comm port.
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(file, &timeouts))
system_error("setting port time-outs.");
// set keyboard to raw reading.
if (!GetConsoleMode(keyboard, &mode))
system_error("getting keyboard mode");
mode &= ~ ENABLE_PROCESSED_INPUT;
if (!SetConsoleMode(keyboard, mode))
system_error("setting keyboard mode");
if (!EscapeCommFunction(file, CLRDTR))
system_error("clearing DTR");
Sleep(200);
if (!EscapeCommFunction(file, SETDTR))
system_error("setting DTR");
if ( !WriteFile(file, init, sizeof(init), &written, NULL))
system_error("writing data to port");
if (written != sizeof(init))
system_error("not all data written to port");
// basic terminal loop:
do {
// check for data on port and display it on screen.
ReadFile(file, buffer, sizeof(buffer), &read, NULL);
if ( read )
WriteFile(screen, buffer, read, &written, NULL);
// check for keypress, and write any out the port.
if ( kbhit() ) {
ch = getch();
WriteFile(file, &ch, 1, &written, NULL);
}
// until user hits ctrl-backspace.
} while ( ch != 127);
// close up and go home.
CloseHandle(keyboard);
CloseHandle(file);
return 0;
}
If you do not explicitly set the timeouts, then ReadFile will indefinitely block until data becomes available.
ReadFile function may be blocking your thread,if so, it will remain blocked until some data can be read from Serial port. Here is a link see if its help. Good luck.
I had this problem on a readfile, with the timeouts set. This was driving me crackers so I ended up getting some code from the web which did work and then changing line by line to see where the error was.
Turns out he readfile was fine. My problem was a WaitCommEvent which was hanging when the port was disconnected as no com event is ever received...

a problem in socks.h

i use this (http://www.codeproject.com/KB/IP/Socks.aspx) lib in my socket programing in c++
and copy the socks.h in include folder and write this code:
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>
#include "socks.h"
#define PORT 1001 // the port client will be connecting to
#define MAXDATASIZE 100
static void ReadThread(void* lp);
int socketId;
int main(int argc, char* argv[])
{
const char temp[]="GET / HTTP/1.0\r\n\r\n";
CSocks cs;
cs.SetVersion(SOCKS_VER4);
cs.SetSocksPort(1080);
cs.SetDestinationPort(1001);
cs.SetDestinationAddress("192.168.11.97");
cs.SetSocksAddress("192.168.11.97");
//cs.SetVersion(SOCKS_VER5);
//cs.SetSocksAddress("128.0.21.200");
socketId = cs.Connect();
// if failed
if (cs.m_IsError)
{
printf( "\n%s", cs.GetLastErrorMessage());
getch();
return 0;
}
// send packet for requesting to a server
if(socketId > 0)
{
send(socketId, temp, strlen(temp), 0);
HANDLE ReadThreadID; // handle for read thread id
HANDLE handle; // handle for thread handle
handle = CreateThread ((LPSECURITY_ATTRIBUTES)NULL, // No security attributes.
(DWORD)0, // Use same stack size.
(LPTHREAD_START_ROUTINE)ReadThread, // Thread procedure.
(LPVOID)(void*)NULL, // Parameter to pass.
(DWORD)0, // Run immediately.
(LPDWORD)&ReadThreadID);
WaitForSingleObject(handle, INFINITE);
}
else
{
printf("\nSocks Server / Destination Server not started..");
}
closesocket(socketId);
getch();
return 0;
}
// Thread Proc for reading from server socket.
static void ReadThread(void* lp)
{
int numbytes;
char buf[MAXDATASIZE];
while(1)
{
if ((numbytes=recv(socketId, buf, MAXDATASIZE-1, 0)) == -1)
{
printf("\nServer / Socks Server has been closed Receive thread Closed\0");
break;
}
if (numbytes == 0) break;
buf[numbytes] = '\0';
printf("Received: %s\r\n",buf);
send(socketId,buf,strlen(buf),0);
}
}
but when compile this i get an error .
pls help me
thanks
To use sockets you need to link your executable with Ws2_32.lib. It will fix the link error that you have mentioned in comments.
According to the MSDN documentation for closesocket, you need to link to Ws2_32.lib.