How to modify recv to implement IO/ non-blocking? - c

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

Related

Differentiate between buffer overflow and other errors when writing to a pipe

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
}

Non blocking read never returns

I am trying to do a non blocking read but the function never returns. Can someone suggest something? Here is my code to set nonblocking fd.
from_ap = open(FFS_GBEMU_OUT, O_RDWR|O_NONBLOCK);
if (from_ap < 0)
return from_ap;
I have also tried this with similar results
from_ap = open(FFS_GBEMU_OUT, O_RDWR);
int status = fcntl(from_ap, F_SETFL, fcntl(from_ap, F_GETFL, 0) | O_NONBLOCK);
if (status == -1){
perror("calling fcntl");
Here is where I call my read function:
rsize = read(from_ap, cport_rbuf, ES1_MSG_SIZE);
if (rsize < 0) {
printf("error %zd receiving from AP\n", rsize);
return NULL;
}
I have also tried this with similar results:
fd_set readset;
struct timeval tv;
FD_ZERO(&readset);
FD_SET(from_ap, &readset);
tv.tv_sec = 0;
tv.tv_usec = 100;
result = select(from_ap+1, &readset, NULL, NULL, &tv);
if (result > 0 && FD_ISSET(from_ap, &readset)){
printf("there was something to read\n");
rsize=read(from_ap,cport_rbuf,ES1_MSG_SIZE);
}
The last message received is "there was something to read" and code does not progress further. What I am doing wrong? This is not a multithreaded program so no one can change flags but I have anyways confirmed them with printing back the flags before reading.
Does the device support O_NONBLOCK? This appears to be code from GitHub for gbsim. Read up on gbsim, it's entirely possible the driver does not support non-blocking calls.

How to convert blocking file io to non-blocking in C

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.

solaris recv infinite receiving

When you run this code, the response does not come.
Soket is a state of being connected.
So forever is in the standby state return value without not.
please help me.
...
sock = socket(PF_INET, protocol, 0);
...
char recv_data[102400] = {0,};
while ((size=recv(sock,recv_data,102400-1, 0)) > 0){
// some code
}
...
OS : SunOS xname 5.10 Generic_147440-12 sun4u sparc
SUNW,Sun-Fire-15000
I am guessing the socket is blocking.
int noblock(int fd)
{
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) return 0;
flags = (blocking) ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK);
return (fcntl(fd, F_SETFL, flags) == 0) ? 1 : 0;
}
Use this to set the socket to non-blocking. When there is no data to read, recv() will return a -1
and set errno to EWOULDBLOCK
See if those changes get you past your current problem.
You really should be checking the return codes of all you calls

Socket Programming Problem

I have implemented the client server using socket programming in C on Unix OS. I have used the non blocking socket at client end. I want to implement the two way communication. But its working only with one way i.e. Client can read and write the data on server, but server can not read or write data on client.
Client
nread = recv(sock, ptr, nleft, MSG_DONTWAIT))
send(sock, ptr, nleft, 0))
Server
recv(sock, ptr, nleft, MSG_DONTWAIT))
SockWrite(sock, Message, dataLength)
Server is always facing problem in reading. Can any one explain me why and how to get rid of this?
Await for socket ready for reading or writing using select() call.
code samples
static void SetNonBlock(const int nSock, bool bNonBlock)
{
int nFlags = fcntl(nSock, F_GETFL, 0);
if (bNonBlock) {
nFlags |= O_NONBLOCK;
} else {
nFlags &= ~O_NONBLOCK;
}
fcntl(nSock, F_SETFL, nFlags);
}
...
SetNonBlock(sock, true);
...
int code = recv(sock, buf, len_expected, 0);
if(code > 0) {
here got all or partial data
} else if(code < 0) {
if((errno != EAGAIN) && (errno != EINPROGRESS) ) {
here handle errors
}
otherwise may try again
} else if(0 == code) {
FIN received, close the socket
}
What is the return code to recv? Have you set the recv socket to non-blocking? In that case you are probably seeing EAGAIN, and you need to select() etc, or go back to blocking. I would not recommend ever ignoring return values to system calls.

Resources