Multicast Daytime
Author: Eva M. Castro eva arroba gsyc.es |
First some useful functions that will be used in the multicast server/client examples are explained. The get_addr function returns a sockaddr_storage struct filled with a valid socket address struct for the address, service, family and socket type input parameters. The joinGroup function configures the socket with useful multicast options.
The file mcastutil.h defines the basic multicast socket interface. It defines the following functions:
get_addr fills the sockaddress_storage struct, addr, with information related to the hostname, service, family and socktype.
joinGroup specifies the address group to be used in the application. It configures the socket with some useful multicast options like loopBack and mcastHop.int get_addr (const char *hostname, const char *service, int family, int socktype, struct sockaddr_storage *addr);
isMulticast checks if an address is a valid multicast group.int joinGroup(int sockfd, int loopBack, int mcastHop, struct sockaddr_storage *addr);
File "mcastutil.cpp"int isMulticast(struct sockaddr_storage *addr);
The multicast server is similar to unicast server. It initializes the service, it stops the process (receivefrom) waiting for client connections and it answers immediately after any request.#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <time.h> #include "mcastutil.h" int get_addr (const char *hostname, const char *service, int family, int socktype, struct sockaddr_storage *addr) { struct addrinfo hints, *res, *ressave; int error, sockfd, retval; retval = -1; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = family; hints.ai_socktype = socktype; error = getaddrinfo(hostname, service, &hints, &res); if (error != 0) { fprintf(stderr, "getaddrinfo error:: [%s]\n", gai_strerror(error)); return retval; } ressave = res; sockfd=-1; while (res) { sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (!(sockfd < 0)) { if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0) { close(sockfd); memcpy(addr, res->ai_addr, sizeof(*addr); retval=0; break; } close(sockfd); sockfd=-1; } res=res->ai_next; } freeaddrinfo(ressave); return retval; } int joinGroup(int sockfd, int loopBack, int mcastTTL, struct sockaddr_storage *addr) { int r1, r2, r3, retval; retval=-1; switch (addr->ss_family) { case AF_INET: { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr= ((struct sockaddr_in *)addr)->sin_addr.s_addr; mreq.imr_interface.s_addr= INADDR_ANY; r1= setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loopBack, sizeof(loopBack)); if (r1<0) perror("joinGroup:: IP_MULTICAST_LOOP:: "); r2= setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)); if (r2<0) perror("joinGroup:: IP_MULTICAST_TTL:: "); r3= setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)); if (r3<0) perror("joinGroup:: IP_ADD_MEMBERSHIP:: "); } break; case AF_INET6: { struct ipv6_mreq mreq6; memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr)); mreq6.ipv6mr_interface= 0; // cualquier interfaz r1= setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loopBack, sizeof(loopBack)); if (r1<0) perror("joinGroup:: IPV6_MULTICAST_LOOP:: "); r2= setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)); if (r2<0) perror("joinGroup:: IPV6_MULTICAST_HOPS:: "); r3= setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)); if (r3<0) perror("joinGroup:: IPV6_ADD_MEMBERSHIP:: "); } break; default: r1=r2=r3=-1; } if ((r1>=0) && (r2>=0) && (r3>=0)) retval=0; return retval; } int isMulticast(struct sockaddr_storage *addr) { int retVal; retVal=-1; switch (addr->ss_family) { case AF_INET: { struct sockaddr_in *addr4=(struct sockaddr_in *)addr; retVal = IN_MULTICAST(ntohl(addr4->sin_addr.s_addr)); } break; case AF_INET6: { struct sockaddr_in6 *addr6=(struct sockaddr_in6 *)addr; retVal = IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr); } break; default: ; } return retVal; }
File "mcastserver.cpp"
The multicast client joins the multicast group and waits announcements received by the multicast group.#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <time.h> #include "mcastutil.h" const char *DAYTIME_PORT="13"; int main(int argc, char *argv[]) { int sockfd, n; char *mcastaddr; char timeStr[256]; char b[256]; struct sockaddr_storage clientaddr, addr; socklen_t addrlen; time_t now; char clienthost[NI_MAXHOST]; char clientservice[NI_MAXSERV]; mcastaddr = "FF01::1111"; if (argc ==2) mcastaddr=argv[1]; memset(&addr, 0, sizeof(addr)); if (get_addr(mcastaddr, DAYTIME_PORT, PF_UNSPEC, SOCK_DGRAM, &addr) <0) { fprintf(stderr, "get_addr error:: could not find multicast " "address=[%s] port=[%s]\n", mcastaddr, DAYTIME_PORT); return -1; } if (isMulticast(&addr)<0) { fprintf(stderr, "This address does not seem a multicast address [%s]\n", mcastaddr); return -1; } sockfd = socket(addr.ss_family, SOCK_DGRAM, 0); if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind error:: "); close(sockfd); return -1; } if (joinGroup(sockfd, 0 , 8, &addr) <0) { close(sockfd); return -1; } addrlen=sizeof(clientaddr); for ( ; ;) { n = recvfrom(sockfd, b, sizeof(b), 0, (struct sockaddr *)&clientaddr, &addrlen); if (n <0) continue; memset(clienthost, 0, sizeof(clienthost)); memset(clientservice, 0, sizeof(clientservice)); getnameinfo((struct sockaddr *)&clientaddr, addrlen, clienthost, sizeof(clienthost), clientservice, sizeof(clientservice), NI_NUMERICHOST); printf("Received request from host=[%s] port=[%s]\n", clienthost, clientservice); memset(timeStr, 0, sizeof(timeStr)); time(&now); sprintf(timeStr, "%s", ctime(&now)); n = sendto(sockfd, timeStr, sizeof(timeStr), 0, (struct sockaddr *)&addr, sizeof(addr)); if (n<1) perror("sendto error:: \n"); } return 0; }
File "mcastclient.cpp"
#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include "mcastutil.h" const char *DAYTIME_PORT="13"; int main(int argc, char *argv[]) { int sockfd, n; char *myhost; char timeStr[256]; char letter; struct sockaddr_storage addr, clientaddr; int addrlen; socklen_t clientaddrlen; myhost = "FF01::1111"; if (argc == 2) myhost=argv[1]; addrlen=sizeof(addr); memset(&addr, 0, addrlen); get_addr(myhost, DAYTIME_PORT, PF_UNSPEC, SOCK_DGRAM, &addr); sockfd = socket(addr.ss_family, SOCK_DGRAM, 0); if (bind(sockfd, (struct sockaddr *)&addr, addrlen) <0) { perror("bind error:: \n"); close(sockfd); return -1; } if (joinGroup(sockfd, 0 , 8, &addr) <0) { close(sockfd); return -1; } letter = '1'; n = sendto(sockfd, &letter, sizeof(letter), 0, (struct sockaddr *)&addr, addrlen); if (n<0) { perror("sendto error:: "); close(sockfd); return -1; } memset(timeStr, 0, sizeof(timeStr)); clientaddrlen=sizeof(clientaddr); n = recvfrom(sockfd, timeStr, sizeof(timeStr), 0, (struct sockaddr *)&clientaddr, &clientaddrlen); if (n<0) { perror("sendto error:: "); close(sockfd); return -1; } printf("%s\n", timeStr); close(sockfd); return 0; }
Author: Eva M. Castro eva arroba gsyc.es |