UDP bad length for IPv6 raw socket - c

My program should sending UDP datagrams, using Raw socket for IPv6 protocol.
I have to use IPV6 CHECKSUM in socket options. Code is compiled well, but TCPDump is showing bad length.
IP6 fe80::20c:29ff:fe95:c051.24576 > waw02s13-in-x03.1e100.net.0: UDP, bad length 12280 > 40
What I miss or what i'm doing wrong?
int main(int argc, char** argv) {
int sockfd;
int offset;
int retval;
struct addrinfo hints;
struct addrinfo *rp, *result;
unsigned char datagram[sizeof(struct ip6_hdr) + sizeof(struct udphdr)
] = {0};
struct ip6_hdr *ip_header = (struct ip6_hdr *)datagram;
struct udphdr *udp_header = (struct udphdr *)
(datagram + sizeof(struct ip6_hdr));
if (argc != 3) {
fprintf(
stderr,
"Invocation: %s <HOSTNAME OR IP ADDRESS> <PORT>\n",
argv[0]
);
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_UDP;
retval = getaddrinfo(argv[1], NULL, &hints, &result);
if (retval != 0) {
fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(retval));
exit(EXIT_FAILURE);
}
offset = 6;
for (rp = result; rp != NULL; rp = rp->ai_next) {
sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sockfd == -1) {
perror("socket()");
continue;
}
retval = setsockopt(
sockfd,
IPPROTO_IPV6, IPV6_CHECKSUM,
&offset, sizeof(offset)
);
if (retval == -1) {
perror("setsockopt()");
exit(EXIT_FAILURE);
} else {
break;
}
}
if (rp == NULL) {
fprintf(stderr, "Client failure: could not create socket.\n");
exit(EXIT_FAILURE);
}
ip_header->ip6_flow = htonl((6 << 28) | (0 << 20) | 0);
ip_header->ip6_hops = 255;
ip_header->ip6_nxt = IPPROTO_UDP;
ip_header->ip6_plen = sizeof(struct ip6_hdr)
+ sizeof(struct udphdr);
inet_pton(AF_INET6, SOURCE_ADDRESS, &(ip_header->ip6_src));
inet_pton(AF_INET6, argv[1], &(ip_header->ip6_dst));
udp_header->uh_sport = htons(SOURCE_PORT);
udp_header->uh_dport = htons(atoi(argv[2]));
udp_header->uh_ulen = htons(ip_header->ip6_plen);
fprintf(stdout, "Sending UDP...\n");
for (;;) {
retval = sendto(
sockfd,
datagram, ip_header->ip6_plen,
0,
rp->ai_addr, rp->ai_addrlen
);
if (retval == -1) {
perror("sendto()");
}
sleep(1);
}
exit(EXIT_SUCCESS);
}
Wireshark Image
Any ideas?

Related

sendto() for UDP server is not sending data to client

I'm lost, but the title sums it up. I'm trying to make a UDP server using netster, but for whatever reason, I'll get data from the client but not the other way around. I suspect it has something to do with clientaddr due to getting an error "sendto: Address family not supported by protocol," but I've looked over multiple examples and this seemed like the documented way to use the struct.
I really cannot pinpoint the issue here so I'll show all my code
void chat_server(char* iface, long port, int use_udp)
{
struct addrinfo hints;
struct addrinfo *results, *rp;
char buff4[INET_ADDRSTRLEN];
void* raw_addr;
int sfd = 0, valread, connectfd;
short end = 0;
char cport[7];
struct sockaddr_in servaddr, clientaddr;
socklen_t addrlen;
char* rescbuff;
sprintf(cport, "%ld", port);
size_t count = 0;
//TCP & UDP FLAGS
if(use_udp)
{
hints.ai_protocol = IPPROTO_UDP;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
}
else
{
hints.ai_protocol = IPPROTO_TCP;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
}
hints.ai_flags = AI_PASSIVE;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
//get IP address and socket from server
if(getaddrinfo(iface, cport, &hints, &results))
{
perror("getaddrinfo");
exit(-1);
}
for(rp = results; rp != NULL; rp = rp->ai_next)
{
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(sfd == -1) continue;
if(rp->ai_family == AF_INET)//(results->ai_family == AF_INET)
{
struct sockaddr_in* tmp = (struct sockaddr_in*)rp->ai_addr;
raw_addr = &(tmp->sin_addr);
inet_ntop(AF_INET, raw_addr, buff4, INET_ADDRSTRLEN);
break;
}
}
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
//bind
valread = bind(sfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
if(valread == -1)
if(valread == -1)
{
perror("bind server");
exit(-1);
}
addrlen = sizeof(clientaddr);
rescbuff = malloc(MAX_S*sizeof(char*));
do
{
//get client IP + count connections starting at 0
//memset(&clientaddr, 0, sizeof(clientaddr));
struct sockaddr_in* pV4Addr = (struct sockaddr_in*)&clientaddr;
struct in_addr ipAddr = pV4Addr->sin_addr;
char str[INET_ADDRSTRLEN];
inet_ntop( AF_INET, &ipAddr, str, INET_ADDRSTRLEN );
clientaddr.sin_family = AF_INET;
//clientaddr.sin_addr.s_addr = inet_addr(str);
do //communicate loop
{
socklen_t len;
memset(rescbuff, 0, MAX_S);
valread = 0;
//get message
valread = recvfrom(sfd, rescbuff, MAX_S, 0, (struct sockaddr*)&clientaddr, &len);
if( valread == -1)
{
perror("recvfrom");
exit(-1);
}
//acknowledge
printf("got message from('%s', %d)\n",str, servaddr.sin_port);
printf("message %s\n", rescbuff);
//reply to message
printf("try1\n");
//valread = sendto(sfd, rescbuff, strlen(rescbuff), 0, ( struct sockaddr*)&clientaddr, sizeof(clientaddr));
valread = sendto(sfd, "hello\n", 20, 0, (struct sockaddr*)&clientaddr, sizeof(clientaddr));
if(valread == -1)
{
perror("sendto");
exit(-1);
}
printf("bytes sent: %d\n", valread);
}
while(1);
if(end) break;
}
while(1);
close(sfd);

Sendto fails with an error "no such device or address" after sometime

int main(int argc, char *argv[]) {
struct sockaddr_in src_socket_address, dest_socket_address;
struct ifreq ifreq_i;
struct ifreq if_mac;
struct ifreq ifreq_ip;
int packet_size;
char ifName[IFNAMSIZ];
char sendbuf[BUF_SIZE];
int tx_len = 0;
unsigned char *buffer = (unsigned char*)malloc(65536);
int sock = socket (AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
int send_soc = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
struct ethhdr *eth = (struct ethhdr*)sendbuf;
struct sockaddr saddr;
struct sockaddr_ll sadr_ll;
int saddr_len = sizeof(saddr);
/*Get interface name*/
if(argc < 1) {
strcpy(ifName, argv[1]);
} else {
strcpy(ifName, DEFAULT_IF);
}
if(sock < 0) {
printf("Failed to create socket");
exit(1);
}
if(send_soc < -1) {
printf("Failed to create socket send");
exit(1);
}
/* Get the index of the interface to send on */
memset(&ifreq_i, 0, sizeof(struct ifreq));
strncpy(ifreq_i.ifr_name, ifName, IFNAMSIZ-1);
if((ioctl(send_soc, SIOCGIFINDEX, (void*)&ifreq_i)) < 0){
printf("Error in index ioctl reading %s\n", strerror(errno));
close(send_soc);
exit(EXIT_FAILURE);
}
/*Get the mac address of the interface*/
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, ifName, IFNAMSIZ-1);
if((ioctl(send_soc, SIOCGIFHWADDR, &if_mac)) <0){
printf("Error in SIOCGIFHWADDR ioctl reading %s\n", strerror(errno));
close(send_soc);
exit(EXIT_FAILURE);
}
/*Get the ip address of the interface"
memset(&ifreq_ip, 0, sizeof(struct ifreq));
strncpy(ifreq_ip.ifr_name, ifName, IFNAMSIZ-1);
if((ioctl(send_soc, SIOCGIFADDR, &ifreq_ip)) <0)
printf("error in SIOCGIFADDR ip address reading\n");*/
while (1) {
packet_size = recvfrom(sock, buffer, 65536, 0, &saddr, (socklen_t*)&saddr_len);
if(packet_size == -1) {
printf("Failed to get packets\n");
return 1;
} else {
printf("Received packets");
}
// struct iphdr *ip_packet = (struct iphdr*)buffer;
// memset(&src_socket_address, 0, sizeof(src_socket_address));
// src_socket_address.sin_addr.s_addr = ip_packet->saddr;
// memset(&dest_socket_address, 0, sizeof(dest_socket_address));
// dest_socket_address.sin_addr.s_addr = ip_packet->daddr;
memset(sendbuf, 0, BUF_SIZE);
/*Construct ethernet header*/
eth->h_source[0] = (unsigned char)(if_mac.ifr_hwaddr.sa_data[0]);
eth->h_source[1] = (unsigned char)(if_mac.ifr_hwaddr.sa_data[1]);
eth->h_source[2] = (unsigned char)(if_mac.ifr_hwaddr.sa_data[2]);
eth->h_source[3] = (unsigned char)(if_mac.ifr_hwaddr.sa_data[3]);
eth->h_source[4] = (unsigned char)(if_mac.ifr_hwaddr.sa_data[4]);
eth->h_source[5] = (unsigned char)(if_mac.ifr_hwaddr.sa_data[5]);
/*filling destination mac address*/
eth->h_dest[0] = DESTMAC0;
eth->h_dest[1] = DESTMAC1;
eth->h_dest[2] = DESTMAC2;
eth->h_dest[3] = DESTMAC3;
eth->h_dest[4] = DESTMAC4;
eth->h_dest[5] = DESTMAC5;
eth->h_proto = htons(ETH_P_IP);
/* end of ethernet header*/
tx_len += sizeof(struct ethhdr);
/*Packet data for dummy data*/
sendbuf[tx_len++] = 0xAA;
sendbuf[tx_len++] = 0xBB;
sendbuf[tx_len++] = 0xCC;
sendbuf[tx_len++] = 0xDD;
sendbuf[tx_len++] = 0xEE;
sadr_ll.sll_ifindex = ifreq_i.ifr_ifindex;
sadr_ll.sll_halen = ETH_ALEN;
sadr_ll.sll_addr[0] = DESTMAC0;
sadr_ll.sll_addr[1] = DESTMAC1;
sadr_ll.sll_addr[2] = DESTMAC2;
sadr_ll.sll_addr[3] = DESTMAC3;
sadr_ll.sll_addr[4] = DESTMAC4;
sadr_ll.sll_addr[5] = DESTMAC5;
/* Send Packet */
if (sendto(send_soc, buffer, packet_size, 0, (const struct sockaddr*)&sadr_ll, sizeof(struct sockaddr_ll)) < 0) {
printf("Sending packet failed\n");
close(send_soc);
} else {
printf("Sending packet successful");
}
printf("================================================\n");
}
close(send_soc);
return 0;
}
I want to receive ethernet packets using raw sockets and duplicate the packets to send to another port in the same machine to analyse the traffic. I can receive the packets however after a while I get an error while sending the packets as "No such device or address".
Can you please explain whats the problem here?
Thanks!
Nivetha

Epoll tcp server grinds to a halt when accepting connections

I'm trying to connect 10,000+ tcp clients to my tcp server below. After 1-5 seconds I'm able to get between 200 and 5000 clients connected before the code grinds to a halt and hangs without terminating. I cant find any further documentation on this and the gprof profiler isnt able to collect any data.
Server:
#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <netdb.h>
#include <errno.h>
#include <iostream>
#ifndef MAXEVENTS
#define MAXEVENTS 64
#endif
#ifndef TX_BUF_SIZE
#define TX_BUF_SIZE (65535)
#endif
#ifndef RX_BUF_SIZE
#define RX_BUF_SIZE (65535)
#endif
char buf[RX_BUF_SIZE];
void user_recv_handler(int efd, int fd, char * buf, int len)
{
int s = -1;
struct epoll_event ev;
ev.data.fd = fd;
ev.events = EPOLLOUT | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_MOD, fd, &ev);
//assert(s!=-1);
if(s==-1)
{
fprintf(stderr, "epoll out error.\n");
return;
}
}
struct addrinfo* tcpipv4_getaddrinfo(char* port)
{
struct addrinfo hints;
struct addrinfo *res;
int s;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_INET; // ipv4 addrs
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_PASSIVE;
s = getaddrinfo(NULL, port, &hints, &res);
//assert(s==0);
if (s)
{
fprintf(stderr, "failed to getaddrinfo: %s\n", gai_strerror(s));
return NULL;
}
return res;
}
struct addrinfo* tcpipv6_getaddrinfo(char* port)
{
struct addrinfo hints;
struct addrinfo *res;
int s;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_INET6; // ipv4 addrs
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_PASSIVE;
s = getaddrinfo(NULL, port, &hints, &res);
//assert(s==0);
if (s)
{
fprintf(stderr, "failed to getaddrinfo-ipv6: %s\n", gai_strerror(s));
return NULL;
}
return res;
}
int set_nonblock(int fd)
{
int flags = -1;
if(-1 == (flags = fcntl(fd, F_GETFL, 0)))
{
return -1;
}
flags |= O_NONBLOCK;
if( fcntl(fd, F_SETFL, flags) == -1 )
{
return -1;
}
return 0;
}
int tcpipv4_createfd_bind(struct addrinfo* rp)
{
int flags = -1;
int s;
// create socket
int sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
//assert(sfd!=-1);
if (sfd == -1)
{
fprintf(stderr, "failed to create socket\n");
return -1;
}
// bind
s = bind(sfd, rp->ai_addr, rp->ai_addrlen);
//assert(s==0);
if(s!=0)
{
fprintf(stderr, "failed to bind socket %d\n", sfd);
return -1;
}
// nonblock
s = set_nonblock(sfd);
//assert(s != -1);
if (s == -1)
{
fprintf(stderr, "failed to set nonblocking socket %d\n", sfd);
return -1;
}
return sfd;
}
int writen(int fd, char * buf, size_t len)
{
char * cur = buf;
int n = -1;
while(len>0)
{
n = write(fd, cur, len);
if (n<=0)
{
if(errno == EINTR) continue;
else return -1;
}
len -= n;
cur += n;
}
return 0;
}
int readn(int fd, char* buf, size_t len)
{
char *cur = buf;
int n = -1;
while (len>0)
{
n = read(fd, cur, len);
if (n == -1)
{
if (errno == EINTR)
continue;
else break;
}
else if (n == 0)
break;
cur += n; len -= n;
}
return (int)(cur-buf);
}
void accept_handler(int efd, int listenfd)
{
struct epoll_event event;
int s;
while(1)
{
struct sockaddr in_addr;
socklen_t in_addrlen = sizeof(struct sockaddr);
int infd = -1;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
infd = accept(listenfd, &in_addr, &in_addrlen);
//assert(infd != -1);
if(infd == -1)
{
if(errno == EAGAIN || errno == EWOULDBLOCK)
;
else
perror("failed to accept\n");
return;
}
s = getnameinfo(&in_addr, in_addrlen,
hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf),
NI_NUMERICHOST | NI_NUMERICSERV);
//assert(s == 0);
if(s == 0)
{
printf("Accept fd %d host %s port %s\n", infd, hbuf, sbuf);
s = set_nonblock(infd);
//assert(s!=-1);
event.data.fd = infd;
event.events = EPOLLIN | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_ADD, infd, &event);
//assert(s != -1);
return;
}
}
return;
}
void read_handler(int efd, int fd)
{
//do sonething with buf.
int s = -1;
s=readn(fd, buf, sizeof(buf));
buf[s] = 0;
//printf("recv %d bytes: %s", s, buf);
if(s < 0)
{
close(fd);
if(-1 == epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL) )
fprintf(stderr, "failed to del event of %d\n", fd);
printf("close conection on fd %d", fd);
}
else if(s > 0)
{
//std::cout << buf << std::endl;
//do sonething with buf.
user_recv_handler(efd, fd, buf, s);
}
}
void write_handler(int efd, int fd)
{
writen(fd, buf, strlen(buf));
if(-1 == epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL) )
fprintf(stderr, "failed to del event of %d\n", fd);
// close(fd);
}
int main(int argc, char ** argv)
{
char* port = NULL;
int listenfd = -1;
struct addrinfo* hostaddr=NULL;
struct addrinfo* rp = NULL;
struct epoll_event event;
struct epoll_event * events, *cur_ev;
int efd = -1;
int num_ev = -1;
int s;
port = argv[1];
// get server ipv4 address by getaddrinfo
(rp = hostaddr = tcpipv4_getaddrinfo(port));
// create and bind listening socket
for(; rp; rp = rp->ai_next)
{
(listenfd = tcpipv4_createfd_bind(rp));
if(-1 == listenfd)
continue;
}
freeaddrinfo(hostaddr);
//assert(listenfd!=-1);
if(listenfd==-1)
exit(EXIT_FAILURE);
//start listening
(s = listen(listenfd, SOMAXCONN));
//assert(s!=-1);
if(s == -1)
exit(EXIT_FAILURE);
// create epoll
efd = epoll_create(MAXEVENTS);
//assert(efd != -1);
if(efd == -1)
exit(EXIT_FAILURE);
event.data.fd = listenfd;
// epoll: read, ET
event.events = EPOLLIN | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &event);
//assert(s!=-1);
if(s==-1)
exit(EXIT_FAILURE);
events = (struct epoll_event*)calloc(MAXEVENTS, sizeof(struct epoll_event));
// event loop;
while (1)
{
num_ev = epoll_wait(efd, events, MAXEVENTS, -1);
// for each active event:
while(num_ev--)
{
cur_ev = events+num_ev;
// close the fd if error (ERR) or hang up (HUP)
if(cur_ev->events & EPOLLERR ||
cur_ev->events & EPOLLHUP)
{
fprintf(stderr, "epoll get event error\n");
close(cur_ev->data.fd);
continue;
}
// one or more new connections (fd = listenfd)
else if(cur_ev->data.fd == listenfd)
{
accept_handler(efd, listenfd);
continue;
}
else if(cur_ev->events & EPOLLIN)
{
// since the registered event is EPOLLIN,
// here we have data on fd waiting for reading.
read_handler(efd, cur_ev->data.fd);
}
else if (cur_ev->events & EPOLLOUT)
{
write_handler(efd, cur_ev->data.fd);
}
}
}
free(events); events = NULL;
close(listenfd);
exit(EXIT_SUCCESS);
}
Client:
int connected_count=0;
int i=0;
struct timespec tstart={0,0}, tend={0,0};
clock_gettime(CLOCK_MONOTONIC, &tstart);
for(; i!=10000; i++)
{
int sockfd;
int portno = 4000;
ssize_t n;
struct sockaddr_in serveraddr;
struct hostent* server;
char hostname[] = "127.0.0.1";
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
printf("ERROR opening socket");
printf("error %d",errno);
test_function_killall(NULL);
return;
}
server = gethostbyname(hostname);
if(server == NULL)
{
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
test_function_killall(NULL);
return;
}
bzero((char*)&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char*)server->h_addr, (char*)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
if(connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
{
printf("ERROR connecting");
test_function_killall(NULL);
return;
}
else
{
std::cout << "active connections " << connected_count++ << std::endl;
}
set_nonblock(sockfd);
}
if(connected_count==10000)
{
printf("complete");
}
Start with this:
Remove the EPOLLET flags from the listen socket registration. You
might want to remove it from the client connection sockets too.
Set your listen socket to non-blocking similar to how the client
connection sockets returned from accept are set.
There's all kinds of edge cases with the listen sockets. I'm not sure, but it appears you aren't fully draining the accept queue when epoll_ctl comes back to indicate that the listen socket has a connection ready. (Think: multiple incoming connections on one edge trigger). It's possible you are blocking on accept and/or stuck on epoll_wait.
Update:
Another thing you could be hitting are the system limits for the maximum number of files handles per process. Read up here.

TCP server hangs after first connection

i am implementing a simple TCP echo server, which writes back whatever is written to it.i use telnet to connect to it when i first send some data to it,it is sent back(expected) but after that it hangs on i assume as nothing is sent back.
here is my code (a little modified version of example in man getaddrinfo).is there any problem with how i recv() and send() below?
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#define MAX_LISTEN_BACKLOG 1
#define BUFFER_SIZE 4096
int main(int argc, char* argv[]){
char buf[BUFFER_SIZE];
int sfd,n,s;
struct addrinfo hints;
struct addrinfo *result;
struct addrinfo *rp;
struct sockaddr_storage peer_addr;
socklen_t peer_addr_len;
ssize_t nread;
int addr_info_error;
memset(&hints,0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
s = getaddrinfo(NULL, argv[1], &hints, &result);
if (s != 0){
printf("got error getaddrinfo");
}
for( rp = result; rp !=NULL; rp = rp->ai_next){
sfd = socket(rp->ai_family,rp->ai_socktype,rp->ai_protocol);
if (sfd == -1) perror("could not create socket");
if (bind(sfd,rp->ai_addr,rp->ai_addrlen) == 0 ) break;
close(sfd);
}
if (rp == NULL){
perror("could not bind");
}
freeaddrinfo(result);
int nsfd;
listen(sfd,100);
for(;;){
peer_addr_len = sizeof(struct sockaddr_storage);
nsfd = accept(sfd,(struct sockaddr*) &peer_addr_len,&peer_addr_len);
nread = recv(nsfd,buf,BUFFER_SIZE,0);
if(nread == -1)
continue;
printf("got ...%d",nread); // this line never prints?????
char host[NI_MAXHOST], service[NI_MAXSERV];
s = getnameinfo((struct sockaddr*) &peer_addr,
peer_addr_len,host,NI_MAXHOST,
service,NI_MAXSERV,NI_NUMERICSERV);
if (s == 0) printf("recieved %s bytes from host:%s port:%s",nread,host,service);
else printf("got %d in s",s);
if(send(nsfd,buf,nread,0) != nread)
perror("error sending response");
}
return 0;
}
[this text intended for people who cannot read the code]
Add an extra loop after accept() has succeeded. This loop finishes once the connection is terminated.
check errno after read() returns -1
diagnostic output should go to stderr, not stdout.
for(;;){
peer_addr_len = sizeof(struct sockaddr_storage);
nsfd = accept(sfd,(struct sockaddr*) &peer_addr_len,&peer_addr_len);
if (nsfd ==-1) {perror("error sending response"); break; }
for(;;) {
nread = recv(nsfd,buf,BUFFER_SIZE,0);
fprintf(stderr, "got ...%d",nread);
if(nread == -1){
if(errno==EAGAIN) continue;
else break;
}
if(nread == 0) break;
char host[NI_MAXHOST], service[NI_MAXSERV];
s = getnameinfo((struct sockaddr*) &peer_addr,
peer_addr_len,host,NI_MAXHOST,
service,NI_MAXSERV,NI_NUMERICSERV);
if (s == 0) fprintf(stderr
, "received %s bytes from host:%s port:%s\n"
, nread,host,service);
else fprintf(stderr, "got %d in s\n", s);
if(send(nsfd,buf,nread,0) != nread) {
perror("error sending response");
break;
}
}
close(nsfd);
}

Using select() for non-blocking sockets

I am trying to use the select function to have non-blocking i/o between a server and 1 client (no more) where the communication flows nicely (can send at any time and the other will receive without waiting to send). I found a tutorial with some code and tried to adapt it to mine. This is what I have -
Server
#define PORT "4950"
#define STDIN 0
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// 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(int agrc, char** argv) {
int status, sock, adrlen, new_sd;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd; // the max wait time for an event
int sel; // holds return value for select();
//socket infoS
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//allow reuse of port
int yes=1;
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
exit(1);
}
freeaddrinfo(servinfo);
//listen
if(listen(sock, 5) < 0) {
printf("\nListen error %m", errno);
exit(1);
}
their_addr_size = sizeof(their_addr);
//accept
new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size);
if( new_sd < 0) {
printf("\nAccept error %m", errno);
exit(1);
}
set_nonblock(new_sd);
cout<<"\nSuccessful Connection!";
char* in = new char[255];
char* out = new char[255];
int numSent;
int numRead;
while(1) {
waitd.tv_sec = 10;
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(new_sd, &read_flags);
if(strlen(out) != 0)
FD_SET(new_sd, &write_flags);
sel = select(new_sd+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(new_sd, &read_flags)) {
FD_CLR(new_sd, &read_flags);
memset(&in, 0, sizeof(in));
if(recv(new_sd, in, sizeof(in), 0) <= 0) {
close(new_sd);
break;
}
else
cout<<"\n"<<in;
} //end if ready for read
//socket ready for writing
if(FD_ISSET(new_sd, &write_flags)) {
FD_CLR(new_sd, &write_flags);
send(new_sd, out, strlen(out), 0);
memset(&out, 0, sizeof(out));
}
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
Client (basically the same just minus an accept call) -
#define PORT "4950"
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// 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(int agrc, char** argv) {
int status, sock, adrlen;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd; // the max wait time for an event
int sel; // holds return value for select();
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
if(connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nclient connection failure %m", errno);
exit(1);
}
cout<<"\nSuccessful connection!";
set_nonblock(sock);
char* out = new char[255];
char* in = new char[255];
int numRead;
int numSent;
while(1) {
waitd.tv_sec = 10;
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(sock, &read_flags);
if(strlen(out) != 0)
FD_SET(sock, &write_flags);
sel = select(sock+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(sock, &read_flags)) {
FD_CLR(sock, &read_flags);
memset(&in, 0, sizeof(in));
if(recv(sock, in, sizeof(in), 0) <= 0) {
close(sock);
break;
}
else
cout<<"\n"<<in;
} //end if ready for read
//socket ready for writing
if(FD_ISSET(sock, &write_flags)) {
FD_CLR(sock, &write_flags);
send(sock, out, strlen(out), 0);
memset(&out, 0, sizeof(out));
}
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
The problem is that when I run them, nothing happens. I can type into one and hit enter and nothing shows up on the other screen (and vice versa). Thats not a whole of information for me to debug and this is my first real attempt at using select so I thought maybe I am just unaware of something simple. If anything can be spotted as wrong or weird please point it out, any help is appreciated.
The problem is that when I run them, nothing happens.
The real problem is that people have been pasting stuff from Beej for years without understanding it. That's why I don't really like that guide; it gives large blocks of code without really explaining them in detail.
You're not reading anything and not sending anything; no fgets, scanf, cin, etc. Here's what I would do:
FD_SET(sock, &read_flags);
FD_SET(STDIN_FILENO, &read_flags);
/* .. snip .. */
if(FD_ISSET(STDIN_FILENO, &read_flags)) {
fgets(out, len, stdin);
}
This will monitor stdin and read from it when input is available; then, when the socket is writeable (FD_ISSET(sock, &write_flags)), it will send the buffer.
I have the program working correctly now.
server -
#define PORT "4950"
#define STDIN 0
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// 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(int agrc, char** argv) {
int status, sock, adrlen, new_sd;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd = {10, 0}; // the max wait time for an event
int sel; // holds return value for select();
//socket infoS
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//allow reuse of port
int yes=1;
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
exit(1);
}
freeaddrinfo(servinfo);
//listen
if(listen(sock, 5) < 0) {
printf("\nListen error %m", errno);
exit(1);
}
their_addr_size = sizeof(their_addr);
//accept
new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size);
if( new_sd < 0) {
printf("\nAccept error %m", errno);
exit(1);
}
//set non blocking
set_nonblock(new_sd);
cout<<"\nSuccessful Connection!\n";
char in[255];
char out[255];
memset(&in, 0, 255);
memset(&out, 0, 255);
int numSent;
int numRead;
while(1) {
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(new_sd, &read_flags);
FD_SET(new_sd, &write_flags);
FD_SET(STDIN_FILENO, &read_flags);
FD_SET(STDIN_FILENO, &write_flags);
sel = select(new_sd+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
//if an error with select
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(new_sd, &read_flags)) {
//clear set
FD_CLR(new_sd, &read_flags);
memset(&in, 0, 255);
numRead = recv(new_sd, in, 255, 0);
if(numRead <= 0) {
printf("\nClosing socket");
close(new_sd);
break;
}
else if(in[0] != '\0')
cout<<"\nClient: "<<in;
} //end if ready for read
//if stdin is ready to be read
if(FD_ISSET(STDIN_FILENO, &read_flags))
fgets(out, 255, stdin);
//socket ready for writing
if(FD_ISSET(new_sd, &write_flags)) {
//printf("\nSocket ready for write");
FD_CLR(new_sd, &write_flags);
send(new_sd, out, 255, 0);
memset(&out, 0, 255);
} //end if
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
The client is basically the same...only difference really is the lack of listen and accept.
I just want to add that above example may not work as expected on Linux. On Linux waitd may be modified by select. So for Linux, waitd should be rewritten before select.
See the "timeout" section in the man page for select.

Resources