I am writing a code send the output of a terminal command over a socket in C. I have tried using select for asynchronous reading and avoid blocking the event-loop, but I wasn't successful.
How can I change this code to make the file stream IO non-blocking?
int maxfdpl;
fd_set rset;
char sendline[100], recvline[100], my_msg[100];
FILE *in;
char str[30]="ping 192.168.26.219";
if(!(in = popen(str, "r"))){
return EXIT_FAILURE;
}
FD_ZERO(&rset);
FD_SET(fileno(in), &rset);
maxfdpl =fileno(in) + 1;
select(maxfdpl, &rset, NULL, NULL, NULL);
while(1) {
if (FD_ISSET(fileno(in), &rset)) {
if (fgets(sendline, 100, in)) {
send_over_socket(sendline);
}
}
}
How can I remove the while loop (which is blocking the event-loop) and replace the code with a non-blocking IO operation?
int blockFD(int fd, int blocking)
{
/* Save the current flags */
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1)
return 0;
if (blocking)
flags &= ~O_NONBLOCK;
else
flags |= O_NONBLOCK;
return fcntl(fd, F_SETFL, flags) != -1;
}
Returns 0 if failed.
Related
I am writing to a pipe, and getting a
"Buffer overflow? : Resource temporarily unavailable" error.
I would like to differentiate between a buffer overflow error, and other pipe related errors.
Here is the code I use for writing to the pipe:
void forward_data_asynch(int source_sock, int destination_sock) {
char buffer[BUF_SIZE];
int n;
//put in error condition for -1, currently the socket is shutdown
while ((n = recv(source_sock, buffer, BUF_SIZE, 0)) > 0)// read data from input socket
{
send(destination_sock, buffer, n, 0); // send data to output socket
if( write(pfds[1],buffer,n) < 0 )//send data to pipe
perror("Buffer overflow? ");
}
shutdown(destination_sock, SHUT_RDWR);
close(destination_sock);
shutdown(source_sock, SHUT_RDWR);
close(source_sock);
}
The pipe has been set as non-blocking:
/** Make file descriptor non blocking */
int setNonblocking(int fd)
{
int flags;
/* If they have O_NONBLOCK, use the Posix way to do it */
#if defined(O_NONBLOCK)
/* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
flags = 0;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#else
/* Otherwise, use the old way of doing it */
flags = 1;
return ioctl(fd, FIOBIO, &flags);
#endif
}
I'm trying to catch an interrupt on GPIO through sysfs using poll(). I have -1 in the third position so it can block, but it seems to be always returning. I've checked out some similar posts on SO. Notably this (1), this (2), and this (3).
In (1), it was solved by placing a dummy read() before calling poll(). If I do this (see commented read() in code). My code runs through the loop once and blocks forever on poll() the second time around.
In (2), this might be an explanation, yet doesn't really provide a solution to my problem.
In (3), I already have an lseek() before my read()
How can I get this poll() to block and only return as in interrupt when the the gpio's value has changed?
Here's the code snippet:
int read_gpio(char *path, void (*callback)(int)){
int fd;
char buf[11];
int res = 0;
char c;
int off;
struct pollfd gpio_poll_fd = {
.fd = fd,
.events = POLLPRI,
.revents = 0
};
for(;;){
gpio_poll_fd.fd = open(path, O_RDONLY);
if(fd == -1){
perror("error opening file");
return -1;
}
// char c;
// read(fd,&c,1);
LOGD("for begins");
res = poll(&gpio_poll_fd,1,-1);
LOGD("polling ended");
if(res == -1){
perror("error polling");
break;
}
if((gpio_poll_fd.revents & POLLPRI) == POLLPRI){
LOGD("POLLPRI");
off = lseek(fd, 0, SEEK_SET);
if(off == -1) break;
memset(&buf[0], 0, 11);
size_t num = read(fd, &buf[0], 10*sizeof(char));
LOGD("Before callback");
callback(atoi(buf));
LOGD("After Callback");
}
if((gpio_poll_fd.revents & POLLERR) == POLLERR) {
//seems always to be true ..
//LOGD("POLLERR");
}
close(fd);
LOGD("for ends");
}
LOGD("for exits");
return 0;
}
Note: As I'm doing this on Android JNI, I've been getting info for debugging from LOGD()
Update:
Following the advice in jxh's comment I've arranged the structure like so, although now it blocks on poll() indefinitely. When the content of value is changed from the externally applied voltage, POLLPRI doesn't go high, and poll() doesn't return:
int read_gpio(char *path, void (*callback)(int)){
int fd = open(path, O_RDONLY);
if(fd == -1){
perror("error opening file");
return -1;
}
char buf[11];
int res, off;
char c;
struct pollfd pfd = {
.fd = fd,
.events = POLLPRI,
.revents = 0
};
for(;;){
LOGD("for begins");
// dummy read causes poll never to run
// lseek() alone here cause poll never to run
// read(fd, &buf[],1);
// lseek(fd, 0, SEEK_SET);
res = poll(&pfd,1,-1);
LOGD("polling ended");
if(res == -1){
perror("error polling");
break;
}
if((pfd.revents & POLLPRI) == POLLPRI){
LOGD("POLLPRI");
off = lseek(fd, 0, SEEK_SET);
if(off == -1) break;
memset(&buf[0], 0, 11);
read(fd, &buf[0], 10*sizeof(char));
// These two lines will cause it to poll constantly
// close(fd);
// fd = open(path, O_RDONLY);
LOGD("Before callback");
callback(atoi(buf));
LOGD("After Callback");
}
LOGD("for ends");
}
close(fd);
LOGD("for exits");
return 0;
}
In your code, fd is not initialized.
When you open the file, you assign to gpio_poll_fd.fd directly, without using fd, so fd remains uninitialized.
Try:
gpio_poll_fd.fd = fd = open(path, O_RDONLY);
As pointed out in comments, according to the GPIO manual (which I had not read until after going through these comments more carefully), the GPIO sysfs interface is a little special:
If the pin can be configured as interrupt-generating interrupt
and if it has been configured to generate interrupts (see the
description of "edge"), you can poll(2) on that file and
poll(2) will return whenever the interrupt was triggered. If
you use poll(2), set the events POLLPRI and POLLERR. If you
use select(2), set the file descriptor in exceptfds. After
poll(2) returns, either lseek(2) to the beginning of the sysfs
file and read the new value or close the file and re-open it
to read the value.
So, although it is not the typical poll() idiom, your construct of closing and re-opening is correct. However, I would choose to leave the file descriptor open. So, here is how I would structure your code:
int read_gpio(char *path, void (*callback)(int)){
char buf[11];
int fd, res, off;
struct pollfd pfd;
if((pfd.fd = fd = open(path, O_RDONLY)) == -1){
perror("path");
return -1;
}
LOGD("First read");
res = read(fd, buf, 10);
assert(res == 10);
LOGD("Before callback");
callback(atoi(buf));
LOGD("After Callback");
pfd.events = POLLPRI|POLLERR; // poll(2) says setting POLLERR is
// unnecessary, but GPIO may be
// special.
for(;;){
LOGD("for begins");
if((res = poll(&pfd,1,-1)) == -1){
perror("poll");
break;
}
LOGD("polling ended");
if((pfd.revents & POLLPRI) == POLLPRI){
LOGD("POLLPRI");
off = lseek(fd, 0, SEEK_SET);
if(off == -1) break;
memset(buf, 0, 11);
res = read(fd, buf, 10);
assert(res == 10);
LOGD("Before callback");
callback(atoi(buf));
LOGD("After Callback");
} else {
// POLLERR, POLLHUP, or POLLNVAL
break;
}
LOGD("for ends");
}
close(fd);
LOGD("for exits");
return 0;
}
In TASK I:
...
while (1)
{
if (running == false)
break;
ret = read(fd, buf, size); /* Or: ret = recvfrom(sock, buf, size, 0, NULL, NULL); */
...
}
In task II:
...
running = true;
/* ioctl(fd, FIOCANCEL, 0); */
close(fd); /* Or: close(sock);*/
what should do in task II to cancel the blocked task I,
In vxworks, there is a function, ioctl(fd, FIOCANCEL, 0) to cancel a blocked read or write but it can not work. Probably because the driver can not support "FIOCANCEL".
how to write task II in vxworks and linux? or are there any other way to do my task?
Cancelling a read/recvfrom call is impossible on linux. You cannot write these tasks using the same API. On Linux you can use epoll and O_NONBLOCK to create the semantics of canceling a read/recvfrom.
It is impossible to do this using the same code for both linux and vxworks.
Don't use blocking IO, this is a classic case of creating a thread with no (reachable) exit condition, which I consider to be a bug. The easiest example of how you should run your thread is as follows:
volatile bool _threadRunning = true;
void taskI()
{
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
while (_threadRunning == true)
{
ret = read(fd, buf, size);
if (ret > 0)
{
// process buffer
}
else
{
// sleep for 1 millisecond or so...
}
}
close(fd);
}
void taskII()
{
_threadRunning = false;
_taskI.join();
}
I'm trying to write a server in C, with I/O non-blocking because sometimes it goes down for flood requests.
Looking around, I've notice that I/O non-blocking can solve my problem.
Reading the Beej guide, I've implemented the recvtimeout function, that set a timeout to handle data from a client.
People told me I have to use the select to avoid this problem, but I used it already in the function recvtimeout:
int Server::recvtimeout(int s, char *buf, int len, int timeout)
{
//Check if non-blocking
fcntl(s, F_SETFL, O_NONBLOCK);
int flags = fcntl(s, F_GETFD);
if ((flags & O_NONBLOCK) == O_NONBLOCK) {
fprintf(stderr, "nonblocking active");
}
else {
fprintf(stderr, "nonblocking not active");
}
//End check
fd_set fds;
int n;
struct timeval tv;
// set up the file descriptor set
FD_ZERO(&fds);
FD_SET(s, &fds);
// set up the struct timeval for the timeout
tv.tv_sec = timeout;
tv.tv_usec = 0;
// wait until timeout or data received
n = select(s+1, &fds, NULL, NULL, &tv);
if (n == 0){
return -2; // timeout!
}
if (n == -1){
return -1; // error
}
// data must be here, so do a normal recv()
return recv(s, buf, len, 0);
}
So, I've added a piece of code that show me if NONBLOCK is set or not, but never I read nonblocking active, so in my code nonblocking is not active.
How can I mod my code to enable this?
The problem is when I read a string from a client and have a code like this:
char headerstring[512];
memset(headerstring,0,512);
if(this->recvtimeout(client_fd,headerstring,sizeof(headerstring),10) < 0){
close(client_fd);
}
All works fine, but with a flooder that close the connection during the transaction, the server goes down.
I've tried try-catch and any other things...but nothing.
The normal way to set a socket to non-blocking is
int x;
x=fcntl(s,F_GETFL,0);
fcntl(s,F_SETFL,x | O_NONBLOCK);
In your code you are getting the flags using
int flags = fcntl(s, F_GETFD);
whereas you should be doing as
x=fcntl(s,F_GETFL,0);
So, non-blocking may actually be getting enabled on your socket.
There are a couple of things:
After select() call:
if(n < 0) continue;
if(FD_ISSET(s, &fds)) { //check if Socket ready for reading
FD_CLR(s, &fds); // Clear for next time
// call recv()
}
Set socket as non-blocking like this:
/* set socket as non-blocking */
int x = fcntl(s, F_GETFL, 0);
fcntl(s, F_SETFL, x | O_NONBLOCK);
I have read this regarding setting a socket to non-blocking mode.
http://www.gnu.org/software/libc/manual/html_mono/libc.html#File-Status-Flags
Here is what I did:
static void setnonblocking(int sock)
{
int opts;
opts = fcntl(sock,F_GETFL);
if (opts < 0) {
perror("fcntl(F_GETFL)");
exit(EXIT_FAILURE);
}
opts = (opts | O_NONBLOCK);
if (fcntl(sock,F_SETFL,opts) < 0) {
perror("fcntl(F_SETFL)");
exit(EXIT_FAILURE);
}
return;
}
How can I set the socket back to Blocking mode? I don't see a O_BLOCK flag?
Thank you.
Did you try clearing the O_NONBLOCK flag?
opts = opts & (~O_NONBLOCK)
Here is a more cross-platform capable solution:
bool set_blocking_mode(int socket, bool is_blocking)
{
bool ret = true;
#ifdef WIN32
/// #note windows sockets are created in blocking mode by default
// currently on windows, there is no easy way to obtain the socket's current blocking mode since WSAIsBlocking was deprecated
u_long non_blocking = is_blocking ? 0 : 1;
ret = NO_ERROR == ioctlsocket(socket, FIONBIO, &non_blocking);
#else
const int flags = fcntl(socket, F_GETFL, 0);
if ((flags & O_NONBLOCK) && !is_blocking) { info("set_blocking_mode(): socket was already in non-blocking mode"); return ret; }
if (!(flags & O_NONBLOCK) && is_blocking) { info("set_blocking_mode(): socket was already in blocking mode"); return ret; }
ret = 0 == fcntl(socket, F_SETFL, is_blocking ? flags ^ O_NONBLOCK : flags | O_NONBLOCK));
#endif
return ret;
}
Alternative way to clear the flag:
opts ^= O_NONBLOCK;
This will toggle the non-blocking flag, i.e. disable non-blocking if currently enabled.