Why select do not tell me that a client wants to connect? - linux

I've made a simple tcp server that I can test with telnet program.
When running it on windows, it works as expected, when running it on linux, the behavior is strange:
telnet clients understand that they are connected to the server,
the server do not see clients (select return always 0),
when I kill the server, the clients detect the disconnection.
I think I missed something in accept, listen or select.
What did I missed?
Thanks.
Here's the program source:
#include "headers.h"
#define DEFAULT_PORT 24891
/**
* test_server [ip port]
*/
int main(int argc, char *argv[])
{
sockaddr_in sin;
socket_t sock;
/* listening socket creation */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sock)
{ die("socket()"); }
/* binding */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(DEFAULT_PORT);
if (3 == argc)
{
sin.sin_addr.s_addr = inet_addr(argv[1]);
sin.sin_port = htons(strtol(argv[2], NULL, 0));
}
if (-1 == bind(sock, (sockaddr*) &sin, sizeof(sin)))
{ die("bind()"); }
/* Listening */
if (-1 == listen(sock, SOMAXCONN))
{ die("listen()"); }
while (1)
{
timeval timeout = { 1, 0 };
fd_set in_set;
FD_ZERO(&in_set);
FD_SET(sock, &in_set);
// select the set
int cnt = select(1, &in_set, NULL, NULL, &timeout);
if (cnt > 0)
{
// ask if an event occurs on listening socket
if (FD_ISSET(sock, &in_set))
{
/* a new client wants to connect */
socket_t csock = accept(sock, NULL, NULL);
send(csock, "hello\r\n", 7, 0);
printf("new client!\n");
close(csock);
}
}
else if (cnt < 0)
{ die("select"); }
}
/* closing listen socket */
close(sock);
printf("socket closed\n");
return 0;
}

You simply call select incorrectly. The first parameter needs to be the highest numbered fd from the fdset, plus one. See man page:
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
....
nfds is the highest-numbered file descriptor in any of the three sets, plus 1.
The code may work, or may not, that depends on the fd returned by "socket()".
In your case the value of "nfds" needs to be "sock + 1", generally you need to track the highest numbered fd when doing a select on multiple fd's.

Related

Why recv() from socket does not block

I create a TCP server socket that listens to connect() requests and accept() them. After accepting a client socket receives data from it. I want recv() function to block with a timeout, but it seems to be non-blocking.
I have achieved the client to be in blocking mode when receiving response from the server, but it does not seem to work the same with the server side.
Below I copy-paste the server side that I want to receive data in blocking mode:
int clientSocket = accept(_serverSocket, (struct sockaddr *)NULL, NULL);
if (clientSocket < 0)
return -1;
// set TIMEOUT option to server socket
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 500 * 1000;
int sockOptRet = setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
struct linger sl;
sl.l_onoff = 1; /* non-zero value enables linger option in kernel */
sl.l_linger = 0; /* timeout interval in seconds */
setsockopt(clientSocket, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl));
char _rcvBuffer[sizeof(can_frame)];
int numBytesRcv = recv(clientSocket, _rcvBuffer, sizeof(can_frame), 0);
I have also tried it with MSG_WAITALL flag but it does not change anything...
Your code should clearly block, but your timeout of 0.5s doesn't do showing it justice.
If you increase the timeout to something more conspicuous such as 2s and graft the code onto, e.g., beej's tpc server template, you get something like:
/*
** server.c -- a stream socket server demo
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define PORT "3490" // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
void sigchld_handler(int s)
{
// waitpid() might overwrite errno, so we save and restore it:
int saved_errno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(servinfo); // all done with this structure
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
// set TIMEOUT option to server socket
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0 * 500 * 1000;
int sockOptRet = setsockopt(new_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
struct linger sl;
sl.l_onoff = 1; /* non-zero value enables linger option in kernel */
sl.l_linger = 0; /* timeout interval in seconds */
setsockopt(new_fd, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl));
char can_frame[1024];
char _rcvBuffer[sizeof(can_frame)];
int numBytesRcv = recv(new_fd, _rcvBuffer, sizeof(can_frame), 0);
if (send(new_fd, "Hello, world!", 13, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
return 0;
}
Now if your run this and then do:
nc localhost 3490
without typing a line to send, there should be a distinct 2-second wait
before the server gives up on you, indicating that the recv is indeed blocking.

client socket connection issue

Hi I'm trying to write a client application which will try to connect a remote server. If it can not connect to the server, it will try once again after 5 seconds. If the socket is closed somehow, it will try to connect once again.
I'm getting an error like connect: Transport endpoint is already connected
What could be the problem ?
static void sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}
int main(int argc, char *argv[])
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
pid_t childpid;
struct hostent *he;
struct sockaddr_in their_addr; /* connector's address information */
if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */
herror("gethostbyname");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
their_addr.sin_family = AF_INET; /* host byte order */
their_addr.sin_port = htons(PORT); /* short, network byte order */
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero), 8); /* zero the rest of the struct */
for ( ; ; ) {
while (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect");
sleep(5);
}
if ( (childpid = fork()) == 0)
{ /* child process */
while(1)
{
if (send(sockfd, "Hello, world!\n", 14, 0) == -1)
{
perror("send");
}
sleep(3);
}
close(sockfd);
}
}
return 0;
}
You can't reconnect a socket once you have even tried to connect it before, even if it failed. You have to close it and create a new one.

Non-blocking Linux server socket

I want to create a server socket that always prints to screen "tick" , and if one client sends data to this server, the server will print that data. I use non-blocking socket, but the it does not work, server prints to screen "tick" but cannot receives data from client.
Server
int main(int argc, char *argv[]) {
int server_sockfd, client_sockfd;
sockaddr_un server_address;
sockaddr_un client_address;
int client_len;
int res;
/* remove old socket and create unnamed socket */
unlink("server_socket");
server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
/* non-blocking socket */
fcntl(server_sockfd, F_SETFL, O_NONBLOCK);
/* name the socket */
server_address.sun_family = AF_UNIX;
strcpy(server_address.sun_path, "server_socket");
bind(server_sockfd, (sockaddr*)&server_address, sizeof(server_address));
/* listen client */
printf("server_waiting\n");
listen(server_sockfd, 5);
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd, (sockaddr*)&client_address, (socklen_t*)&client_len);
while(1) {
char ch;
res = recv(client_sockfd, &ch, 1, 0);
if (res == -1) {
printf("tick\n");
}
else {
printf("received: %c\n", ch);
}
}
}
client
int main(int argc, char *argv[]) {
int sock_fd;
struct sockaddr_un address;
int result;
char ch = 'A';
/* create socket for client */
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
/* name of socket as agreed with server */
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "server_socket");
result = connect(sock_fd, (sockaddr*) &address, sizeof(address));
if (result == -1) {
perror("fail\n");
exit(1);
}
/* write via socket */
send(sock_fd, &ch, 1, 0);
close(sock_fd);
exit(0);
}
You are setting the listing socket to be non-blocking instead of the accepted socket.
Following your code logic, you DO want to wait on the accept call, but not the recv call
Instead of
/* non-blocking socket */
fcntl(server_sockfd, F_SETFL, O_NONBLOCK);
Delete it and instead add the fcntl call to the socket you are getting back from the accept call, like
client_sockfd = accept(....);
int flags = fcntl(client_sockfd, F_GETFL, 0);
fcntl(client_sockfd, F_SETFL, flags | O_NONBLOCK);
accept and fcntl can fail so you should check for failures in production code.

socket::accept continual to return EGAIN

I use nonblocking socket to receive new connection. But the code repeatedly fails to accept().
int sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
::bind(sockfd, bind_addr, static_cast<socklen_t>(sizeof(struct sockaddr_in6)));
ret = ::listen(sockfd, SOMAXCONN);
while (True) {
::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs);
struct sockaddr_in6 addr;
bzero(&addr, sizeof addr);
socklen_t addrlen = static_cast<socklen_t>(sizeof *addr);
int connfd = ::accept4(sockfd, sockaddr_cast(addr),
&addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
}
errno is EAGAIN.
From the manpage to accept(2):
EAGAIN or EWOULDBLOCK
The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.
This means that the call to accept is made before the client has connected.
Before calling accept, you must call listen and bind.
But as your socket is not blocking, you should wait for client to wait to connect. You can do that with select function:
int sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
// addr is for accept call, sin for bind call
struct sockaddr_in6 addr, sin;
bzero(&addr, sizeof addr);
// prepare sin to tell bind to listen on any connection on given port
sin.sin6_family = family;
sin.sin6_addr = in6addr_any;
sin.sin6_port = htons(port); // choose port on which client could connect
sin.sin6_scope_id = 0;
// bind socket to interface
if (::bind(sock, (struct sockaddr*) &sin, sizeof(sin)) < 0)
{
perror("bind");
}
// listen for new connection
if (::listen(sock, SOMAXCONN) < 0)
{
perror("socket");
}
while (1)
{
fd_set conset;
FD_ZERO(&conset);
FD_SET(sockfd, &conset);
struct timeval timeout = {10, 0};
int maxfd = sockfd;
// wait for new client
select(maxfd + 1, &conset, NULL, NULL, &timeout);
if (FD_ISSET(sockfd, &conset))
{
// a new client is waiting
int connfd = ::accept(sockfd, &addr);
if (connfd < 0)
{
perror("accept");
}
else
{
// do thing with new client
}
}
else
{
printf("no new client in last 10 seconds")
}
}

create SOCK_RAW socket just for sending data without any recvform()

If I create a socket whose type is SOCK_RAW only to send some data without receiving any data, is there any problem when kernel continue to receive network packets and copy its datagram to somebuffer (of application?). In other words, after the somebuffer is filled what will happened? error or ignore?
I don't know how to prevent kernel from delivering the copy of datagram to my application.
Reference http://sock-raw.org/papers/sock_raw 0x4 raw_input
After the IP layer processes
a new incoming IP datagram, it calls ip_local_deliver_finish() kernel function
which is responsibe for calling a registered transport protocol handler by
inspecting the protocol field of the IP header (remember from above). However
before it delivers the datagram to the handler, it checks every time if an
application has created a raw socket with the same protocol number. If there
is one or more such applications, it makes a copy of the datagram and delivers
it to them as well.
You can use shutdown(2) in order to shutdown reception part of the socket.
See shutdown man page
EDIT : I found that shutdown only works on connected (ie TCP) sockets.
With Raw socket, there are 2 possibilities :
Receive data into a temporary buffer (with recv) and discard them (perhaps in an other thread)
If I remember well, when the socket buffer is full, incoming data are automatically discarded (and data in the buffer aren't modified), so you can set the socket reception buffer size to 0 (and increase it later if needed).
Here's how to set reception buffer size to 0 :
int opt = 0;
setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
TEST
/**
* #file raw_print_pkt.c
* #brief
* #author Airead Fan <fgh1987168#gmail.com>
* #date 2012/08/22 12:35:22
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
int main(int argc, char *argv[])
{
int s;
ssize_t rn; /* receive number */
struct sockaddr_in saddr;
char packet[4096];
int count;
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
memset(packet, 0, sizeof(packet));
socklen_t *len = (socklen_t *)sizeof(saddr);
int fromlen = sizeof(saddr);
int opt = 0;
count = 0;
while(1) {
if ((rn = recvfrom(s, (char *)&packet, sizeof(packet), 0,
(struct sockaddr *)&saddr, &fromlen)) < 0)
perror("packet receive error:");
if (rn == 0) {
printf("the peer has performed an orderly shutdown\n");
break;
}
printf("[%d] rn = %lu \n", count++, rn);
if (count == 16) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
perror("setsocketopt failed");
} else {
fprintf(stdout, "setsocketopt successful\n");
}
// int shutdown(int sockfd, int how);
/* if (shutdown(s, SHUT_RD) < 0) {
* perror("shutdown failed");
* } */
}
}
return 0;
}
TEST 2 (same includes):
int main(int argc, char *argv[])
{
int s;
ssize_t rn; /* receive number */
char packet[4096];
int count;
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
memset(packet, 0, sizeof(packet));
int opt = 0;
count = 0;
//Set recv buffer size
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
perror("setsocketopt failed");
} else {
fprintf(stdout, "setsocketopt successful\n");
}
//10 seconds countdown
int i = 10;
while(i > 0)
{
printf("\r%d ", i);
fflush(stdout);
i--;
sleep(1);
}
printf("\n");
while(1) {
if ((rn = recv(s, (char *)&packet, sizeof(packet), 0)) <= 0)
perror("packet receive error:");
printf("[%d] rn = %lu \n", count++, rn);
}
return 0;
}
Here's how to proceed with test 2 :
First of all, set the buffer size to 4096 (or bigger if you have a lot of traffic on your network). Compile and launch. During the 10 seconds before starting receiving data, send a lot of data to the socket. After the 10 seconds, the program will receive everything you sent during the countdown.
After that, set the buffer size to 0. Proceed as previously. After the 10 seconds, the program won't receive the data you sent during the countdown. But if you send data while it's in recvfrom, it will read them normally.
I don't really understand what you want! if you want just to inject some packets, it's simple:
#include<netinet/tcp.h> /* TCP header */
#include<netinet/ip.h> /* IP header */
/* Checksum compute function */
/* source : http://www.winpcap.org/pipermail/winpcap-users/2007-July/001984.html */
unsigned short checksum(unsigned short *buffer, int size)
{
unsigned long cksum=0;
while(size >1)
{
cksum+=*buffer++;
size -=sizeof(unsigned short);
}
if(size)
cksum += *(UCHAR*)buffer;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (unsigned short)(~cksum);
}
int main (int argc, char **argv)
{
char packet_buffer[BUFFER_SIZE];
struct sockaddr_in sin;
struct iphdr *ip_header; /* IP header */
struct tcphdr *tcp_header; /* TCP header */
int flag = 1;
/* Creating RAW socket */
int raw_socket = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
ip_header = (struct iphdr *) packet_buffer;
tcp_header = (struct tcphdr *) (packet_buffer + sizeof (struct ip));
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT_NUMBER);
sin.sin_addr.s_addr = inet_addr (IP_ADDRESS);
/* Zeroing the bbuffer */
memset (packet_buffer, 0, BUFFER_SIZE);
/* Construct your IP Header */
ip_header->ihl = 5;
ip_header->version = 4;
ip_header->tos = 0;
ip_header->tot_len = sizeof (struct ip) + sizeof (struct tcphdr);
ip_header->id = htonl(CHOOSE_PACKET_ID);
ip_header->frag_off = 0;
ip_header->ttl = 255;
ip_header->protocol = 6; /* TCP. Change to 17 if you want UDP */
ip_header->check = 0;
ip_header->saddr = inet_addr (SOURCE_IP_ADDRESS_TO_SPOOF);
ip_header->daddr = sin.sin_addr.s_addr;
/* Construct your TCP Header */
tcp_header->source = htons (SOURCE);
tcp_header->dest = htons(DEST);
tcp_header->seq = random();
tcp_header->ack_seq = 0;
tcp_header->doff = 0;
tcp_header->syn = 1;
tcp_header->window = htonl(65535);
tcp_header->check = 0;
tcp_header->urg_ptr = 0;
/* IP Checksum */
ip_header->check = checksum((unsigned short *) packet_buffer, ip_header->tot_len >> 1);
if (setsockopt(raw_socket, IPPROTO_IP, IP_HDRINCL, &flag, sizeof(flag)) < 0)
{
/* ERROR handling */
}
while (1)
{
/* Send the packet */
if (sendto(raw_socket, packet_buffer, ip_header->tot_len, 0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
/* ERROR handling */
}
/* The rest of your need */
}
return 0;
}

Resources