solaris recv infinite receiving - c

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

Related

What is the proper way to send an AT command with termios and get the reply

I am using Termios in an (ressource constrained) embedded Linux platform (in C) to send commands and receive data from various tty peripherals (CP2102 USB-UART). Apparently there are various ways to do that and many are improper. I tried few with mitigated success, I came across something that works but i am not sure it is optimal or even correct :
#define BAUDRATE 115200
#define DEVICE "/dev/ttyUSB0"
#define DATA "BLK\r"
int handler(void){
char buf[255];
struct pollfd fds[1];
int fd, ret, res, retry = 0;
connect:
fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == 0){
perror(DEVICE);
printf("Failed to open %s\n",DEVICE);
sleepms(2000);
if(retry++<5) goto connect;
//exit(-1);
}
set_interface_attribs (fd, BAUDRATE, 0); // 8n1 no parity
set_blocking (fd, 0); // not blocking
fds[0].fd = fd; // streams
fds[0].events = POLLRDNORM;
for (;;)
{
int count = write(fd, DATA, strlen(DATA));
ret = poll(fds, 1, 1000);
if (ret > 0){
if (fds[0].revents & POLLHUP){ printf("Hangup\n"); close(fd); goto connect;}
if (fds[0].revents & POLLRDNORM){
res = read(fd,buf,255);
if(!res){close(fd); goto connect;}
buf[res-2]=0;
printf("Received %d bytes : %s",res,buf);
}
}
}
}
Basically the command is sent, then its polling until some data come or timeout occurs.
This worked for over 24h and shown no issue communication wise however there is one problem : if the peripheral is disconnected then i get the "hangout" notification but it never reconnects, i was expecting it would since i close the file and retry connection to interface.
Also, is poll is the best approach here? i dont want to spend CPU time in pure lost by polling (unless polling has some mecanism to release the CPU time to other threads) but i still want the call to be blocking until the timeout occurs or response arrive (i.e. i dont want to send command and get the response later with a callback). The response come from peripheral under few millisecond.
n.b. i know some eyes are bleeding because of the goto statement, no worries, goto has been used here to test quickly the "reconnect" approach (which didn't worked) but in the end if the connection has to be restarted it will be in a separate function, goto will never be used in the final implementation.
EDIT:
After rewrite. It works but there are still problems, mainly, when i disconnect the peripheral, Linux will randomly keep the port name or change it. Sometimes it will keep the port name for multiple consecutive disconnect, sometime it will rename it and stick with the new name for a while. So i have to find a way to identify the peripheral from USB and get current port name whatever it is.
On disconnect it throws error 9 from tcgetattr (coming from set_interface_attribs or set_blocking i think) but once it is reconnected and if Linux does not change the port name then it reconnects right away and restart to send and receive as it should, however, when Linux rename the port then it fail.
int fd=-1,retry=0;
struct pollfd fds[1];
int connect(void){
if(fd==-1) fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
else return 0; // already opened
printf("Connecting to fd #%d\n",fd);
if (fd==0){
perror(MODEMDEVICE);
printf("Failed to open %s\n",MODEMDEVICE);
retry++;
sleepms(2000);
return -1;
}
set_interface_attribs (fd, BAUDRATE, 0); // 8n1 no parity
set_blocking (fd, 0); // not blocking
fds[0].fd = fd; // streams
fds[0].events = POLLERR|POLLHUP|POLLRDNORM;
return 0;
}
int handlePoll(){
int ret=0,res=0;
char buf[255];
ret = poll(fds, 1, 1000); // 1000ms
if (ret > 0){
if (fds[0].revents & POLLERR){ close(fd); fd=-1; return -1; } // IO error
if (fds[0].revents & POLLHUP){ close(fd); fd=-1; return -2; } // interface closed
if (fds[0].revents & POLLRDNORM){
res = read(fd,buf,255);
if(!res){ close(fd); return -3; } // data receive error
buf[res-2]=0;
printf("Received %d bytes : %s\n",res,buf);
return 0;
}
return -4; // unknown error
}
return -5; // timeout
}
int sendCMD(char* cmd){
int res=1;
retry=0;
while(res && retry<5){ res=connect(); }
if(res) return -7;
if(retry>5) return -8;
int len = strlen(cmd);
int count = write(fd, cmd, len);
if(count<len){ return -6;}
return handlePoll();
}
int main(void){
while(1){
switch(sendCMD(DATA)){
case -1: printf("IO error\n"); break;
case -2: printf("Interface closed error\n"); break;
case -3: printf("data receive error\n"); break;
case -4: printf("Unknown error\n"); break;
case -5: printf("Timeout\n"); break;
case -6: printf("Command send error\n"); sleepms(200); break;
case -7: printf("Interface open error\n"); break;
case -8: printf("Cannot open interface after 5 try\n"); break;
default: break;
}
}
}
I think there should be a better way to deal with disconnect (Detecting if a character device has disconnected in Linux in with termios api (c++))
connect:
fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == 0){
perror(DEVICE);
The open(2) doesn't return 0, but -1 in case of error. 0 is a valid file descriptor -- by convention the standard input.
int count = write(fd, DATA, strlen(DATA));
ret = poll(fds, 1, 1000);
if (ret > 0){
Why aren't you checking the return value of write()? If the open() above actually failed and returned -1, this write() will fail too, return -1 and set errno to EBADF.
res = read(fd,buf,255);
if(!res){close(fd); goto connect;}
buf[res-2]=0;
Ditto, you don't care if read() fails, which it will certainly do if the open() above failed to open the file. Just like open(), write() and all system calls, read() will return -1 in case of error.
Since your file descriptor is non-blocking, be prepared to handle transient errors like EAGAIN separately [2].
In the case where res == -1 the buf[res-2]=0 will corrupt memory by writing before the start of buf.
Notice that poll() will not set POLLERR in revents if passed an invalid fd -- if will either ignore it if it's negative (like the fd returned by your failing open()), or set POLLNVAL if it's positive.
if (fds[0].revents & POLLHUP){ printf("Hangup\n"); close(fd); goto connect;}
if (fds[0].revents & POLLRDNORM){
POLLHUP and POLLRDNORM[1] can be returned together in revents, signaling the last possible read, which your code will miss.
I strongly suggest you strace(1) your program, which you could do while it's running, with strace -p PID.
[1] btw, POLLRDNORM is equivalent to POLLIN in Linux.
[2] and EINTR, if your program or the libraries it's using are setting any signal handler.

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.

select returns 0 although packets returned, i did reset the readset every time before calling select

I wrote a ping program sending syn packet to destination ip address 1.1.1.1 port 0. I used wireshark that i saw packets returned with RST/ACK flags on. But the problem is when i use select() to try to read the socket, select() always returns 0. So I have no idea how to debug the program. I'm sure I reset the fd_set readset everytime. Is there anything i just missed ?
i discovered the reply from 1.1.1.1 returned back in 0.0003 second using wireshark
the timeout i set is 1 second(1000 ms)
Here is the code
void readloop() {
....
while(nsent < 4) {
send_v4();
wait_for_reply(1000); // wait for 1 second;
}
}
int wait_for_reply(long wait_time) {
....
result = recving_time(...);
if(result < 0) // because time out
return 0;
....
}
int recving_time(...) {
......
fd_set readset;
select_again:
set timeout value to structure *to*
FD_ZERO(&readset);
FD_SET(sockfd, &readset);
readable = select(sockfd+1, &readset, NULL, NULL, &to);
#ifdef DEBUG
fprintf(stderr, "readable is %d\n",readable); // **Why readable always be 0 although packets returned.**
#endif
if(readable < 0) {
if(errno == EINTR)
goto select_again;
else {
perror("select() error");
exit(1);
}
if(readable == 0) {
return -1;
}
......
}
I'm not sure there is enough code here to understand what I am trying to saying. I will be very very appreciate if you can help me
Select() returns the number of ready descriptors that are contained in the descriptor sets, or -1 if an error occurred. If the time limit expires, select() returns 0.
It would seem like your timeout (which you're not showing the setup of) is elapsing.

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

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

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