IPv6 example program fails on connect() - linux

IPv6 example program fails on connect()
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <ctype.h>
void error(const char * es)
{
fprintf(stderr, "Error: %s\n", es);
exit(1);
}
struct sockaddr * getadr(char * name)
{
struct addrinfo * p;
int r;
struct sockaddr_in6 * sap;
unsigned long long addrl, addrh;
printf("getadr: begin\n");
r = getaddrinfo(name, NULL, NULL, & p);
if (r) error(gai_strerror(r));
sap = NULL;
while (p && !sap) {
/* traverse the available addresses */
if (p - > ai_family == AF_INET6 && p - > ai_socktype == SOCK_STREAM) {
/* get the IPv6 address */
sap = (struct sockaddr_in6 * ) p - > ai_addr;
}
p = p - > ai_next;
}
if (!sap) error("No address found");
addrh = (unsigned long long) ntohl(sap - > sin6_addr.__in6_u.__u6_addr32[0]) << 32 |
(unsigned long long) ntohl(sap - > sin6_addr.__in6_u.__u6_addr32[1]);
addrl = (unsigned long long) ntohl(sap - > sin6_addr.__in6_u.__u6_addr32[2]) << 32 |
(unsigned long long) ntohl(sap - > sin6_addr.__in6_u.__u6_addr32[3]);
printf("Address: %llx:%llx:%llx:%llx:%llx:%llx:%llx:%llx\n",
addrh >> 48 & 0xffff, addrh >> 32 & 0xffff, addrh >> 16 & 0xffff, addrh & 0xffff,
addrl >> 48 & 0xffff, addrl >> 32 & 0xffff, addrl >> 16 & 0xffff, addrl & 0xffff);
printf("getadr: end\n");
return ((struct sockaddr * ) sap);
}
int main(int argc, char * argv[]) {
int sockfd = 0, n = 0;
char buff[1024];
struct sockaddr_in6 serv_addr;
int r;
struct sockaddr * sap;
if (argc != 3) {
printf("Usage: socket <server> <page>\n");
exit(1);
}
if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
error("Could not create socket");
memset( & serv_addr, '0', sizeof(serv_addr));
serv_addr.sin6_family = AF_INET6;
serv_addr.sin6_port = htons(80);
printf("before address resolve\n");
if (isdigit(argv[1][0])) {
r = inet_pton(AF_INET6, argv[1], & serv_addr.sin6_addr);
if (r <= 0) error("inet_pton error occured");
} else {
sap = getadr(argv[1]);
memcpy( & serv_addr, sap, sizeof(struct sockaddr));
}
printf("after address resolve\n");
r = connect(sockfd, (struct sockaddr * ) & serv_addr, sizeof(serv_addr));
if (r < 0) error("Connect Failed");
printf("after connect\n");
/* send request */
sprintf(buff, "GET %s HTTP/1.1\r\n", argv[2]);
write(sockfd, buff, strlen(buff));
sprintf(buff, "Host: %s\r\n\r\n", "www.example.com" /*argv[1]*/ );
write(sockfd, buff, strlen(buff));
do {
r = read(sockfd, buff, sizeof(buff));
if (r > 0) {
buff[r] = 0;
printf("%s", buff);
}
} while (r);
return 0;
}
I arranged the server argument to be evaluated by inet_pton() if numeric, otherwise, it goes through getaddrinfo(). inet_pton() sets up the address and it works. getaddrinfo() does not, apparently, it dies in connect (hangs up). The example program is a simple web page fetch and print (not https). I used the www.example.com server to test it.
Note in the following example run that I use the same address getaddrinfo()gives me in a numeric example, then that works fine.
What am I doing wrong here?
The compile is simply gcc socket.c -o socket.
$ socket6 www.example.com /
before address resolve
getadr: begin
Address: 2606:2800:220:1:248:1893:25c8:1946
getadr: end
after address resolve
^C
(hangs up in connect, CTL-C out of it)
$ socket6 2606:2800:220:1:248:1893:25c8:1946 /
before address resolve
after address resolve
after connect
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
...
(prints the rest of the page)
I did find a similar post where they recommend adding the interface name to the server name, like www.example.com%enp2s0, but that was just rejected as invalid by getaddrinfo().

The main problem is that you are not populating serv_addr correctly.
When calling getadr(), your call to memcpy() for the result does not copy enough bytes for a complete sockaddr_in6 (sizeof(sockaddr) is less thansizeof(sockaddr_in6)). Also, you are not askinggetaddrinfo()to output a port number, so thesin6_port` of the result will not be 80 as you are expecting.
That is why connect() fails when you use getaddrinfo() instead of inet_pton().
There are other problems with your code, too.
When using memset(), you need to use an integer 0 rather than a character '0'. They are not the same value. Unused sockaddr_in6 fields need to be zeroed out properly.
Your getadr() function leaks memory, and it is inefficient in general. Use the hints parameter of getaddrinfo() to limit the results it outputs so you don't have to go hunting for them. And you need to free the output with freeaddrinfo() when you are done using it.
isdigit() is not the correct way to differentiate a numeric IP from a hostname. And besides, you don't really need to do this differentiation manually, as getaddrinfo() can parse a numeric IP string. But if you do differentiate manually, call inet_pton() unconditionally and then call getaddrinfo() if inet_pton() fails.
With that said, try something more like this instead:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <ctype.h>
void error(const char* es)
{
fprintf(stderr, "Error: %s\n", es);
exit(1);
}
void getadr(const char* name, struct in6_addr *addr)
{
struct addrinfo hints, *p;
int r;
struct sockaddr_in6 *sap;
char addrstr[INET6_ADDRSTRLEN];
printf("getadr: begin\n");
/*
r = inet_pton(AF_INET6, name, addr);
if (r == 1)
{
printf("getadr: end\n")
return;
}
*/
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
r = getaddrinfo(name, NULL, &hints, &p);
if (r != 0)
error(gai_strerror(r));
sap = (struct sockaddr_in6*)p->ai_addr;
memcpy(addr, &(sap->sin6_addr), sizeof(*addr));
freeaddrinfo(p);
printf("Address: %s\n", inet_ntop(AF_INET6, addr, addrstr, sizeof(addrstr)));
printf("getadr: end\n");
}
int main(int argc, char *argv[])
{
int sockfd, r;
char buff[1024];
struct sockaddr_in6 serv_addr;
if (argc != 3)
{
printf("Usage: socket <server> <page>\n");
exit(1);
}
sockfd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0)
error("Could not create socket");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin6_family = AF_INET6;
serv_addr.sin6_port = htons(80);
printf("before address resolve\n");
getadr(argv[1], &(serv_addr.sin6_addr));
printf("after address resolve\n");
r = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (r < 0)
error("Connect Failed");
printf("after connect\n");
/* send request */
sprintf(buff, "GET %s HTTP/1.1\r\n", argv[2]);
write(sockfd, buff, strlen(buff));
sprintf(buff, "Host: %s\r\n", argv[1]);
write(sockfd, buff, strlen(buff));
sprintf(buff, "%s", "Connection: close\r\n\r\n");
write(sockfd, buff, strlen(buff));
do
{
r = read(sockfd, buff, sizeof(buff));
if (r <= 0) break;
printf("%.*s", r, buff);
}
while (true);
close(sockfd);
return 0;
}
That said, getaddrinfo() outputs a linked list of IP addresses. It is possible for a hostname to resolve to multiple IPs, not all of which may be reachable from your machine. You should loop through the entire list connect()'ing to each IP until one of them succeeds or the list is exhausted. For example:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <ctype.h>
void error(const char* es)
{
fprintf(stderr, "Error: %s\n", es);
exit(1);
}
struct addrinfo* getadrs(const char* name, const char* port)
{
struct addrinfo hints, *p;
int r;
printf("getadr: begin\n");
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6 /*AF_UNSPEC*/;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
r = getaddrinfo(name, port, &hints, &p);
if (r != 0)
error(gai_strerror(r));
printf("getadr: end\n");
return p;
}
void* adrptr(struct sockaddr* addr)
{
switch (addr->sa_family)
{
case AF_INET:
return &(((struct sockaddr_in*)addr)->sin_addr);
case AF_INET6:
return &(((struct sockaddr_in6*)addr)->sin6_addr);
}
return NULL;
}
int main(int argc, char *argv[])
{
int sockfd = -1, r;
char buff[1024], addrstr[INET6_ADDRSTRLEN];
struct addrinfo *serv_addrs, *addr;
if (argc != 3)
{
printf("Usage: socket <server> <page>\n");
exit(1);
}
printf("before address resolve\n");
serv_addrs = getadrs(argv[1], "80");
printf("after address resolve\n");
for(addr = serv_addrs; addr != NULL; addr = addr->ai_next)
{
sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (sockfd < 0)
error("Could not create socket");
printf("Address: %s\n", inet_ntop(addr->ai_family, adrptr(addr->ai_addr), addrstr, sizeof(addrstr)));
r = connect(sockfd, addr->ai_addr, addr->ai_addrlen);
if (r == 0) break;
close(sockfd);
sockfd = -1;
}
if (sockfd < 0)
error("Connect Failed");
printf("after connect\n");
/* send request */
sprintf(buff, "GET %s HTTP/1.1\r\n", argv[2]);
write(sockfd, buff, strlen(buff));
sprintf(buff, "Host: %s\r\n", argv[1]);
write(sockfd, buff, strlen(buff));
sprintf(buff, "%s", "Connection: close\r\n\r\n");
write(sockfd, buff, strlen(buff));
do
{
r = read(sockfd, buff, sizeof(buff));
if (r <= 0) break;
printf("%.*s", r, buff);
}
while (true);
close(sockfd);
return 0;
}

Refactored code:
/*
* Socket.c program taken from the sockets example for linux
* and refactored for IPv6.
*/
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <ctype.h>
void error(const char* es)
{
fprintf(stderr, "Error: %s\n", es);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd = 0, n = 0;
char buff[1024];
struct sockaddr_in6 serv_addr;
int r;
struct sockaddr* sap;
struct addrinfo hints, *p;
if(argc != 3)
{
printf("Usage: socket <server> <page>\n");
exit(1);
}
if((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
error("Could not create socket");
/* resolve address */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
r = getaddrinfo(argv[1], "80", &hints, &p);
if (r != 0) error(gai_strerror(r));
memcpy(&serv_addr, (struct sockaddr_in6*)p->ai_addr, sizeof(struct sockaddr_in6));
freeaddrinfo(p);
/* connect to server */
r = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (r < 0) error("Connect Failed");
/* send request */
sprintf(buff, "GET %s HTTP/1.1\r\n", argv[2]);
write(sockfd, buff, strlen(buff));
sprintf(buff, "Host: %s\r\n\r\n", "www.example.com" /*argv[1]*/);
write(sockfd, buff, strlen(buff));
do {
r = read(sockfd, buff, sizeof(buff));
if (r > 0) {
buff[r] = 0;
printf("%s", buff);
}
} while (r);
return 0;
}
The run is now:
$ addr www.example.com
Addresses for host: www.example.com
Address: type: AF_INET6 Socket type: SOCK_STREAM Address: 2606:2800:220:1:248:1893:25c8:1946
Address: type: AF_INET6 Socket type: SOCK_DGRAM Address: 2606:2800:220:1:248:1893:25c8:1946
Address: type: AF_INET6 Socket type: SOCK_RAW Address: 2606:2800:220:1:248:1893:25c8:1946
Address: type: AF_INET Socket type: SOCK_STREAM Address: 93.184.216.34
Address: type: AF_INET Socket type: SOCK_DGRAM Address: 93.184.216.34
Address: type: AF_INET Socket type: SOCK_RAW Address: 93.184.216.34
$ socket6 www.example.com /
HTTP/1.1 200 OK
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Sun, 27 Oct 2019 17:50:10 GMT
...
(full page)
$ socket6 2606:2800:220:1:248:1893:25c8:1946 /
HTTP/1.1 200 OK
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Sun, 27 Oct 2019 17:50:21 GMT
...
(full page)
I'll have to put some thought into what you said about not all of the far addresses being valid, I wasn't aware of that.

Related

socket communication between multiple machines

I am trying to make communication between raspberry pi 4 and my ubuntu machine using socket programming. When i run them in same machine it works fine. But when i do it in different machine it shows error saying : no such host. Here is the server.c
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
}
Here is the client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
close(sockfd);
return 0;
}
To run the server i use the cmd: ./server 8081 and to run the client i used:
./client raspberrypi 8081
after which the error is showing. when i do the same in laptop it works fine. i checked the hostname is also correct.
no such host means the computer cannot resolve the hostname (raspberrypi) to a IP address (typically using DNS).
Assuming the server is the Rasberry Pi, add the following line to the file /etc/hosts on your client
192.168.0.5 rasberrypi
Replacing 192.168.0.5 with the IP address of your raspberrypi.

Time the connect syscall

I would like to see how much time it takes for connect syscall. I get the code for a simple TCP client. However, the program will wait for the server to respond after connect. How can I make it return right after syscall or using some other ways to time the syscall time?
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]) {
int sockfd = 0, n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
if(argc != 2) {
printf("\n Usage: %s <ip of server> \n",argv[0]);
return 1;
}
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Error : Could not create socket \n");
return 1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0) {
printf("\n inet_pton error occured\n");
return 1;
}
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\n Error : Connect Failed \n");
return 1;
}
printf("\nhello\n");
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0) {
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF) {
printf("\n Error : Fputs error\n");
}
}
if(n < 0)
{
printf("\n Read error \n");
}
return 0;
}
However, the program will wait for the server to respond after connect.
Yes, and it does so here:
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0) {
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF) {
printf("\n Error : Fputs error\n");
}
}
How can I make it return right after syscall
Err, remove the receive loop above?

Net Link Linux User code bind socket call always fail for multicast group Id (non zero value)

Hi am trying to implement net link user code and kernel code every thing works fine for unicast (src_addr.nl_groups = 0;). For mulicast, user code bind call always fails for non zero src_addr.nl_groups value. Really am not sure what value to put for multicast and how to proceed further. I checked the usage of netlink_broadcast in kernel source tree, so I put the same group Id value (RTMGRP_LINK) here. For unicast I found good number of help in internet but for multicast I don't think so . So Please help me to proceed further.
Error am getting is:
bind: No such file or directory
./a.out: can't bind socket (3)and err : -1: No such file or directory
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdio.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#define NETLINK_TEST 28
#define GROUP_IB 1
#define MAX_PAYLOAD 1024
struct sockaddr_nl src_addr, dst_addr;
struct nlmsghdr *nlh = NULL;
struct msghdr msg;
struct iovec iov;
int sock_fd;
int main(int argc, char ** argv)
{
int err;
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
if (sock_fd<0) {
char s[BUFSIZ];
sprintf( s, "%s: can't assign fd for socket", argv[0] );
perror(s);
return -1;
}
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups = 0; // Unicast
//src_addr.nl_groups = RTMGRP_LINK; /* Multicast, bind call always fails for non zero values */
err = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
perror("bind");
if (err<0) {
char s[BUFSIZ];
sprintf( s, "%s: can't bind socket (%d)and err : %d", argv[0], sock_fd,err );
perror(s);
return -1;
}
memset(&dst_addr, 0, sizeof(dst_addr));
nlh = (struct nlhmsghdr *) malloc(NLMSG_SPACE(MAX_PAYLOAD));
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov.iov_base = (void *)nlh;
iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
msg.msg_name = (void *)&dst_addr;
msg.msg_namelen = sizeof(dst_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
printf("pid : %d\n Waiting for messages from kernel...\n",getpid());
recvmsg(sock_fd, &msg, 0);
printf("Message : %s\n", NLMSG_DATA(nlh));
close(sock_fd);
return 0;
}
Netlink socket binds are sensitive to what USER you are- I've seen them reliably fail if you are not running the program in question as 'root', at least on RedHat 6.
Try running as root 1st, before changing your logic. If you get the same failure as you do in normal operation, then you know it isn't (necessarily) a permissions issue.
The issue is
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
Does you kernel module define the NETLINK_TEST family? your own family might must be supported at kernel module and it should post the message in the proper group using nlmsg_multicast()
RTMGRP_LINK is group defined in NETLINK_ROUTE.
This sample code is example for multicast
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#define MYPROTO NETLINK_USERSOCK
#define MYMGRP 21
int open_netlink(void)
{
int sock;
struct sockaddr_nl addr;
int group = MYMGRP;
sock = socket(AF_NETLINK, SOCK_RAW, MYPROTO);
if (sock < 0) {
printf("sock < 0.\n");
return sock;
}
memset((void *) &addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
/* addr.nl_groups = MYMGRP; */
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
printf("bind < 0.\n");
return -1;
}
if (setsockopt(sock, 270, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)) < 0) {
printf("setsockopt < 0\n");
return -1;
}
return sock;
}
void read_event(int sock)
{
struct sockaddr_nl nladdr;
struct msghdr msg;
struct iovec iov;
char buffer[65536];
int ret;
iov.iov_base = (void *) buffer;
iov.iov_len = sizeof(buffer);
msg.msg_name = (void *) &(nladdr);
msg.msg_namelen = sizeof(nladdr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
printf("Ok, listening.\n");
ret = recvmsg(sock, &msg, 0);
if (ret < 0)
printf("ret < 0.\n");
else
printf("Received message payload: %s\n", NLMSG_DATA((struct nlmsghdr *) &buffer));
}
int main(int argc, char *argv[])
{
int nls;
nls = open_netlink();
if (nls < 0)
return nls;
while (1)
read_event(nls);
return 0;
}
kernel module:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/netlink.h>
#include <net/net_namespace.h>
#define MYPROTO NETLINK_USERSOCK
#define MYGRP 21
static struct sock *nl_sk = NULL;
static void send_to_user(void)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
char *msg = "Hello from kernel";
int msg_size = strlen(msg) + 1;
int res;
pr_info("Creating skb.\n");
skb = nlmsg_new(NLMSG_ALIGN(msg_size + 1), GFP_KERNEL);
if (!skb) {
pr_err("Allocation failure.\n");
return;
}
nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, msg_size + 1, 0);
strcpy(nlmsg_data(nlh), msg);
pr_info("Sending skb.\n");
res = nlmsg_multicast(nl_sk, skb, 0, MYGRP, GFP_KERNEL);
if (res < 0)
pr_info("nlmsg_multicast() error: %d\n", res);
else
pr_info("Success.\n");
}
static int __init hello_init(void)
{
pr_info("Inserting hello module.\n");
nl_sk = netlink_kernel_create(&init_net, MYPROTO, NULL);
if (!nl_sk) {
pr_err("Error creating socket.\n");
return -10;
}
send_to_user();
netlink_kernel_release(nl_sk);
return 0;
}
static void __exit hello_exit(void)
{
pr_info("Exiting hello module.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

Can't read any data when connecting to Redis

I have the following code with connects to Redis running locally on port 6379. The problem is that can't read any output, the reader thread just blocks on recvfrom(). Everything works fine with an echo server for example, but not with Redis.
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
struct sockaddr_in servAddr;
int sock;
/* Reader loop */
void *readerf(void *n) {
char buffer[128];
int bytesRcvd;
while((bytesRcvd = recvfrom(sock, buffer, 127, 0, NULL, 0)) > 0) {
printf("[%s]",buffer);
}
}
char *getk = "GET key\n";
char *setk = "SET key \"test\"\n";
void sendd(char *str) {
if (send(sock, str, strlen(str), 0) != strlen(str))
perror("Send error");
send(sock, "\0", 1, 0);
//printf("sent: [%s]",str);
}
int main(int argc, char *argv[]) {
int i = 1;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
return 1;
/* Construct the server address structure */
memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */
servAddr.sin_family = AF_INET; /* Internet address family */
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); /* Server IP address */
servAddr.sin_port = htons(6379); /* Server port */
if (connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr))<0)
perror("Could not connect");
sendd(getk);
sendd(setk);
sendd(getk);
pthread_t reader;
pthread_create(&reader, NULL, readerf, &i);
sleep(5);
close(sock);
return 0;
}
It seems like you are not properly implementing Redis' protocol: http://redis.io/topics/protocol
If you are seriously coding a client, and not just investigating/having fun consider hiredis: https://github.com/antirez/hiredis/

How to UDP Broadcast with C in Linux?

How to UDP Broadcast with C in Linux?
In many IP stack, such as Linux, this code does not work. Your socket must have broadcast permissions. Try this:
bcast_sock = socket(AF_INET, SOCK_DGRAM, 0);
int broadcastEnable=1;
int ret=setsockopt(bcast_sock, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
/* Add other code, sockaddr, sendto() etc. */
Unwind has it right, except you should use 'sendto'
Here is an example, that assumes you already have a socket. It was taken from clamav
static void
broadcast(const char *mess)
{
#define BROADCAST_PORT 30000u
struct sockaddr_in s;
int broadcastSock = socket(AF_INET, SOCK_DGRAM, 0);
if(broadcastSock < 0)
return;
memset(&s, '\0', sizeof(struct sockaddr_in));
s.sin_family = AF_INET;
s.sin_port = htons(BROADCAST_PORT)
s.sin_addr.s_addr = INADDR_BROADCAST; /* This is not correct : htonl(INADDR_BROADCAST); */
cli_dbgmsg("broadcast %s to %d\n", mess, broadcastSock);
if(sendto(broadcastSock, mess, strlen(mess), 0, (struct sockaddr *)&s, sizeof(struct sockaddr_in)) < 0)
perror("sendto");
}
Typically using the Berkeley sockets API, to sendto() one or more datagrams to a known broadcast-class IP address.
I wrote udp multicast server recently for testing. To subscribe to multicast you would subscribe your client to Multicast group 225.0.0.37 port 12346 and port 12345 (2 feeds - one feeds sends "Hello, World!" the other one "Bye, Office!").
I've been using it for testing my client, both client and server run on the same box so there might be bits that may not work but give it a try first.
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define BYE_OFFICE 12346
#define HELLO_PORT 12345
#define HELLO_GROUP "225.0.0.37"
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
struct sockaddr_in addr2;
int fd;
int fd2;
char *message = "Hello, World!";
char *message2 = "Bye, Office!";
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
if ((fd2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
/* set up destination address */
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(HELLO_GROUP);
addr.sin_port=htons(HELLO_PORT);
memset(&addr2,0,sizeof(addr2));
addr2.sin_family = AF_INET;
addr2.sin_addr.s_addr = inet_addr(HELLO_GROUP);
addr2.sin_port=htons(BYE_OFFICE);
while (1)
{
if (sendto(fd, message, strlen(message), 0,(struct sockaddr *) &addr, sizeof(addr)) < 0)
{
perror("sendto");
exit(1);
}
sleep(3);
if (sendto(fd2, message2, strlen(message2), 0,(struct sockaddr *) &addr2, sizeof(addr2)) < 0)
{
perror("sendto2");
exit(1);
}
sleep(3);
}
}

Resources