socket communication between multiple machines - linux

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.

Related

IPv6 example program fails on connect()

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.

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?

UDP client doesn't connect with server

I create chat with clients and server. But the client can't connect to the server. Please tell me what is wrong?
Server code
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define BUFOR 512
int main(int argc, char *argv[])
{
int fd, serverLength, cLength;
struct sockaddr_in serverAddr, c_addr[2], clientAddr;
cLength = sizeof(clientAddr);
char buf[BUFOR];
int clients = 0;
int c_port[2];
if(argc != 2)
{
printf(" portu");
exit(1);
}
uint16_t port = atoi( argv[ 1 ] );
if ((fd = socket(AF_INET, SOCK_DGRAM, 0))==-1)
{
perror("Blad socket");
exit(1);
}
bzero((char*) &serverAddr, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(port);
serverLength = sizeof(serverAddr);
if (bind(fd, (struct sockaddr* ) &serverAddr, serverLength)==-1)
{
perror("Blad bind");
exit(1);
}
for(;;)
{
printf("Receiving...\n");
if (recvfrom(fd, buf, BUFOR, 0, (struct sockaddr*)&clientAddr, &cLength)==-1)
{
perror("Blad recvfrom");
exit(1);
}
if (clients==0)
{
c_addr[0] = clientAddr;
c_port[0] = ntohs(c_addr[0].sin_port);
clients++;
printf("Client 0 was connected. Port: %d\n",c_port[0]);
sendto(fd, "I am only one cleint.", 24, 0, (struct sockaddr*)&clientAddr, cLength);
}else if(clients==1)
{
if (c_port[0]==ntohs(clientAddr.sin_port))
{
sendto(fd, "I am only one client.", 24, 0, (struct sockaddr*)&c_addr[0], sizeof(c_addr[0]));
printf("One cleint\n");
}else
{
c_addr[1] = clientAddr;
c_port[1] = ntohs(c_addr[1].sin_port);
clients++;
printf("Second cleint\n");
sendto(fd, buf, BUFOR, 0, (struct sockaddr*)&c_addr[0], sizeof(c_addr[0]));
}
}else
{
if (c_port[0]==ntohs(clientAddr.sin_port))
{
printf("Sending emssage for client 1\n");
if (sendto(fd, buf, BUFOR, 0, (struct sockaddr*)&c_addr[1], sizeof(c_addr[0]))==-1)
{
clients--;
perror("Error senttoen");
}
}else
{
printf("Sending message for client 0\n");
if (sendto(fd, buf, BUFOR, 0, (struct sockaddr*)&c_addr[0], sizeof(c_addr[1]))==-1)
{
clients--;
perror("Blad senttoen");
}
}
}
}
close(fd);
return 0;
}
Client code
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>
#define BUFLEN 512
int main(int argc, char *argv[])
{
struct sockaddr_in serv_addr;
int sockfd;
socklen_t slen;
slen=sizeof(serv_addr);
char buf[BUFLEN];
if(argc != 3)
{
printf("Usage : %s <Server-IP>\n",argv[2]);
exit(0);
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
{
perror("Socket Error");
exit(1);
}
uint16_t port = atoi( argv[ 1 ] );
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = inet_addr(argv[2]);
while(1)
{
bzero(buf,BUFLEN);
printf("Attempting to READ to socket %d: ",sockfd);
fflush(stdout);
if(recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&serv_addr, &slen)==-1)
{
perror("Blad bind");
exit(1);
}
printf("The message from the server is: %s \n",buf);
printf("Please enter the message to send: ");
bzero(buf,BUFLEN);
fgets(buf,BUFLEN,stdin);
printf("Attempting to write to socket %d: ",sockfd);
fflush(stdout);
if (sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&serv_addr, slen)==-1)
{
perror("Blad bind");
exit(1);
}
}
close(sockfd);
return 0;
}
It seems the sendto is blocked by recvfrom, but I don't know how to create it in infinitable loop.

Unix Domain Sockets: accept() not setting sun_path

I am doing some testing with Unix domain sockets and I can communicate over them without an issue, however, when I call accept() on the server side of my test program, the returned struct sockaddr_un doesn't contain a sun_path.
I am pretty sure that Inet sockets have their address and port properly filled out after an accept() call, so am I doing something wrong in my test program or am I expecting the wrong outcome?
I am running CentOS 6.2 and gcc 4.4.6.
Sample Code:
server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NAME "socket"
int main(int argc, char **argv)
{
int sock, msgsock, rval;
struct sockaddr_un server, client;
char buf[1024];
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, NAME);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
perror("binding stream socket");
exit(1);
}
printf("Socket has name %s\n", server.sun_path);
listen(sock, 5);
for (;;) {
socklen_t len = sizeof(client);
msgsock = accept(sock, (struct sockaddr *)&client, &len);
if (msgsock == -1)
perror("accept");
else do {
printf("strlen(sun_path) = %zu\n", strlen(client.sun_path));
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
} while (rval > 0);
close(msgsock);
}
close(sock);
unlink(NAME);
return 0;
}
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define DATA "Half a league, half a league . . ."
int main(int argc, char **argv)
{
int sock;
struct sockaddr_un server;
if (argc < 2) {
printf("usage:%s <pathname>", argv[0]);
exit(1);
}
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, argv[1]);
if (connect(sock, (struct sockaddr *) &server,
sizeof(struct sockaddr_un)) < 0) {
close(sock);
perror("connecting stream socket");
exit(1);
}
if (write(sock, DATA, sizeof(DATA)) < 0)
perror("writing on stream socket");
close(sock);
return 0;
}
Just to reiterate the question:
Why isn't sun_path filled out after the accept() call on the server?
I am really not sure if this is an answer at all. Probably it's more like musings about some research, though maybe still worth while reading.
The value filled by accept(2) seems to be quite protocol agnostic at least in Linux 3.16.0, NetBSD 6.1.4 and Darwin 13.1.0 kernels. In practice this means that the second parameter to accept(2), struct sockaddr * gets filled only up to what is shared between all protocols. So what you have in your hands after a successful acccept(2) is far from being a complete struct sockaddr_un.
Probably nobody thought it would be of much importance at the time first implementations of accept(2) were done and now we're stuck with this. Fortunately there is a way around that, in case one has lost the pathname used for socket with call to bind(2), and would now like to find it again.
With struct sockaddr_storage and getsockname(2) the member sun_path is accessible. So, to make sure you are getting all juicy details, call getsockname(2) after a successful call to accept(2) (this would be put after line number 40 in your server.c):
struct sockaddr_storage ss;
socklen_t sslen = sizeof(struct sockaddr_storage);
if (getsockname(msgsock, (struct sockaddr *)&ss, &sslen) == 0) {
struct sockaddr_un *un = (struct sockaddr_un *)&ss;
printf("socket name is: %s\n", un->sun_path);
}
Or just use this:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NAME "socket"
int main(int argc, char **argv)
{
int sock, msgsock, rval;
struct sockaddr_un server, client;
char buf[1024];
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, NAME);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
perror("binding stream socket");
exit(1);
}
printf("Socket has name %s\n", server.sun_path);
listen(sock, 5);
for (;;) {
socklen_t len = sizeof(client);
msgsock = accept(sock, (struct sockaddr *)&client, &len);
if (msgsock == -1)
perror("accept");
else do {
printf("strlen(sun_path) = %zu\n", strlen(client.sun_path));
struct sockaddr_storage ss;
socklen_t sslen = sizeof(struct sockaddr_storage);
if (getsockname(msgsock, (struct sockaddr *)&ss, &sslen) == 0) {
struct sockaddr_un *un = (struct sockaddr_un *)&ss;
printf("socket name is: %s\n", un->sun_path);
}
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
} while (rval > 0);
close(msgsock);
}
close(sock);
unlink(NAME);
return 0;
}
This has been tested, ie. it compiles and produces expected results, to work on a GNU/Linux system running kernel 3.16.0, a NetBSD system running 6.1.4 kernel, and a system equipped with OS/X Mavericks, running 13.1.0 kernel. In all of these behaviour of accept(2) is consistent: sun_path is nowhere to be found in the structure filled. The behaviour of getsockname(2) is consistent between different operating environments too, making all protocol specific details available.
You haven't bound your client socket to an address.
You don't need to bind your client socket to an address for connect() to work; but, if you expect to access your client address in your server, then you do have to bind().
Make sense?
Just setup a call to bind() before you connect in your client. Make sure you the path you use for you client is valid and check for errors as normal.

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