From: mreed <mr...@us...> - 2006-07-17 15:25:18
|
Update of /cvsroot/ltp/ltp/testcases/network/stress/ns-tools In directory sc8-pr-cvs6.sourceforge.net:/tmp/cvs-serv20335 Added Files: ns-mcast.h ns-mcast_join.c ns-mcast_receiver.c Log Message: Adding files for Mitsuru's Chinen's nfs patch --- NEW FILE: ns-mcast_receiver.c --- /******************************************************************************/ /* */ /* Copyright (c) International Business Machines Corp., 2006 */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ /* the GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /* * File: * ns-mcast_receiver.c * * Description: * This is a multicast UDP datagram receiver * * Author: * Mitsuru Chinen <mi...@jp...> * * History: * Apr 19 2006 - Created (Mitsuru Chinen) *---------------------------------------------------------------------------*/ /* * Header Files */ #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <netdb.h> #include <signal.h> #include <time.h> #include <unistd.h> #include <net/if.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/types.h> #include "ns-mcast.h" #include "ns-traffic.h" /* * Structure Definitions */ struct mcast_rcv_info { struct addrinfo *mainfo; struct group_req *greq; struct group_filter *gsf; double timeout; }; /* * Gloval variables */ char *program_name; /* program name */ struct sigaction handler; /* Behavior for a signal */ int catch_sighup; /* When catch the SIGHUP, set to non-zero */ /* * Function: usage() * * Descripton: * Print the usage of this program. Then, terminate this program with * the specified exit value. * * Argument: * exit_value: exit value * * Return value: * This function does not return. */ void usage (char *program_name, int exit_value) { FILE *stream = stdout; /* stream where the usage is output */ if (exit_value == EXIT_FAILURE) stream = stderr; fprintf (stream, "%s [OPTION]\n" "\t-f num\ttprotocol family\n" "\t\t 4 : IPv4\n" "\t\t 6 : IPv6\n" "\t-I ifname\tname of listening interface\n" "\t-m addr\tmulticast address\n" "\t-F mode\tfilter mode\n" "\t\t include : include mode\n" "\t\t exclude : exclude mode\n" "\t-s addrs\tcomma separated array of Source Addresses\n" "\t-p num\tport number\n" "\t-t value\ttimeout [sec]\n" "\t-b\t\twork in the background\n" "\t-d\t\tdisplay debug informations\n" "\t-h\t\tdisplay this usage\n" , program_name); exit (exit_value); } /* * Function: set_signal_flag() * * Description: * This function sets global variables accordig to signal * * Argument: * type: type of signal * * Return value: * None */ void set_signal_flag(int type) { if (debug) fprintf(stderr, "Catch signal. type is %d\n", type); switch (type) { case SIGHUP: catch_sighup = 1; handler.sa_handler = SIG_IGN; if (sigaction(type, &handler, NULL) < 0) fatal_error("sigaction()"); break; default: fprintf(stderr, "Unexpected signal (%d) is caught\n", type); exit(EXIT_FAILURE); } } /* * Function: parse_options() * * Description: * This function parse the options * * Argument: * argc: the number of argument * argv: arguments * info_p: pointer to data of multicast receiver information * bg_p: pointer to the flag of working in backgrond * * Return value: * None */ void parse_options(int argc, char *argv[], struct mcast_rcv_info *info_p, int *bg_p) { int optc; /* option */ unsigned long opt_ul; /* option value in unsigned long */ double opt_d; /* option value in double */ uint32_t ifindex = 0; /* interface index where listening multicast */ sa_family_t family = AF_UNSPEC; /* protocol family */ char *maddr; /* multicast address */ uint32_t fmode = 0; /* filter mode */ char *saddrs; /* comma separated array of source addresses */ char *portnum; /* listen port number in character string */ maddr = NULL; saddrs = NULL; portnum = NULL; while ((optc = getopt(argc, argv, "f:I:m:F:s:p:t:bdh")) != EOF ) { switch (optc) { case 'f': if (optarg[0] == '4') family = PF_INET; /* IPv4 */ else if (optarg[0] == '6') family = PF_INET6; /* IPv6 */ else { fprintf(stderr, "protocol family should be 4 or 6.\n"); usage(program_name, EXIT_FAILURE); } break; case 'I': ifindex = if_nametoindex(optarg); if (ifindex == 0) { fprintf(stderr, "specified interface is incorrect\n"); usage(program_name, EXIT_FAILURE); } break; case 'm': maddr = strdup(optarg); if (maddr == NULL) fatal_error("strdup()"); break; case 'F': if (strncmp(optarg, "exclude", 8) == 0) fmode = MCAST_EXCLUDE; else if (strncmp(optarg, "include", 8) == 0) fmode = MCAST_INCLUDE; else { fprintf(stderr, "specified filter mode is incorrect\n"); usage(program_name, EXIT_FAILURE); } break; case 's': saddrs = strdup(optarg); if (saddrs == NULL) fatal_error("strdup()"); break; case 'p': opt_ul = strtoul(optarg, NULL, 0); if (opt_ul < PORTNUMMIN || PORTNUMMAX < opt_ul) { fprintf(stderr, "The range of port is from %u to %u\n", PORTNUMMIN, PORTNUMMAX); usage(program_name, EXIT_FAILURE); } portnum = strdup(optarg); break; case 't': opt_d = strtod(optarg, NULL); if (opt_d < 0.0) { fprintf(stderr, "Timeout should be positive value\n"); usage(program_name, EXIT_FAILURE); } info_p->timeout = opt_d; break; case 'b': *bg_p = 1; break; case 'd': debug = 1; break; case 'h': usage(program_name, EXIT_SUCCESS); break; default: usage(program_name, EXIT_FAILURE); } } if (ifindex == 0) { fprintf(stderr, "specified interface seems incorrect\n"); usage(program_name, EXIT_FAILURE); } if (maddr == NULL) { fprintf(stderr, "multicast address is not specified\n"); usage(program_name, EXIT_FAILURE); } if (portnum == NULL) { fprintf(stderr, "listening port number is not specified\n"); usage(program_name, EXIT_FAILURE); } info_p->mainfo = get_maddrinfo(family, maddr, portnum); info_p->greq = create_group_info(ifindex, info_p->mainfo); if (saddrs) { if (fmode != MCAST_EXCLUDE && fmode != MCAST_INCLUDE) { fprintf(stderr, "filter mode is wrong\n"); usage(program_name, EXIT_FAILURE); } info_p->gsf = create_source_filter(ifindex, info_p->mainfo, fmode, saddrs); } if (maddr) free(maddr); if (saddrs) free(saddrs); if (portnum) free(portnum); } /* * Function: create_mcast_socket() * * Description: * This function creates a socket to receive multicast datagrams * * Argument: * info_p: pointer to data of multicast receiver information * * Return value: * file descriptor referencing the socket */ int create_mcast_socket(struct mcast_rcv_info *info_p) { int sd; /* socket file descriptor */ int level; /* protocol levels */ int on; /* flag for setsockopt */ switch (info_p->mainfo->ai_family) { case PF_INET: level = IPPROTO_IP; break; case PF_INET6: level = IPPROTO_IPV6; break; default: level = 0; fprintf(stderr, "Unknown protocol level %d\n", level); exit(EXIT_FAILURE); break; } /* Create a socket */ sd = socket(info_p->mainfo->ai_family, info_p->mainfo->ai_socktype, info_p->mainfo->ai_protocol); if (sd < 0) fatal_error("socket()"); /* Bind to the multicast address */ if (bind(sd, info_p->mainfo->ai_addr, info_p->mainfo->ai_addrlen) < 0) fatal_error("bind()"); /* Enable to reuse the socket */ on = 1; if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int))) fatal_error("setsockopt(): failed to set reuse the socket"); /* Join the multicast group */ if (setsockopt(sd, level, MCAST_JOIN_GROUP, info_p->greq, sizeof(struct group_req))) fatal_error("setsockopt(): failed to join the multicast group"); /* Apply the source filter */ if (info_p->gsf) { if (setsockopt(sd, level, MCAST_MSFILTER, info_p->gsf, GROUP_FILTER_SIZE(info_p->gsf->gf_numsrc))) fatal_error("setsockopt(): failed to apply the source filter"); } return sd; } /* * Function: receive_mcast() * * Description: * This function receives multicast datagarms * * Argument: * info_p: pointer to data of multicast receiver information * * Return value: * None */ void receive_mcast(struct mcast_rcv_info *info_p) { int sd; char *msgbuf; /* Pointer to the message */ size_t msgbuf_size; /* size of msgbuf */ ssize_t msglen; /* the length of message */ socklen_t optlen; /* size of the result parameter */ double start_time; /* start time when receiving datagrams */ /* Create a socket */ sd = create_mcast_socket(info_p); /* Allocate a buffer to store the message */ optlen = sizeof(msgbuf_size); if (getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &msgbuf_size, &optlen) < 0) { perror("getsockopt()"); close(sd); exit(EXIT_FAILURE); } msgbuf = (char *)malloc(msgbuf_size + 1); if (msgbuf == NULL) { fprintf(stderr, "malloc() is failed.\n"); close(sd); exit(EXIT_FAILURE); } /* Set singal hander for SIGHUP */ handler.sa_handler = set_signal_flag; handler.sa_flags = 0; if (sigfillset(&handler.sa_mask) < 0) fatal_error("sigfillset()"); if (sigaction(SIGHUP, &handler, NULL) < 0) fatal_error("sigfillset()"); /* Receive the message */ start_time = time(NULL); for(;;) { struct sockaddr_storage addr; socklen_t addrlen; addrlen = sizeof(addr); msglen = recvfrom(sd, msgbuf, msgbuf_size,MSG_DONTWAIT, (struct sockaddr *)&addr, &addrlen); if (msglen < 0) { if (errno != EAGAIN) fatal_error("recvfrom()"); } else if (debug) fprintf(stderr, "received %d byte message\n", msglen); if (info_p->timeout) if (info_p->timeout < difftime(time(NULL), start_time)) break; if (catch_sighup) /* catch SIGHUP */ break; } close(sd); } /* * * Function: main() * */ int main(int argc, char *argv[]) { struct mcast_rcv_info mcast_rcv; int background = 0; debug = 0; program_name = strdup(argv[0]); memset(&mcast_rcv, '\0', sizeof(struct mcast_rcv_info)); parse_options(argc, argv, &mcast_rcv, &background); if (background) /* Work in the background */ if (daemon(0, 0) < 0) fatal_error("daemon()"); receive_mcast(&mcast_rcv); exit(EXIT_SUCCESS); } --- NEW FILE: ns-mcast.h --- /******************************************************************************/ /* */ /* Copyright (c) International Business Machines Corp., 2006 */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ /* the GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /* * File: * ns-mcast.h * * Description: * Header file for multicast test. * This file specifies structures and macors if missing * * Author: * Mitsuru Chinen <mi...@jp...> * * History: * Apr 21 2006 - Created (Mitsuru Chinen) *---------------------------------------------------------------------------*/ #ifndef _NS_MCAST_H #define _NS_MCAST_H 1 #include <netinet/in.h> #include <endian.h> #ifndef MLD_LISTENER_QUERY # define MLD_LISTENER_QUERY 130 #endif /* group_req */ #ifndef MCAST_JOIN_GROUP # define MCAST_JOIN_GROUP 42 # define MCAST_BLOCK_SOURCE 43 # define MCAST_UNBLOCK_SOURCE 44 # define MCAST_LEAVE_GROUP 45 struct group_req { uint32_t gr_interface; struct sockaddr_storage gr_group; }; #endif /* MCAST_JOIN_GROUP */ /* group_filter */ #ifndef MCAST_MSFILTER # define MCAST_MSFILTER 48 # define MCAST_EXCLUDE 0 # define MCAST_INCLUDE 1 struct group_filter { uint32_t gf_interface; struct sockaddr_storage gf_group; uint32_t gf_fmode; uint32_t gf_numsrc; struct sockaddr_storage gf_slist[1]; }; #define GROUP_FILTER_SIZE(numsrc) \ (sizeof(struct group_filter) - sizeof(struct sockaddr_storage) \ + (numsrc) * sizeof(struct sockaddr_storage)) #endif /* MCAST_MSFILTER */ #ifndef IGMP_ALL_HOSTS # define IGMP_ALL_HOSTS htonl(0xE0000001L) #endif #ifndef IGMPV3_HOST_MEMBERSHIP_REPORT struct igmpv3_query { uint8_t type; uint8_t code; uint16_t csum; uint32_t group; # if __BYTE_ORDER == __LITTLE_ENDIAN uint8_t qrv:3; uint8_t suppress:1; uint8_t resv:4; # elif __BYTE_ORDER == __BIG_ENDIAN uint8_t resv:4; uint8_t suppress:1; uint8_t qrv:3; # else # error "Failed to detect endian" #endif uint8_t qqic; uint16_t nsrcs; uint32_t srcs[0]; }; #endif /* IGMPV3_HOST_MEMBERSHIP_REPORT */ #endif /* _NS_MCAST_H */ --- NEW FILE: ns-mcast_join.c --- /******************************************************************************/ /* */ /* Copyright (c) International Business Machines Corp., 2006 */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ /* the GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /* * File: * ns-mcast_join.c * * Description: * This is an assistant tool to join multicast groups * * Author: * Mitsuru Chinen <mi...@jp...> * * History: * May 1 2006 - Created (Mitsuru Chinen) *---------------------------------------------------------------------------*/ /* * Header Files */ #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <netdb.h> #include <signal.h> #include <time.h> #include <unistd.h> #include <net/if.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/types.h> #include "ns-mcast.h" #include "ns-traffic.h" #define ADDR_STR_MAXSIZE 80 #define OPEN_SOCK_MIN 6 /* * Gloval variables */ char *program_name; /* program name */ struct sigaction handler; /* Behavior for a signal */ int catch_sighup; /* When catch the SIGHUP, set to non-zero */ sa_family_t family; /* protocol family */ int level; /* protocol levels */ uint32_t ifindex; /* interface index where listening multicast */ size_t num_group; /* Number of the groups */ char *mcast_prefix; /* Prefix of the multicast address */ uint32_t fmode; /* filter mode */ char *saddrs; /* comma separated array of source addresses */ int is_multi_socket; /* If non-zero, multi-socket mode */ size_t join_leave_times; /* If non-zero, join-leave mode */ /* the value is times of join/leave */ char *mcast_addr; /* multicast address to join/leave */ struct timespec interval; /* interval for join-leave mode */ /* * Function: usage() * * Descripton: * Print the usage of this program. Then, terminate this program with * the specified exit value. * * Argument: * exit_value: exit value * * Return value: * This function does not return. */ void usage (char *program_name, int exit_value) { FILE *stream = stdout; /* stream where the usage is output */ if (exit_value == EXIT_FAILURE) stream = stderr; fprintf (stream, "%s [OPTION]\n" "\t-f num\tprotocol family\n" "\t\t 4 : IPv4\n" "\t\t 6 : IPv6\n" "\t-I ifname\tname of listening interface\n" "\t-a addr\tmulticast address for join-leave mode\n" "\t-F mode\tfilter mode\n" "\t\t include : include mode\n" "\t\t exclude : exclude mode\n" "\t-s addrs\tcomma separated array of Source Addresses\n" "\t-d\t\tdisplay debug informations\n" "\t-h\t\tdisplay this usage\n" "\n" "\t[multiple join mode]\n" "\t -n num\tnumber of multicast address\n" "\t -p prefix\tprefix of the multicast address\n" "\t -m\t\tmultiple socket mode\n" "\t\t 4 : a.b(.x.y) - x y is defined automatically\n" "\t\t 6 : {prefix}::z - z is defined automatically\n" "\n" "\t[join-leave mode]\n" "\t -l times of join/leave\n" "\t -i nsec\tinterval for join-leave mode\n" , program_name); exit (exit_value); } /* * Function: set_signal_flag() * * Description: * This function sets global variables accordig to signal * * Argument: * type: type of signal * * Return value: * None */ void set_signal_flag(int type) { if (debug) fprintf(stderr, "Catch signal. type is %d\n", type); switch (type) { case SIGHUP: catch_sighup = 1; handler.sa_handler = SIG_IGN; if (sigaction(type, &handler, NULL) < 0) fatal_error("sigaction()"); break; default: fprintf(stderr, "Unexpected signal (%d) is caught\n", type); exit(EXIT_FAILURE); } } /* * Function: parse_options() * * Description: * This function parse the options * * Argument: * argc: the number of argument * argv: arguments * * Return value: * None */ void parse_options(int argc, char *argv[]) { int optc; /* option */ unsigned long opt_ul; /* option value in unsigned long */ while ((optc = getopt(argc, argv, "f:I:p:F:s:n:ml:i:a:dh")) != EOF ) { switch (optc) { case 'f': if (optarg[0] == '4') { family = PF_INET; /* IPv4 */ level = IPPROTO_IP; } else if (optarg[0] == '6') { family = PF_INET6; /* IPv6 */ level = IPPROTO_IPV6; } else { fprintf(stderr, "protocol family should be 4 or 6.\n"); usage(program_name, EXIT_FAILURE); } break; case 'I': ifindex = if_nametoindex(optarg); if (ifindex == 0) { fprintf(stderr, "specified interface is incorrect\n"); usage(program_name, EXIT_FAILURE); } break; case 'p': mcast_prefix = strdup(optarg); break; case 'F': if (strncmp(optarg, "exclude", 8) == 0) fmode = MCAST_EXCLUDE; else if (strncmp(optarg, "include", 8) == 0) fmode = MCAST_INCLUDE; else { fprintf(stderr, "specified filter mode is incorrect\n"); usage(program_name, EXIT_FAILURE); } break; case 'l': join_leave_times = strtoul(optarg, NULL, 0); break; case 'i': if (strtotimespec(optarg, &interval)) { fprintf(stderr, "Interval is something wrong\n"); usage(program_name, EXIT_FAILURE); } break; case 'a': mcast_addr = strdup(optarg); break; case 's': saddrs = strdup(optarg); if (saddrs == NULL) fatal_error("strdup()"); break; case 'n': opt_ul = strtoul(optarg, NULL, 0); if (opt_ul > 255 * 254) { fprintf(stderr, "The number of group shoud be less than %u\n", 255 * 254); usage(program_name, EXIT_FAILURE); } num_group = opt_ul; break; case 'm': is_multi_socket = 1; break; case 'd': debug = 1; break; case 'h': usage(program_name, EXIT_SUCCESS); break; default: usage(program_name, EXIT_FAILURE); } } if (ifindex == 0) { fprintf(stderr, "specified interface seems incorrect\n"); usage(program_name, EXIT_FAILURE); } if (saddrs) { if (fmode != MCAST_EXCLUDE && fmode != MCAST_INCLUDE) { fprintf(stderr, "filter mode is wrong\n"); usage(program_name, EXIT_FAILURE); } } } /* * Function: join_group() * * Description: * This function make sockets to join the groups * * Return value: * None */ void join_group(void) { int sd; /* socket file descriptor */ int *sock_array; /* socket descriptor array */ size_t num_sock; /* number of the socket */ char maddr[ADDR_STR_MAXSIZE]; /* multicast address in string */ int idx; struct addrinfo *maddr_info; struct group_req *grp_info; struct group_filter *gsf; if (! is_multi_socket) num_sock = 1; else num_sock = num_group; /* Allocate socket array */ sock_array = calloc(num_sock, sizeof(int)); if (sock_array == NULL) fatal_error("calloc()"); for (idx = 0; idx < num_sock; idx++) { sock_array[idx] = socket(family, SOCK_DGRAM, IPPROTO_UDP); if (sock_array[idx] < 0) { if (idx < OPEN_SOCK_MIN) fatal_error("socket()"); else { int j; /* Closed some sockets for daemon() */ for (j = 0; j < OPEN_SOCK_MIN; j++) close(sock_array[idx - 1 - j]); num_group = idx - j - 1; break; } } if (! is_multi_socket) maximize_sockbuf(sock_array[idx]); } sd = sock_array[0]; if (mcast_addr) { strncpy(maddr, mcast_addr, ADDR_STR_MAXSIZE); if (debug) fprintf(stderr, "multicast address is %s\n", maddr); } for(idx = 0; idx < num_group; idx++) { if (is_multi_socket) sd = sock_array[idx]; if (debug) fprintf(stderr, "socket: %d\n", sd); if (mcast_prefix) { switch (family) { case PF_INET: { unsigned int x, y; x = idx / 254; y = idx % 254 + 1; sprintf(maddr, "%s.%d.%d", mcast_prefix, x, y); } break; case PF_INET6: sprintf(maddr, "%s:%x", mcast_prefix, idx + 1); break; } if (debug) fprintf(stderr, "multicast address is %s\n", maddr); } maddr_info = get_maddrinfo(family, maddr, NULL); grp_info = create_group_info(ifindex, maddr_info); if (setsockopt(sd, level, MCAST_JOIN_GROUP, grp_info, sizeof(struct group_req)) == -1) { if (idx == 0) fatal_error("setsockopt(): Join no group"); else { num_group--; free(grp_info); freeaddrinfo(maddr_info); break; } free(grp_info); } if (saddrs) { gsf = create_source_filter(ifindex, maddr_info, fmode, saddrs); if (setsockopt(sd, level, MCAST_MSFILTER, gsf, GROUP_FILTER_SIZE(gsf->gf_numsrc)) == -1) { if (idx == 0) fatal_error("setsockopt(): Add no group filter"); else { num_group--; free(gsf); freeaddrinfo(maddr_info); break; } free(gsf); } } freeaddrinfo(maddr_info); } fprintf(stdout, "%u groups\n", num_group); fflush(stdout); /* Become a daemon for the next step in shell script */ if (daemon(0, 0) < 0) fatal_error("daemon()"); /* Waiting for SIGHUP */ handler.sa_handler = set_signal_flag; handler.sa_flags = 0; if (sigfillset(&handler.sa_mask) < 0) fatal_error("sigfillset()"); if (sigaction(SIGHUP, &handler, NULL) < 0) fatal_error("sigfillset()"); for(;;) if (catch_sighup) break; } /* * Function: join_leave_group() * * Description: * This function make sockets to join the groups then leave it * * Return value: * None */ void join_leave_group(void) { int sd; /* socket file descriptor */ struct addrinfo *maddr_info; struct group_req *grp_info; struct group_filter *gsf; size_t cnt; sd = socket(family, SOCK_DGRAM, IPPROTO_UDP); if (sd < 0) fatal_error("socket()"); maddr_info = get_maddrinfo(family, mcast_addr, NULL); grp_info = create_group_info(ifindex, maddr_info); if (saddrs) gsf = create_source_filter(ifindex, maddr_info, fmode, saddrs); else gsf=NULL; /* Waiting for SIGHUP */ handler.sa_handler = set_signal_flag; handler.sa_flags = 0; if (sigfillset(&handler.sa_mask) < 0) fatal_error("sigfillset()"); if (sigaction(SIGHUP, &handler, NULL) < 0) fatal_error("sigfillset()"); for(cnt = 0; cnt < join_leave_times ; cnt++) { /* Join */ if (setsockopt(sd, level, MCAST_JOIN_GROUP, grp_info, sizeof(struct group_req)) == -1) fatal_error("setsockopt(): Failed to join a group"); if(gsf) if (setsockopt(sd, level, MCAST_MSFILTER, gsf, GROUP_FILTER_SIZE(gsf->gf_numsrc)) == -1) fatal_error("setsockopt(): Failed to add a group filter"); nanosleep(&interval, NULL); /* Leave */ if (setsockopt(sd, level, MCAST_LEAVE_GROUP, grp_info, sizeof(struct group_req)) == -1) fatal_error("setsockopt(): Failed to leave a group"); nanosleep(&interval, NULL); if (catch_sighup) break; } free(grp_info); if(gsf) free(gsf); freeaddrinfo(maddr_info); } /* * * Function: main() * */ int main(int argc, char *argv[]) { debug = 0; program_name = strdup(argv[0]); parse_options(argc, argv); if (! join_leave_times) { if (mcast_prefix == NULL && mcast_addr == NULL) { fprintf(stderr, "multicast address is not specified\n"); usage(program_name, EXIT_FAILURE); } join_group(); } else { if (mcast_addr == NULL) { fprintf(stderr, "multicast address is not specified\n"); usage(program_name, EXIT_FAILURE); } join_leave_group(); } exit(EXIT_SUCCESS); } |