- added Jan's multicast support patch
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 3 May 2004 11:32:19 +0000 (11:32 +0000)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 3 May 2004 11:32:19 +0000 (11:32 +0000)
Makefile.defs
cfg.lex
cfg.y
globals.h
ip_addr.c
ip_addr.h
main.c
socket_info.c
udp_server.c

index 32c1937..44408d9 100644 (file)
@@ -278,6 +278,7 @@ DEFS+= $(extra_defs) \
         -DSHM_MEM  -DSHM_MMAP \
         -DDNS_IP_HACK \
         -DUSE_IPV6 \
+        -DUSE_MCAST \
         -DUSE_TCP \
         -DDISABLE_NAGLE \
         -DF_MALLOC \
diff --git a/cfg.lex b/cfg.lex
index a4aef1c..16d1d1d 100644 (file)
--- a/cfg.lex
+++ b/cfg.lex
@@ -210,6 +210,8 @@ ADVERTISED_ADDRESS  "advertised_address"
 ADVERTISED_PORT                "advertised_port"
 DISABLE_CORE           "disable_core_dump"
 OPEN_FD_LIMIT          "open_files_limit"
+MCAST_LOOPBACK         "mcast_loopback"
+MCAST_TTL                      "mcast_ttl"
 
 LOADMODULE     loadmodule
 MODPARAM        modparam
@@ -392,6 +394,10 @@ EAT_ABLE   [\ \t\b\r]
                                                                        return DISABLE_CORE; }
 <INITIAL>{OPEN_FD_LIMIT}               {       count(); yylval.strval=yytext;
                                                                        return OPEN_FD_LIMIT; }
+<INITIAL>{MCAST_LOOPBACK}              {       count(); yylval.strval=yytext;
+                                                                       return MCAST_LOOPBACK; }
+<INITIAL>{MCAST_TTL}           {       count(); yylval.strval=yytext;
+                                                                       return MCAST_TTL; }
 <INITIAL>{LOADMODULE}  { count(); yylval.strval=yytext; return LOADMODULE; }
 <INITIAL>{MODPARAM}     { count(); yylval.strval=yytext; return MODPARAM; }
 
diff --git a/cfg.y b/cfg.y
index 3dfabbc..bac3ed1 100644 (file)
--- a/cfg.y
+++ b/cfg.y
@@ -242,7 +242,7 @@ static struct id_list* mk_listen_id(char*, int, int);
 %token ADVERTISED_PORT
 %token DISABLE_CORE
 %token OPEN_FD_LIMIT
-
+%token MCAST_LOOPBACK
 
 
 
@@ -658,6 +658,15 @@ assign_stm:        DEBUG EQUAL NUMBER { debug=$3; }
                                                                                open_files_limit=$3;
                                                                        }
                | OPEN_FD_LIMIT EQUAL error { yyerror("number expected"); }
+               | MCAST_LOOPBACK EQUAL NUMBER {
+                                                               #ifdef USE_MCAST
+                                                                               mcast_loopback=$3;
+                                                               #else
+                                                                       warn("no multicast support compiled in");
+                                                               #endif
+                 }
+                | MCAST_LOOPBACK EQUAL error { yyerror("boolean value expected"); }
+
                | error EQUAL { yyerror("unknown config variable"); }
        ;
 
index 31c69d2..e076d0b 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -102,6 +102,10 @@ extern int sock_mode;
 extern char* chroot_dir;
 extern char* working_dir;
 
+#ifdef USE_MCAST
+extern int mcast_loopback;
+#endif /* USE_MCAST */
+
 /*
  * debug & log_stderr moved to dprint.h*/
 
index 2e4cb3e..100d432 100644 (file)
--- a/ip_addr.c
+++ b/ip_addr.c
@@ -160,3 +160,28 @@ void print_net(struct net* net)
        }
        print_ip("", &net->ip, "/"); print_ip("", &net->mask, "");
 }
+
+
+#ifdef USE_MCAST
+
+/* Returns 1 if the given address is a multicast address */
+int is_mcast(struct ip_addr* ip)
+{
+       if (!ip){
+               LOG(L_ERR, "ERROR: is_mcast: Invalid parameter value\n");
+               return -1;
+       }
+
+       if (ip->af==AF_INET){
+               return IN_MULTICAST(htonl(ip->u.addr32[0]));
+#ifdef USE_IPV6
+       } else if (ip->af==AF_INET6){
+               return IN6_IS_ADDR_MULTICAST(ip->u.addr);
+#endif /* USE_IPV6 */
+       } else {
+               LOG(L_ERR, "ERROR: is_mcast: Unsupported protocol family\n");
+               return -1;
+       }
+}
+
+#endif /* USE_MCAST */
index cb431d8..7e9a481 100644 (file)
--- a/ip_addr.h
+++ b/ip_addr.h
@@ -78,7 +78,7 @@ union sockaddr_union{
 
 
 
-enum si_flags { SI_NONE=0, SI_IS_IP=1, SI_IS_LO=2 };
+enum si_flags { SI_NONE=0, SI_IS_IP=1, SI_IS_LO=2, SI_IS_MCAST=4 };
 
 struct socket_info{
        int socket;
@@ -87,7 +87,7 @@ struct socket_info{
        str address_str;        /* ip address converted to string -- optimization*/
        unsigned short port_no;  /* port number */
        str port_no_str; /* port number converted to string -- optimization*/
-       enum si_flags flags; /* SI_IS_IP | SI_IS_LO */
+       enum si_flags flags; /* SI_IS_IP | SI_IS_LO | SI_IS_MCAST */
        union sockaddr_union su; 
        int proto; /* tcp or udp*/
        struct socket_info* next;
@@ -165,8 +165,10 @@ void print_ip(char* prefix, struct ip_addr* ip, char* suffix);
 void stdout_print_ip(struct ip_addr* ip);
 void print_net(struct net* net);
 
-
-
+#ifdef USE_MCAST
+/* Returns 1 if the given address is a multicast address */
+int is_mcast(struct ip_addr* ip);
+#endif /* USE_MCAST */
 
 /* returns 1 if ip & net.mask == net.ip ; 0 otherwise & -1 on error 
        [ diff. adress fams ]) */
diff --git a/main.c b/main.c
index ab9d96d..5ca1bdd 100644 (file)
--- a/main.c
+++ b/main.c
@@ -346,6 +346,10 @@ int open_files_limit=-1; /* don't touch it by default */
 */
 int reply_to_via=0;
 
+#ifdef USE_MCAST
+int mcast_loopback = 0;
+#endif /* USE_MCAST */
+
 #if 0
 char* names[MAX_LISTEN];              /* our names */
 int names_len[MAX_LISTEN];            /* lengths of the names*/
index 2570e54..22a6220 100644 (file)
@@ -472,9 +472,20 @@ static int fix_socket_list(struct socket_info **list)
                                                }
                                }
                }
+
+#ifdef USE_MCAST
+                    /* Check if it is an multicast address and
+                     * set the flag if so
+                     */
+               if (is_mcast(&si->address)) {
+                       si->flags |= SI_IS_MCAST;
+               }
+#endif /* USE_MCAST */
+
 #ifdef EXTRA_DEBUG
-               printf("              %.*s [%s]:%s\n", si->name.len, 
-                               si->name.s, si->address_str.s, si->port_no_str.s);
+               printf("              %.*s [%s]:%s%s\n", si->name.len, 
+                               si->name.s, si->address_str.s, si->port_no_str.s,
+                               si->flags & SI_IS_MCAST ? " mcast" : "");
 #endif
        }
        /* removing duplicate addresses*/
@@ -505,6 +516,30 @@ static int fix_socket_list(struct socket_info **list)
                        l=next;
                }
        }
+
+#ifdef USE_MCAST
+            /* Remove invalid multicast entries */
+       si=*list;
+       while(si){
+               if ((si->flags & SI_IS_MCAST) && 
+                   ((si->proto == PROTO_TCP)
+#ifdef USE_TLS
+                   || (si->proto == PROTO_TLS)
+#endif /* USE_TLS */
+                   )){
+                       LOG(L_WARN, "WARNING: removing entry %s:%s [%s]:%s\n",
+                           get_proto_name(si->proto), si->name.s, 
+                           si->address_str.s, si->port_no_str.s);
+                       l = si;
+                       si=si->next;
+                       sock_listrm(list, l);
+                       free_sock_info(l);
+               } else {
+                       si=si->next;
+               }
+       }
+#endif /* USE_MCAST */
+
        return 0;
 error:
        return -1;
@@ -600,8 +635,9 @@ void print_all_socket_lists()
        do{
                list=get_sock_info_list(proto);
                for(si=list?*list:0; si; si=si->next){
-                       printf("             %s: %s [%s]:%s\n", get_proto_name(proto),
-                                               si->name.s, si->address_str.s, si->port_no_str.s);
+                       printf("             %s: %s [%s]:%s%s\n", get_proto_name(proto),
+                              si->name.s, si->address_str.s, si->port_no_str.s, 
+                              si->flags & SI_IS_MCAST ? " mcast" : "");
                }
        }while((proto=next_proto(proto)));
 }
index 522d854..2cb3608 100644 (file)
@@ -206,11 +206,71 @@ int probe_max_receive_buffer( int udp_sock )
        /* EoJKU */
 }
 
+
+#ifdef USE_MCAST
+
+/*
+ * Setup multicast receiver
+ */
+static int setup_mcast_rcvr(int sock, union sockaddr_union* addr)
+{
+       struct ip_mreq mreq;
+#ifdef USE_IPV6
+       struct ipv6_mreq mreq6;
+#endif /* USE_IPV6 */
+       
+       if (addr->s.sa_family==AF_INET){
+               memcpy(&mreq.imr_multiaddr, &addr->sin.sin_addr, 
+                      sizeof(struct in_addr));
+               mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+               
+               if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq,
+                              sizeof(mreq))==-1){
+                       LOG(L_ERR, "ERROR: setup_mcast_rcvr: setsockopt: %s\n",
+                           strerror(errno));
+                       return -1;
+               }
+               
+               if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, 
+                              &mcast_loopback, sizeof(mcast_loopback))==-1){
+                       LOG(L_ERR, "ERROR: setup_mcast_rcvr: setsockopt: %s\n",
+                           strerror(errno));
+                       return -1;
+               }
+#ifdef USE_IPV6
+       } else if (addr->s.sa_family==AF_INET6){
+               memcpy(&mreq6.ipv6mr_multiaddr, &addr->sin6.sin6_addr, 
+                      sizeof(struct in6_addr));
+               mreq6.ipv6mr_interface = 0;
+               
+               if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6,
+                              sizeof(mreq6))==-1){
+                       LOG(L_ERR, "ERROR: setup_mcast_rcvr: setsockopt:%s\n",
+                           strerror(errno));
+                       return -1;
+               }
+               
+               if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 
+                              &mcast_loopback, sizeof(mcast_loopback))==-1){
+                       LOG(L_ERR, "ERROR: udp_init: setsockopt: %s\n", 
+                           strerror(errno));
+                       return -1;
+               }
+#endif /* USE_IPV6 */
+       } else {
+               LOG(L_ERR, "ERROR: udp_init: Unsupported protocol family\n");
+               return -1;
+       }
+       return 0;
+}
+
+#endif /* USE_MCAST */
+
+
 int udp_init(struct socket_info* sock_info)
 {
        union sockaddr_union* addr;
        int optval;
-
        addr=&sock_info->su;
 /*
        addr=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union));
@@ -254,6 +314,12 @@ int udp_init(struct socket_info* sock_info)
        }
 #endif
 
+#ifdef USE_MCAST
+       if ((sock_info->flags & SI_IS_MCAST) 
+           && (setup_mcast_rcvr(sock_info->socket, addr)<0)){
+                       goto error;
+       }
+#endif /* USE_MCAST */
 
        if ( probe_max_receive_buffer(sock_info->socket)==-1) goto error;