Inconsistent behavior of select for socket between Linux and BSD - linux

I am building a cross platform socket program under MacOS (FreeBSD) and Linux, like this
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
int main(void) {
fd_set rfds;
fd_set wfds;
struct timeval tv;
int retval;
int fd = socket(AF_INET, SOCK_STREAM, 0);
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(fd, &rfds);
FD_SET(fd, &wfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
retval = select(fd + 1, &rfds, &wfds, NULL, &tv);
printf("ready sockets = %d\n", retval);
exit(EXIT_SUCCESS);
}
It's very simple, it creates a socket, and use select to see if it's either readable or writable.
If I run it under MacOS
ready sockets = 0
You will see the program blocks for 1 second and it prints socket ready. But if you run it under Linux, you will see it prints out
ready sockets = 2
immediately. Which sounds very odd to me, since the socket just created, there is nothing to read or write, but yet select function told me it's ready to read and write, how come they behave differently?

Related

NETLINK_NFLOG support in Linux 4.14

I've this program which runs fine on Linux 2.6.34. While porting this program to 4.14, socket creation is giving error "Error: : Protocol not supported". As per http://man7.org/linux/man-pages/man7/netlink.7.html
NETLINK_NFLOG (up to and including Linux 3.16)
Netfilter/iptables ULOG.
Do we know what is the alternative in 4.14 ?
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <pthread.h>
#include <netinet/ip.h>
#include <linux/types.h>
#include <linux/netlink.h>
int main()
{
struct sockaddr_nl addr;
int mypid;
int status;
int sockfd = -1;
/* mypid = getpid(); */
mypid = pthread_self();
sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NFLOG);
if (sockfd <= 0) {
printf("netlink socket() failed - rc:%d, errno:%d\n",
sockfd, errno);
perror("Error: ");
return (-1);
}
/* set up socket address */
memset(&addr, 0, sizeof (addr));
addr.nl_pid = mypid;
addr.nl_family = AF_NETLINK;
/*
nl_groups is the multicast
group ID to which the ULOG
messages will be sent.It
is bitmap of hexadecimal
format
*/
addr.nl_groups = 1;
/* bind socket to listen on
* multicast group 1 */
status = bind(sockfd, (struct sockaddr *)&addr, sizeof (addr));
if (status < 0) {
perror("bind:");
close(sockfd);
return (-1);
}
printf("socket bind successful\n");
close(sockfd);
return (0);
}
I tried to browse kernel source but couldn't identify.
I've below config
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_ADVANCED is not set
CONFIG_NETFILTER_INGRESS=y
CONFIG_NETFILTER_NETLINK=y
CONFIG_NETFILTER_NETLINK_LOG=y
# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set
CONFIG_NETFILTER_XTABLES=y
CONFIG_NETFILTER_XT_MARK=y
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
CONFIG_NETFILTER_XT_TARGET_LOG=y
CONFIG_NETFILTER_XT_NAT=y
# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
NETLINK_NFLOG (up to and including Linux 3.16)
see worked example in libnml

UART reply includes previous command?

I am trying to read from a UART device in a Linux environment using a C program, but I experience different results respect to communicating to the UART using screen.
The C code I use to test the UART communication is the following:
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <getopt.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <signal.h>
#include <ctype.h>
bool loop;
void sigHandler(int32_t sig)
{
if(sig == SIGINT)
{
printf("Catched SIGINT");
loop = false;
}
}
int main(int argc, char *argv[])
{
char *devname = argv[1];
int fd = -1;
int nread = -1;
int nwrite = -1;
int ret;
struct termios t_new = {0};
struct termios t_old = {0};
signal(SIGINT, sigHandler);
fd = open(devname, O_RDWR | O_NOCTTY |O_NONBLOCK);
if(fd > 0)
{
printf("TTY open ! Configuring TTY");
}
else
{
fd = -1;
return 1;
}
ret = tcgetattr(fd, &t_old);
if(ret < 0)
{
perror("tcgetattr ");
close(fd);
fd = -1;
return 1;
}
t_new = t_old;
t_new.c_cflag = (B9600 | CS8 | CREAD );
t_new.c_oflag = 0;
t_new.c_iflag = 0;
t_new.c_lflag = 0;
ret = tcsetattr(fd, TCSANOW, &t_new);
loop = true;
while(loop)
{
char s[] = "at+gmi=?\r\n";
nwrite = write(fd, s, strlen(s));
if(nwrite == strlen(s))
{
fd_set rfd;
struct timeval tm = {.tv_sec = 0, .tv_usec = 500000};
FD_ZERO(&rfd);
FD_SET(fd, &rfd);
char buffer[64] = {0};
if(select(fd + 1, &rfd, NULL, NULL, &tm) > 0)
nread = read(fd, buffer, sizeof(buffer));
if(nread > 0)
printf("Reply is: %s\n", buffer);
}
usleep(500000);
}
}
But when I read the reply, it always includes the string I have sent.
I don't experience this problem using screen.
What is the best way to read from an UART in C using Linux ?
Could the multiplexed way (using select) causing the problems ?
EDIT
For completeness, the output is:
Reply is: at+gmi=?
OK
Also, sometimes I don't read anything.
But when I read the reply, it always includes the string I have sent.
Since your termios configuration obliterated the local echo attributes and you're sending an AT modem command, you should try sending an ATE0 command to disable echoing by the modem.
I don't experience this problem using screen.
This observation confirms that the connected modem has its echoing enabled.
The AT command is echoed (by the modem) as you type, but you don't object to this received data in this situation (because you want to see what you type).
If the modem did not have echoing enabled, then you would be complaining that what you type in screen was not visible.
IOW echo is desired when using a terminal emulator program (such as screen), but echoing needs to be disabled when sending data by a program.
What is the best way to read from an UART in C using Linux ?
(Technically you are not reading from a "UART", but rather from a serial terminal that fully buffers all input and output.)
Code that conforms to POSIX standard as described in Setting Terminal Modes Properly
and Serial Programming Guide for POSIX Operating Systems would be far better that what you have now.
I'm surprised that it works at all (e.g. CREAD is not enabled).
Could the multiplexed way (using select) causing the problems ?
Not the echo "problem".
Your program does not do anything that requires using select() and nonblocking mode.
Also, sometimes I don't read anything.
When you write code that is not POSIX compliant, you should not expect reliable program behavior.

setsockopt IPT_SO_SET_REPLACE flag return error (linux)

I try to use setsockopt with the flag IPT_SO_SET_REPLACE but i keep getting the wired error from errno Protocol not available this is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <linux/sched.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <fcntl.h>
int main(void) {
int sock;
int ret;
void *data;
size_t size;
struct ipt_replace *repl;
sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
if (sock == -1) {
perror("socket");
return -1;
}
size = sizeof(struct ipt_replace);
data = malloc(size); Protocol not available
if (data == NULL) {
perror("malloc");
return -1;
}
memset(data, 0, size);
repl = (struct ipt_replace *) data;
repl->num_counters = 0x1;
repl->size = 0xffffffff;
repl->valid_hooks = 0x1;
repl->num_entries = 0x1;
ret = setsockopt(sock, SOL_IP, IPT_SO_SET_REPLACE, (void *) data, size);
printf("\ndone %d\n", ret);
perror("error: ");
return 0;
}
this is the output :
sock:3
data:
size:92
done -1
error: : Protocol not available
Looking briefly at the kernel code, this would seem to indicate that the IP tables module isn't available (i.e. the kernel wasn't built with it configured, or it can't be found or loaded).
It appears to me that for a socket of the kind you created, the code flow is:
enter raw_setsockopt: level != SOL_RAW so...
call ip_setsockopt: level == SOL_IP but option isn't any of the IP_xxx options so...
call nf_setsockopt: Search loaded netfilter modules for one that has registered IPT_SO_SET_REPLACE.
I think the last must have failed, so you get ENOPROTOOPT back (== Protocol not available)

How to use static file descriptor using poll linux function call?

poll is running for infinite time interval.
i want poll to hit when some thing is written into file or when file is updated.
but poll is not able to detect when file is written.
#include <stdio.h>
#include <poll.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
char buf[5]="true";
struct pollfd ufds[1];
int rv;
ufds[0].fd = 0;
ufds[0].events = POLLIN;
char *filename="textfile.txt";
ssize_t ret_write,ret_read;
ufds[0].fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 5);
if(ufds[0].fd== -1){
perror("open");
return 3;
}
while(1) {
ret_write= write (ufds[0].fd, &buf, (ssize_t) 5);
if((rv = poll(ufds, 1,-1 )) == -1) perror("select");
else if (rv == 0) printf("Timeout occurred!\n");
else if (ufds[0].revents & POLLIN) {
printf("return hit\n");
read(ufds[0].fd, buf, 5);
}
fflush(stdout);
}
return 0;
}
Your example can't work because the file is not open for reading. Even if the file was opened for reading, the code would not work as intended because poll would return sucessfully on end of file.
What you want is the inotify function. Please try it by yourself first, and ask a question when you have code not working as intended.

poll() can't detect event when socket is closed locally?

I'm working on a project that will port a TCP/IP client program onto an embedded ARM-Linux controller board. The client program was originally written in epoll(). However, the target platform is quite old; the only kernel available is 2.4.x, and epoll() is not supported. So I decided to rewrite the I/O loop in poll().
But when I'm testing code, I found that poll() does not act as I expected : it won't return when a TCP/IP client socket is closed locally, by another thread. I've wrote a very simple codes to do some test:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <pthread.h>
#include <poll.h>
struct pollfd fdList[1];
void *thread_runner(void *arg)
{
sleep(10);
close(fdList[0].fd);
printf("socket closed\n");
pthread_exit(NULL);
}
int main(void)
{
struct sockaddr_in hostAddr;
int sockFD;
char buf[32];
pthread_t handle;
sockFD = socket(AF_INET, SOCK_STREAM, 0);
fcntl(sockFD,F_SETFL,O_NONBLOCK|fcntl(sockFD,F_GETFL,0));
inet_aton("127.0.0.1",&(hostAddr.sin_addr));
hostAddr.sin_family = AF_INET;
hostAddr.sin_port = htons(12345);
connect(sockFD,(struct sockaddr *)&hostAddr,sizeof(struct sockaddr));
fdList[0].fd = sockFD;
fdList[0].events = POLLOUT;
pthread_create(&handle,NULL,thread_runner,NULL);
while(1) {
if(poll(fdList,1,-1) < 1) {
continue;
}
if(fdList[0].revents & POLLNVAL ) {
printf("POLLNVAL\n");
exit(-1);
}
if(fdList[0].revents & POLLOUT) {
printf("connected\n");
fdList[0].events = POLLIN;
}
if(fdList[0].revents & POLLHUP ) {
printf("closed by peer\n");
close(fdList[0].fd);
exit(-1);
}
if(fdList[0].revents & POLLIN) {
if( read(fdList[0].fd, buf, sizeof(buf)) < 0) {
printf("closed by peer\n");
close(fdList[0].fd);
exit(-1);
}
}
}
return 0;
}
In this code I first create a TCP client socket, set to non-blocking mode, add to poll(), and close() the socket in another thread. And the result is: "POLLNVAL" is never printed while the socket is closed.
Is that an expected behavior of poll() ? Will it help if I choose select() instead of poll() ?
Yes, this is expected behavior. You solve this by using shutdown() on the socket instead of close().
See e.g. http://www.faqs.org/faqs/unix-faq/socket/ section 2.6
EDIT: The reason this is expected is that poll() and select() reacts to events happening on one of their fd's. close() removes the fd, it does not exist at all anymore, and thus it can't have any events associated with it.

Resources