diff -ruN igmpproxy.orig/Makefile igmpproxy/Makefile --- igmpproxy.orig/Makefile 2009-08-22 04:31:27.000000000 +0400 +++ igmpproxy/Makefile 2009-12-20 13:44:53.000000000 +0300 @@ -7,35 +7,26 @@ PORTNAME= igmpproxy PORTVERSION= 0.1 -PORTREVISION= 1 +PORTREVISION= 2 CATEGORIES= net -MASTER_SITES= SF/${PORTNAME}/${PORTNAME}/${PORTVERSION}-beta2 -DISTNAME= ${PORTNAME}-src-${PORTVERSION}-beta2 +MASTER_SITES= ${MASTER_SITE_SOURCEFORGE} +MASTER_SITE_SUBDIR= ${PORTNAME}/${PORTNAME}/${PORTVERSION} MAINTAINER= melifaro@ipfw.ru COMMENT= Multicast forwarding IGMP proxy HOMEPAGE= http://igmpproxy.sourceforge.net/ -WRKSRC= ${WRKDIR}/${PORTNAME}-${PORTVERSION} -BUILD_WRKSRC= ${WRKSRC}/src - USE_RC_SUBR= igmpproxy USE_GMAKE= yes +GNU_CONFIGURE= yes MAN5= igmpproxy.conf.5 MAN8= igmpproxy.8 PLIST_FILES= sbin/igmpproxy \ etc/igmpproxy.conf.sample - -post-extract: - @${MV} ${WRKDIR}/${PORTNAME} ${WRKDIR}/${PORTNAME}-${PORTVERSION} - -do-install: - @${INSTALL_PROGRAM} ${WRKSRC}/src/igmpproxy ${PREFIX}/sbin/ - @${INSTALL_DATA} ${WRKSRC}/src/igmpproxy.conf ${PREFIX}/etc/igmpproxy.conf.sample - @${INSTALL_MAN} ${WRKSRC}/doc/igmpproxy.8 ${PREFIX}/man/man8/ - @${INSTALL_MAN} ${WRKSRC}/doc/igmpproxy.conf.5 ${PREFIX}/man/man5/ +#post-patch: +# @${REINPLACE_CMD} 's/^\(dist_sysconf_DATA.*\)$$/\1.sample/' ${WRKSRC}/src/Makefile.in .include diff -ruN igmpproxy.orig/distinfo igmpproxy/distinfo --- igmpproxy.orig/distinfo 2009-03-18 18:18:53.000000000 +0300 +++ igmpproxy/distinfo 2009-12-20 13:24:17.000000000 +0300 @@ -1,3 +1,3 @@ -MD5 (igmpproxy-src-0.1-beta2.tar.gz) = 2a5a59480f44d4b14077a6b5319e9940 -SHA256 (igmpproxy-src-0.1-beta2.tar.gz) = 7f6e5486e84827150c8ca402967c96334bbd62b9f785195c4ee84da1218abb40 -SIZE (igmpproxy-src-0.1-beta2.tar.gz) = 35103 +MD5 (igmpproxy-0.1.tar.gz) = c56f41ec195bc1fe016369bf74efc5a1 +SHA256 (igmpproxy-0.1.tar.gz) = ee18ff3d8c3ae3a29dccb7e5eedf332337330020168bd95a11cece8d7d7ee6ae +SIZE (igmpproxy-0.1.tar.gz) = 140159 diff -ruN igmpproxy.orig/files/patch-Makefile igmpproxy/files/patch-Makefile --- igmpproxy.orig/files/patch-Makefile 1970-01-01 03:00:00.000000000 +0300 +++ igmpproxy/files/patch-Makefile 2009-12-20 13:24:17.000000000 +0300 @@ -0,0 +1,14 @@ +--- Makefile.in.orig 2009-12-20 13:13:06.000000000 +0300 ++++ Makefile.in 2009-12-20 13:15:11.000000000 +0300 +@@ -284,7 +284,10 @@ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sysconfdir)'"; \ +- $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)" || exit $$?; \ ++ if [ ! -f "$(DESTDIR)$(sysconfdir)/$$files" ]; then \ ++ $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)" || exit $$?; \ ++ fi; \ ++ $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)/$$files.sample" || exit $$?; \ + done + + uninstall-dist_sysconfDATA: diff -ruN igmpproxy.orig/files/patch-freebsd igmpproxy/files/patch-freebsd --- igmpproxy.orig/files/patch-freebsd 2009-05-25 19:37:58.000000000 +0400 +++ igmpproxy/files/patch-freebsd 1970-01-01 03:00:00.000000000 +0300 @@ -1,1131 +0,0 @@ ---- src/Makefile.orig 2005-08-20 13:34:18.000000000 +0100 -+++ src/Makefile 2009-03-18 14:39:19.000000000 +0000 -@@ -1,12 +1,12 @@ - - #BINDIR=../bin - BINDIR=/usr/local/bin --ETCDIR=/etc --MANDIR=/usr/share/man -+ETCDIR=/usr/local/etc -+MANDIR=/usr/local/man - - - # CFLAGS=-g --CFLAGS=-O -+CFLAGS+=-O2 -Wall -Wextra -fno-builtin-log - - default : build.h igmpproxy - -@@ -21,8 +21,11 @@ - cp ../doc/igmpproxy.conf.5 ${MANDIR}/man5 - if [ ! -e ${ETCDIR}/igmpproxy.conf ]; then cp igmpproxy.conf ${ETCDIR}; fi - --igmpproxy : igmpproxy.o config.o confread.o request.o udpsock.o mcgroup.o rttable.o \ -- igmp.o ifvc.o callout.o kern.o syslog.o lib.o mroute-api.o -+SRC = igmpproxy.c config.c confread.c request.c mcgroup.c rttable.c \ -+ igmp.c ifvc.c callout.c kern.c syslog.c lib.c mroute-api.c -+OBJS = ${SRC:.c=.o} -+igmpproxy: build.h ${OBJS} -+ $(CC) ${CFLAGS} ${OBJS} -o igmpproxy - - build.h : - echo '#define BUILD "' `date +%y%m%d` '"' >build.h ---- src/config.c.orig 2005-05-24 16:49:29.000000000 +0100 -+++ src/config.c 2009-03-18 14:35:31.000000000 +0000 -@@ -39,16 +39,16 @@ - - // Structure to keep configuration for VIFs... - struct vifconfig { -- char* name; -- short state; -- int ratelimit; -- int threshold; -+ char name[IFNAMSIZ]; -+ short state; -+ int ratelimit; -+ int threshold; - - // Keep allowed nets for VIF. -- struct SubnetList* allowednets; -+ struct SubnetList* allowednets; - - // Next config in list... -- struct vifconfig* next; -+ struct vifconfig* next; - }; - - // Structure to keep vif configuration -@@ -177,7 +177,7 @@ - } - - // Loop through all VIFs... -- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) { -+ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) { - if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) { - - // Now try to find a matching config... -@@ -240,12 +240,7 @@ - tmpPtr->state = IF_STATE_DOWNSTREAM; - tmpPtr->allowednets = NULL; - -- // Make a copy of the token to store the IF name -- tmpPtr->name = (char *)malloc( sizeof(char) * strlen(token) ); -- if(tmpPtr->name == NULL) { -- log(LOG_ERR, 0, "Out of memory."); -- } -- strcpy(tmpPtr->name, token); -+ strlcpy(tmpPtr->name, token, sizeof(tmpPtr->name)); - - // Set the altnet pointer to the allowednets pointer. - anetPtr = &tmpPtr->allowednets; -@@ -255,7 +250,7 @@ - while(token != NULL) { - if(strcmp("altnet", token)==0) { - // Altnet... -- struct in_addr networkAddr; -+ //struct in_addr networkAddr; - - token = nextConfigToken(); - IF_DEBUG log(LOG_DEBUG, 0, "Config: IF: Got altnet token %s.",token); -@@ -347,7 +342,7 @@ - mask <<= (32 - bitcnt); - } - -- if(addr == -1 || addr == 0) { -+ if(addr == (uint32) -1 || addr == 0) { - log(LOG_WARNING, 0, "Unable to parse address token '%s'.", addrstr); - return NULL; - } ---- src/defs.h.orig 2005-08-20 13:44:47.000000000 +0100 -+++ src/defs.h 2009-03-18 14:35:31.000000000 +0000 -@@ -40,27 +40,46 @@ - #include - #include - #include -- - #include -+ -+#ifdef __FreeBSD__ -+#include -+#include -+#include -+#include -+ -+#else - #include - #include -+#endif - - #include - --// The multicats API needs linux spesific headers !!! -+// The multicats API needs linux specific headers !!! - #ifdef USE_LINUX_IN_H - #include - #include - #else -+#ifdef __FreeBSD__ -+ #include -+ #include -+ #include - #include -+ #include -+#endif -+ #include -+ #include - #include - #include - #include - #endif - -- - // The default path for the config file... -+#ifdef __FreeBSD__ -+#define IGMPPROXY_CONFIG_FILEPATH "/usr/local/etc/igmpproxy.conf" -+#else - #define IGMPPROXY_CONFIG_FILEPATH "/etc/igmpproxy.conf" -+#endif - #define ENABLE_DEBUG 1 - - /* -@@ -72,9 +91,31 @@ - - #define MAX_MC_VIFS 32 // !!! check this const in the specific includes - -+#ifndef IGMP_MEMBERSHIP_QUERY -+#define IGMP_MEMBERSHIP_QUERY IGMP_HOST_MEMBERSHIP_QUERY -+#endif -+#ifndef IGMP_V1_MEMBERSHIP_REPORT -+#define IGMP_V1_MEMBERSHIP_REPORT IGMP_v1_HOST_MEMBERSHIP_REPORT -+#endif -+#ifndef IGMP_V2_MEMBERSHIP_REPORT -+#define IGMP_V2_MEMBERSHIP_REPORT IGMP_v2_HOST_MEMBERSHIP_REPORT -+#endif -+#ifndef IGMP_V2_LEAVE_GROUP -+#define IGMP_V2_LEAVE_GROUP IGMP_HOST_LEAVE_MESSAGE -+#endif -+ -+#ifndef INADDR_ALLRTRS_GROUP -+/* address for multicast mtrace msg */ -+#define INADDR_ALLRTRS_GROUP (u_int32_t)0xe0000002 /* 224.0.0.2 */ -+#endif -+ - // Useful macros.. -+#ifndef MIN - #define MIN( a, b ) ((a) < (b) ? (a) : (b)) -+#endif -+#ifndef MAX - #define MAX( a, b ) ((a) < (b) ? (b) : (a)) -+#endif - #define VCMC( Vc ) (sizeof( Vc ) / sizeof( (Vc)[ 0 ] )) - #define VCEP( Vc ) (&(Vc)[ VCMC( Vc ) ]) - -@@ -126,7 +167,12 @@ - - #define IF_DEBUG if(Log2Stderr & LOG_DEBUG) - --void log( int Serverity, int Errno, const char *FmtSt, ... ); -+#ifdef DEVEL_LOGGING -+#define log(Severity, Errno, Fmt, args...) _log((Severity), (Errno), __FUNCTION__, __LINE__, (Fmt), ##args) -+void _log( int Serverity, int Errno, const char *func, int line, const char *FmtSt, ...); -+#else -+void log( int Serverity, int Errno, const char *FmtSt, ...); -+#endif - - /* ifvc.c - */ -@@ -161,7 +207,7 @@ - }; - - struct IfDesc { -- char Name[ sizeof( ((struct ifreq *)NULL)->ifr_name ) ]; -+ char Name[IFNAMSIZ]; - struct in_addr InAdr; /* == 0 for non IP interfaces */ - short Flags; - short state; -@@ -196,6 +242,7 @@ - struct IfDesc *getIfByName( const char *IfName ); - struct IfDesc *getIfByIx( unsigned Ix ); - struct IfDesc *getIfByAddress( uint32 Ix ); -+int isAdressValidForIf( struct IfDesc* intrface, uint32 ipaddr ); - - /* mroute-api.c - */ -@@ -235,7 +282,7 @@ - char *fmtInAdr( char *St, struct in_addr InAdr ); - char *inetFmt(uint32 addr, char *s); - char *inetFmts(uint32 addr, uint32 mask, char *s); --int inetCksum(u_short *addr, u_int len); -+int inetChksum(u_short *addr, u_int len); - - /* kern.c - */ -@@ -264,7 +311,7 @@ - void initRouteTable(); - void clearAllRoutes(); - int insertRoute(uint32 group, int ifx); --int activateRoute(uint32 group, uint32 originAddr); -+int activateRoute(uint32 group, uint32 originAddr, int downIf); - void ageActiveRoutes(); - void setRouteLastMemberMode(uint32 group); - int lastMemberGroupAge(uint32 group); ---- src/ifvc.c.orig 2005-05-24 16:49:18.000000000 +0100 -+++ src/ifvc.c 2009-03-18 14:35:31.000000000 +0000 -@@ -32,7 +32,11 @@ - */ - - #include "defs.h" -+#ifdef __FreeBSD__ -+#include -+#else - #include -+#endif - - struct IfDesc IfDescVc[ MAX_IF ], *IfDescEp = IfDescVc; - -@@ -42,119 +46,91 @@ - ** - */ - void buildIfVc() { -- struct ifreq IfVc[ sizeof( IfDescVc ) / sizeof( IfDescVc[ 0 ] ) ]; -- struct ifreq *IfEp; -+ struct ifaddrs *ifap, *ifa; -+ struct IfDesc *ifp; -+ struct SubnetList *net; - -- int Sock; -- -- if ( (Sock = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) -- log( LOG_ERR, errno, "RAW socket open" ); -- -- /* get If vector -- */ -- { -- struct ifconf IoCtlReq; -- -- IoCtlReq.ifc_buf = (void *)IfVc; -- IoCtlReq.ifc_len = sizeof( IfVc ); -- -- if ( ioctl( Sock, SIOCGIFCONF, &IoCtlReq ) < 0 ) -- log( LOG_ERR, errno, "ioctl SIOCGIFCONF" ); -- -- IfEp = (void *)((char *)IfVc + IoCtlReq.ifc_len); -- } -+ if (getifaddrs(&ifap) < 0) -+ log( LOG_ERR, errno, "getifaddrs" ); - - /* loop over interfaces and copy interface info to IfDescVc - */ - { -- struct ifreq *IfPt; -- struct IfDesc *IfDp; -- - // Temp keepers of interface params... - uint32 addr, subnet, mask; - -- for ( IfPt = IfVc; IfPt < IfEp; IfPt++ ) { -- struct ifreq IfReq; -+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - char FmtBu[ 32 ]; - -- strncpy( IfDescEp->Name, IfPt->ifr_name, sizeof( IfDescEp->Name ) ); -- -- // Currently don't set any allowed nets... -- //IfDescEp->allowednets = NULL; -- -- // Set the index to -1 by default. -- IfDescEp->index = -1; -+ if (IfDescEp >= &IfDescVc[ MAX_IF ]) { -+ log(LOG_WARNING, 0, "Too many interfaces, skipping %d", ifa->ifa_name); -+ continue; -+ } - -- /* don't retrieve more info for non-IP interfaces -+ /* ignore non-IP interfaces - */ -- if ( IfPt->ifr_addr.sa_family != AF_INET ) { -- IfDescEp->InAdr.s_addr = 0; /* mark as non-IP interface */ -- IfDescEp++; -+ if ( ifa->ifa_addr->sa_family != AF_INET ) - continue; -- } -- -- // Get the interface adress... -- IfDescEp->InAdr = ((struct sockaddr_in *)&IfPt->ifr_addr)->sin_addr; -- addr = IfDescEp->InAdr.s_addr; -- -- memcpy( IfReq.ifr_name, IfDescEp->Name, sizeof( IfReq.ifr_name ) ); -- -- // Get the subnet mask... -- if (ioctl(Sock, SIOCGIFNETMASK, &IfReq ) < 0) -- log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", IfReq.ifr_name); -- mask = ((struct sockaddr_in *)&IfReq.ifr_addr)->sin_addr.s_addr; -- subnet = addr & mask; - -- // Get the physical index of the Interface -- if (ioctl(Sock, SIOCGIFINDEX, &IfReq ) < 0) -- log(LOG_ERR, errno, "ioctl SIOCGIFINDEX for %s", IfReq.ifr_name); -- -- log(LOG_DEBUG, 0, "Physical Index value of IF '%s' is %d", -- IfDescEp->Name, IfReq.ifr_ifindex); -+ if ((ifp = getIfByName(ifa->ifa_name)) == NULL) { - -+ strlcpy( IfDescEp->Name, ifa->ifa_name, sizeof( IfDescEp->Name ) ); - -- /* get if flags -- ** -- ** typical flags: -- ** lo 0x0049 -> Running, Loopback, Up -- ** ethx 0x1043 -> Multicast, Running, Broadcast, Up -- ** ipppx 0x0091 -> NoArp, PointToPoint, Up -- ** grex 0x00C1 -> NoArp, Running, Up -- ** ipipx 0x00C1 -> NoArp, Running, Up -- */ -- if ( ioctl( Sock, SIOCGIFFLAGS, &IfReq ) < 0 ) -- log( LOG_ERR, errno, "ioctl SIOCGIFFLAGS" ); -+ log(LOG_DEBUG, 0, "Adding Physical Index value of IF '%s' is %d", -+ IfDescEp->Name, if_nametoindex(IfDescEp->Name)); - -- IfDescEp->Flags = IfReq.ifr_flags; -+ // Set the index to -1 by default. -+ IfDescEp->index = -1; -+ -+ // Get the interface adress... -+ IfDescEp->InAdr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; -+ -+ /* get if flags -+ ** -+ ** typical flags: -+ ** lo 0x0049 -> Running, Loopback, Up -+ ** ethx 0x1043 -> Multicast, Running, Broadcast, Up -+ ** ipppx 0x0091 -> NoArp, PointToPoint, Up -+ ** grex 0x00C1 -> NoArp, Running, Up -+ ** ipipx 0x00C1 -> NoArp, Running, Up -+ */ -+ -+ IfDescEp->Flags = ifa->ifa_flags; -+ -+ // Set the default params for the IF... -+ IfDescEp->state = IF_STATE_DOWNSTREAM; -+ IfDescEp->robustness = DEFAULT_ROBUSTNESS; -+ IfDescEp->threshold = DEFAULT_THRESHOLD; /* ttl limit */ -+ IfDescEp->ratelimit = DEFAULT_RATELIMIT; -+ IfDescEp->allowednets = NULL; -+ ifp = IfDescEp++; -+ } - - // Insert the verified subnet as an allowed net... -- IfDescEp->allowednets = (struct SubnetList *)malloc(sizeof(struct SubnetList)); -- if(IfDescEp->allowednets == NULL) log(LOG_ERR, 0, "Out of memory !"); -+ addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; -+ mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr; -+ subnet = addr & mask; -+ -+ net = (struct SubnetList *)malloc(sizeof(struct SubnetList)); -+ if(net == NULL) log(LOG_ERR, 0, "Out of memory !"); - - // Create the network address for the IF.. -- IfDescEp->allowednets->next = NULL; -- IfDescEp->allowednets->subnet_mask = mask; -- IfDescEp->allowednets->subnet_addr = subnet; -- -- // Set the default params for the IF... -- IfDescEp->state = IF_STATE_DOWNSTREAM; -- IfDescEp->robustness = DEFAULT_ROBUSTNESS; -- IfDescEp->threshold = DEFAULT_THRESHOLD; /* ttl limit */ -- IfDescEp->ratelimit = DEFAULT_RATELIMIT; -+ net->next = ifp->allowednets; -+ net->subnet_mask = mask; -+ net->subnet_addr = subnet; -+ ifp->allowednets = net; - -- - // Debug log the result... - IF_DEBUG log( LOG_DEBUG, 0, "buildIfVc: Interface %s Addr: %s, Flags: 0x%04x, Network: %s", -- IfDescEp->Name, -- fmtInAdr( FmtBu, IfDescEp->InAdr ), -- IfDescEp->Flags, -+ ifp->Name, -+ fmtInAdr( FmtBu, ifp->InAdr ), -+ ifp->Flags, - inetFmts(subnet,mask, s1)); - -- IfDescEp++; - } -- } - -- close( Sock ); -+ } -+ freeifaddrs(ifap); - } - - /* ---- src/igmp.c.orig 2005-05-24 16:49:16.000000000 +0100 -+++ src/igmp.c 2009-03-18 14:35:31.000000000 +0000 -@@ -105,7 +105,7 @@ - struct igmp *igmp; - int ipdatalen, iphdrlen, igmpdatalen; - -- if (recvlen < sizeof(struct ip)) { -+ if (recvlen < (int) sizeof(struct ip)) { - log(LOG_WARNING, 0, - "received packet too short (%u bytes) for IP header", recvlen); - return; -@@ -128,6 +128,7 @@ - } - else { - struct IfDesc *checkVIF; -+ int downIf = -1; - - // Check if the source address matches a valid address on upstream vif. - checkVIF = getIfByIx( upStreamVif ); -@@ -141,23 +142,44 @@ - return; - } - else if(!isAdressValidForIf(checkVIF, src)) { -- log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.", -- inetFmt(src, s1), inetFmt(dst, s2)); -- return; -+ unsigned Ix; -+ struct IfDesc *Dp; -+ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) { -+ if ((Dp->state == IF_STATE_DOWNSTREAM) &&isAdressValidForIf(Dp, src)) { -+ downIf = Ix; -+ break; -+ } -+ } -+ -+ if (downIf == -1) { -+ log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.", -+ inetFmt(src, s1), inetFmt(dst, s2)); -+ return; -+ } else { -+ log(LOG_NOTICE, 0, "The source address %s for group %s, is valid DOWNSTREAM VIF #%d.", -+ inetFmt(src, s1), inetFmt(dst, s2), downIf); -+ } - } - - // Activate the route. -- IF_DEBUG log(LOG_DEBUG, 0, "Route activate request from %s to %s", -- inetFmt(src,s1), inetFmt(dst,s2)); -- activateRoute(dst, src); -+ IF_DEBUG log(LOG_DEBUG, 0, "Route activate request from %s to %s, downIf %d", -+ inetFmt(src,s1), inetFmt(dst,s2), downIf); -+ activateRoute(dst, src, downIf); - - - } - return; - } - -+ log(LOG_DEBUG, 0, "Packet from %s: proto: %d hdrlen: %d iplen: %d or %d", -+ inetFmt(src, s1), ip->ip_p, ip->ip_hl << 2, ip->ip_len, ntohs(ip->ip_len)); -+ - iphdrlen = ip->ip_hl << 2; -+#ifdef RAW_INPUT_IS_RAW - ipdatalen = ntohs(ip->ip_len) - iphdrlen; -+#else -+ ipdatalen = ip->ip_len; -+#endif - - if (iphdrlen + ipdatalen != recvlen) { - log(LOG_WARNING, 0, -@@ -176,9 +198,9 @@ - return; - } - -- log(LOG_NOTICE, 0, "RECV %s from %-15s to %s", -+ log(LOG_NOTICE, 0, "RECV %s from %-15s to %s (ip_hl %d, data %d)", - igmpPacketKind(igmp->igmp_type, igmp->igmp_code), -- inetFmt(src, s1), inetFmt(dst, s2) ); -+ inetFmt(src, s1), inetFmt(dst, s2), iphdrlen, ipdatalen); - - switch (igmp->igmp_type) { - case IGMP_V1_MEMBERSHIP_REPORT: -@@ -190,13 +212,10 @@ - acceptLeaveMessage(src, group); - return; - -- /* - case IGMP_MEMBERSHIP_QUERY: - //accept_membership_query(src, dst, group, igmp->igmp_code); - return; - -- */ -- - default: - log(LOG_INFO, 0, - "ignoring unknown IGMP message type %x from %s to %s", -@@ -220,8 +239,9 @@ - ip->ip_src.s_addr = src; - ip->ip_dst.s_addr = dst; - ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; -+#ifdef RAW_OUTPUT_IS_RAW - ip->ip_len = htons(ip->ip_len); -- -+#endif - if (IN_MULTICAST(ntohl(dst))) { - ip->ip_ttl = curttl; - } else { ---- src/igmpproxy.c.orig 2005-08-20 13:56:32.000000000 +0100 -+++ src/igmpproxy.c 2009-03-18 14:35:31.000000000 +0000 -@@ -80,7 +80,7 @@ - * on commandline. The number of commandline arguments, and a - * pointer to the arguments are recieved on the line... - */ --int main( int ArgCn, const char *ArgVc[] ) { -+int main( int ArgCn, char *ArgVc[] ) { - - int debugMode = 0; - -@@ -155,17 +155,8 @@ - if ( ! debugMode ) { - - IF_DEBUG log( LOG_DEBUG, 0, "Starting daemon mode."); -- -- // Only daemon goes past this line... -- if (fork()) exit(0); -- -- // Detach deamon from terminal -- if ( close( 0 ) < 0 || close( 1 ) < 0 || close( 2 ) < 0 -- || open( "/dev/null", 0 ) != 0 || dup2( 0, 1 ) < 0 || dup2( 0, 2 ) < 0 -- || setpgrp() < 0 -- ) { -+ if (daemon(1, 0) != 0) - log( LOG_ERR, errno, "failed to detach deamon" ); -- } - } - - // Go to the main loop. -@@ -218,7 +209,7 @@ - int vifcount = 0; - upStreamVif = -1; - -- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) { -+ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) { - - if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) { - if(Dp->state == IF_STATE_UPSTREAM) { -@@ -237,7 +228,7 @@ - - // If there is only one VIF, or no defined upstream VIF, we send an error. - if(vifcount < 2 || upStreamVif < 0) { -- log(LOG_ERR, 0, "There must be at least 2 Vif's where one is upstream."); -+ log(LOG_ERR, 0, "There must be at least 2 Vif's where one is upstream. (vifcount %d, upStreamVif %d)", vifcount, upStreamVif); - } - } - -@@ -275,7 +266,7 @@ - register int recvlen; - int MaxFD, Rt, secs; - fd_set ReadFDS; -- int dummy = 0; -+ socklen_t dummy = 0; - struct timeval curtime, lasttime, difftime, tv; - // The timeout is a pointer in order to set it to NULL if nessecary. - struct timeval *timeout = &tv; ---- src/igmpproxy.conf.orig 2005-04-29 20:27:50.000000000 +0100 -+++ src/igmpproxy.conf 2009-03-18 14:35:31.000000000 +0000 -@@ -25,22 +25,22 @@ - - - ##------------------------------------------------------ --## Configuration for eth0 (Upstream Interface) -+## Configuration for em0 (Upstream Interface) - ##------------------------------------------------------ --phyint eth0 upstream ratelimit 0 threshold 1 -+phyint em0 upstream ratelimit 0 threshold 1 - altnet 10.0.0.0/8 - altnet 192.168.0.0/24 - - - ##------------------------------------------------------ --## Configuration for eth1 (Downstream Interface) -+## Configuration for em1 (Downstream Interface) - ##------------------------------------------------------ --phyint eth1 downstream ratelimit 0 threshold 1 -+phyint em1 downstream ratelimit 0 threshold 1 - - - ##------------------------------------------------------ --## Configuration for eth2 (Disabled Interface) -+## Configuration for xl0 (Disabled Interface) - ##------------------------------------------------------ --phyint eth2 disabled -+phyint xl0 disabled - - ---- src/mcgroup.c.orig 2005-08-20 13:54:37.000000000 +0100 -+++ src/mcgroup.c 2009-03-18 14:35:31.000000000 +0000 -@@ -49,7 +49,6 @@ - CtlReq.imr_interface.s_addr = IfDp->InAdr.s_addr; - - { -- char FmtBu[ 32 ]; - log( LOG_NOTICE, 0, "%sMcGroup: %s on %s", CmdSt, - inetFmt( mcastaddr, s1 ), IfDp ? IfDp->Name : "" ); - } ---- src/mroute-api.c.orig 2005-05-24 16:48:33.000000000 +0100 -+++ src/mroute-api.c 2009-03-18 14:35:31.000000000 +0000 -@@ -37,7 +37,9 @@ - */ - - -+#ifndef __FreeBSD__ - #define USE_LINUX_IN_H -+#endif - #include "defs.h" - - // MAX_MC_VIFS from mclab.h must have same value as MAXVIFS from mroute.h -@@ -47,7 +49,7 @@ - - // need an IGMP socket as interface for the mrouted API - // - receives the IGMP messages --int MRouterFD; /* socket for all network I/O */ -+int MRouterFD = -1; /* socket for all network I/O */ - char *recv_buf; /* input packet buffer */ - char *send_buf; /* output packet buffer */ - -@@ -177,13 +179,15 @@ - log( LOG_NOTICE, 0, "Adding MFC: %s -> %s, InpVIf: %d", - fmtInAdr( FmtBuO, CtlReq.mfcc_origin ), - fmtInAdr( FmtBuM, CtlReq.mfcc_mcastgrp ), -- CtlReq.mfcc_parent == ALL_VIFS ? -1 : CtlReq.mfcc_parent -+ CtlReq.mfcc_parent - ); - } - - if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_ADD_MFC, - (void *)&CtlReq, sizeof( CtlReq ) ) ) - log( LOG_WARNING, errno, "MRT_ADD_MFC" ); -+ -+ return 0; - } - - /* -@@ -210,13 +214,15 @@ - log( LOG_NOTICE, 0, "Removing MFC: %s -> %s, InpVIf: %d", - fmtInAdr( FmtBuO, CtlReq.mfcc_origin ), - fmtInAdr( FmtBuM, CtlReq.mfcc_mcastgrp ), -- CtlReq.mfcc_parent == ALL_VIFS ? -1 : CtlReq.mfcc_parent -+ CtlReq.mfcc_parent - ); - } - - if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_DEL_MFC, - (void *)&CtlReq, sizeof( CtlReq ) ) ) - log( LOG_WARNING, errno, "MRT_DEL_MFC" ); -+ -+ return 0; - } - - /* ---- src/request.c.orig 2005-05-24 16:48:29.000000000 +0100 -+++ src/request.c 2009-03-18 14:35:31.000000000 +0000 -@@ -88,10 +88,11 @@ - - } else { - // Log the state of the interface the report was recieved on. -- log(LOG_INFO, 0, "Mebership report was recieved on %s. Ignoring.", -+ log(LOG_INFO, 0, "Membership report was received on %s. Ignoring.", - sourceVif->state==IF_STATE_UPSTREAM?"the upstream interface":"a disabled interface"); - } - -+ log(LOG_DEBUG, 0, "Eliminate compiler warning for field type = %u", type); - } - - /** -@@ -136,7 +137,7 @@ - - } else { - // just ignore the leave request... -- IF_DEBUG log(LOG_DEBUG, 0, "The found if for %s was not downstream. Ignoring leave request."); -+ IF_DEBUG log(LOG_DEBUG, 0, "The found if for %s was not downstream. Ignoring leave request.", inetFmt(src, s1)); - } - } - -@@ -184,7 +185,7 @@ - int Ix; - - // Loop through all downstream vifs... -- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) { -+ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) { - if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) { - if(Dp->state == IF_STATE_DOWNSTREAM) { - // Send the membership query... ---- src/rttable.c.orig 2005-08-20 13:46:20.000000000 +0100 -+++ src/rttable.c 2009-03-18 14:35:31.000000000 +0000 -@@ -38,15 +38,22 @@ - */ - - #include "defs.h" -+#include - - /** - * Routing table structure definition. Double linked list... - */ -+struct Origin { -+ TAILQ_ENTRY(Origin) next; -+ uint32 originAddr; -+ int flood; -+ uint32 pktcnt; -+}; -+ - struct RouteTable { - struct RouteTable *nextroute; // Pointer to the next group in line. - struct RouteTable *prevroute; // Pointer to the previous group in line. - uint32 group; // The group to route -- uint32 originAddr; // The origin adress (only set on activated routes) - uint32 vifBits; // Bits representing recieving VIFs. - - // Keeps the upstream membership state... -@@ -56,6 +63,7 @@ - uint32 ageVifBits; // Bits representing aging VIFs. - int ageValue; // Downcounter for death. - int ageActivity; // Records any acitivity that notes there are still listeners. -+ TAILQ_HEAD(originhead, Origin) originList; // The origin adresses (non-empty on activated routes) - }; - - -@@ -65,19 +73,17 @@ - // Prototypes - void logRouteTable(char *header); - int internAgeRoute(struct RouteTable* croute); -- --// Socket for sending join or leave requests. --int mcGroupSock = 0; -+int internUpdateKernelRoute(struct RouteTable *route, int activate, struct Origin *o); - - - /** - * Function for retrieving the Multicast Group socket. - */ - int getMcGroupSock() { -- if( ! mcGroupSock ) { -- mcGroupSock = openUdpSocket( INADDR_ANY, 0 );; -+ if (MRouterFD < 0) { -+ log(LOG_ERR, errno, "no MRouterFD."); - } -- return mcGroupSock; -+ return MRouterFD; - } - - /** -@@ -91,7 +97,7 @@ - routing_table = NULL; - - // Join the all routers group on downstream vifs... -- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) { -+ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) { - // If this is a downstream vif, we should join the All routers group... - if( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) && Dp->state == IF_STATE_DOWNSTREAM) { - IF_DEBUG log(LOG_DEBUG, 0, "Joining all-routers group %s on vif %s", -@@ -160,6 +166,7 @@ - */ - void clearAllRoutes() { - struct RouteTable *croute, *remainroute; -+ struct Origin *o; - - // Loop through all routes... - for(croute = routing_table; croute; croute = remainroute) { -@@ -171,7 +178,7 @@ - inetFmt(croute->group, s1)); - - // Uninstall current route -- if(!internUpdateKernelRoute(croute, 0)) { -+ if(!internUpdateKernelRoute(croute, 0, NULL)) { - log(LOG_WARNING, 0, "The removal from Kernel failed."); - } - -@@ -179,6 +186,10 @@ - sendJoinLeaveUpstream(croute, 0); - - // Clear memory, and set pointer to next route... -+ while ((o = TAILQ_FIRST(&croute->originList))) { -+ TAILQ_REMOVE(&croute->originList, o, next); -+ free(o); -+ } - free(croute); - } - routing_table = NULL; -@@ -212,7 +223,6 @@ - - struct Config *conf = getCommonConfig(); - struct RouteTable* croute; -- int result = 1; - - // Sanitycheck the group adress... - if( ! IN_MULTICAST( ntohl(group) )) { -@@ -241,7 +251,8 @@ - newroute = (struct RouteTable*)malloc(sizeof(struct RouteTable)); - // Insert the route desc and clear all pointers... - newroute->group = group; -- newroute->originAddr = 0; -+ TAILQ_INIT(&newroute->originList); -+ - newroute->nextroute = NULL; - newroute->prevroute = NULL; - -@@ -325,10 +336,10 @@ - inetFmt(croute->group, s1), ifx); - - // If the route is active, it must be reloaded into the Kernel.. -- if(croute->originAddr != 0) { -+ if(!TAILQ_EMPTY(&croute->originList)) { - - // Update route in kernel... -- if(!internUpdateKernelRoute(croute, 1)) { -+ if(!internUpdateKernelRoute(croute, 1, NULL)) { - log(LOG_WARNING, 0, "The insertion into Kernel failed."); - return 0; - } -@@ -351,7 +362,7 @@ - * activated, it's reinstalled in the kernel. If - * the route is activated, no originAddr is needed. - */ --int activateRoute(uint32 group, uint32 originAddr) { -+int activateRoute(uint32 group, uint32 originAddr, int downIf) { - struct RouteTable* croute; - int result = 0; - -@@ -369,21 +380,42 @@ - } - - if(croute != NULL) { -+ struct Origin *o = NULL; -+ int found = 0; -+ - // If the origin address is set, update the route data. -- if(originAddr > 0) { -- if(croute->originAddr > 0 && croute->originAddr!=originAddr) { -- log(LOG_WARNING, 0, "The origin for route %s changed from %s to %s", -- inetFmt(croute->group, s1), -- inetFmt(croute->originAddr, s2), -- inetFmt(originAddr, s3)); -- } -- croute->originAddr = originAddr; -- } -+ if(originAddr > 0) { - -- // Only update kernel table if there are listeners ! -- if(croute->vifBits > 0) { -- result = internUpdateKernelRoute(croute, 1); -- } -+ TAILQ_FOREACH(o, &croute->originList, next) { -+ log(LOG_INFO, 0, "Origin for route %s have %s, new %s", -+ inetFmt(croute->group, s1), -+ inetFmt(o->originAddr, s2), -+ inetFmt(originAddr, s3)); -+ if (o->originAddr==originAddr) { -+ found++; -+ break; -+ } -+ } -+ if (!found) { -+ log(LOG_NOTICE, 0, "New origin for route %s is %s, flood %d", -+ inetFmt(croute->group, s1), -+ inetFmt(originAddr, s3), downIf); -+ o = malloc(sizeof(*o)); -+ o->originAddr = originAddr; -+ o->flood = downIf; -+ o->pktcnt = 0; -+ TAILQ_INSERT_TAIL(&croute->originList, o, next); -+ } else { -+ log(LOG_INFO, 0, "Have origin for route %s at %s, pktcnt %d", -+ inetFmt(croute->group, s1), -+ inetFmt(o->originAddr, s3), -+ o->pktcnt); -+ } -+ } -+ -+ // Only update kernel table if there are listeners, but flood upstream! -+ if(croute->vifBits > 0 || downIf >= 0) -+ result = internUpdateKernelRoute(croute, 1, o); - } - IF_DEBUG logRouteTable("Activate Route"); - -@@ -443,7 +475,6 @@ - * route is not found, or not in this state, 0 is returned. - */ - int lastMemberGroupAge(uint32 group) { -- struct Config *conf = getCommonConfig(); - struct RouteTable *croute; - - croute = findRoute(group); -@@ -463,6 +494,7 @@ - */ - int removeRoute(struct RouteTable* croute) { - struct Config *conf = getCommonConfig(); -+ struct Origin *o; - int result = 1; - - // If croute is null, no routes was found. -@@ -477,7 +509,7 @@ - //BIT_ZERO(croute->vifBits); - - // Uninstall current route from kernel -- if(!internUpdateKernelRoute(croute, 0)) { -+ if(!internUpdateKernelRoute(croute, 0, NULL)) { - log(LOG_WARNING, 0, "The removal from Kernel failed."); - result = 0; - } -@@ -503,7 +535,12 @@ - croute->nextroute->prevroute = croute->prevroute; - } - } -+ - // Free the memory, and set the route to NULL... -+ while ((o = TAILQ_FIRST(&croute->originList))) { -+ TAILQ_REMOVE(&croute->originList, o, next); -+ free(o); -+ } - free(croute); - croute = NULL; - -@@ -551,6 +588,36 @@ - } - } - -+ { -+ struct Origin *o, *nxt; -+ struct sioc_sg_req sg_req; -+ -+ sg_req.grp.s_addr = croute->group; -+ for (o = TAILQ_FIRST(&croute->originList); o; o = nxt) { -+ nxt = TAILQ_NEXT(o, next); -+ sg_req.src.s_addr = o->originAddr; -+ if (ioctl(MRouterFD, SIOCGETSGCNT, (char *)&sg_req) < 0) { -+ log(LOG_WARNING, errno, "%s (%s %s)", -+ "age_table_entry: SIOCGETSGCNT failing for", -+ inetFmt(o->originAddr, s1), -+ inetFmt(croute->group, s2)); -+ /* Make sure it gets deleted below */ -+ sg_req.pktcnt = o->pktcnt; -+ } -+ log(LOG_DEBUG, 0, "Aging Origin %s Dst %s PktCnt %d -> %d", -+ inetFmt(o->originAddr, s1), inetFmt(croute->group, s2), -+ o->pktcnt, sg_req.pktcnt); -+ if (sg_req.pktcnt == o->pktcnt) { -+ /* no traffic, remove from kernel cache */ -+ internUpdateKernelRoute(croute, 0, o); -+ TAILQ_REMOVE(&croute->originList, o, next); -+ free(o); -+ } else { -+ o->pktcnt = sg_req.pktcnt; -+ } -+ } -+ } -+ - // If the aging counter has reached zero, its time for updating... - if(croute->ageValue == 0) { - // Check for activity in the aging process, -@@ -560,7 +627,7 @@ - inetFmt(croute->group,s1)); - - // Just update the routing settings in kernel... -- internUpdateKernelRoute(croute, 1); -+ internUpdateKernelRoute(croute, 1, NULL); - - // We append the activity counter to the age, and continue... - croute->ageValue = croute->ageActivity; -@@ -586,34 +653,57 @@ - /** - * Updates the Kernel routing table. If activate is 1, the route - * is (re-)activated. If activate is false, the route is removed. -+* if 'origin' is given, only the route with 'origin' will be -+* updated, otherwise all MFC routes for the group will updated. - */ --int internUpdateKernelRoute(struct RouteTable *route, int activate) { -+int internUpdateKernelRoute(struct RouteTable *route, int activate, struct Origin *origin) { - struct MRouteDesc mrDesc; - struct IfDesc *Dp; - unsigned Ix; -- -- if(route->originAddr>0) { -+ struct Origin *o; -+ -+ if (TAILQ_EMPTY(&route->originList)) { -+ log(LOG_NOTICE, 0, "Route is not active. No kernel updates done."); -+ return 1; -+ } -+ TAILQ_FOREACH(o, &route->originList, next) { -+ if (origin && origin != o) -+ continue; - - // Build route descriptor from table entry... - // Set the source address and group address... - mrDesc.McAdr.s_addr = route->group; -- mrDesc.OriginAdr.s_addr = route->originAddr; -+ mrDesc.OriginAdr.s_addr = o->originAddr; - - // clear output interfaces - memset( mrDesc.TtlVc, 0, sizeof( mrDesc.TtlVc ) ); - -- IF_DEBUG log(LOG_DEBUG, 0, "Vif bits : 0x%08x", route->vifBits); -- -+ IF_DEBUG log(LOG_DEBUG, 0, "Origin %s Vif bits : 0x%08x", inetFmt(o->originAddr, s1), route->vifBits); - // Set the TTL's for the route descriptor... -- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) { -- if(Dp->state == IF_STATE_UPSTREAM) { -- //IF_DEBUG log(LOG_DEBUG, 0, "Identified VIF #%d as upstream.", Dp->index); -- mrDesc.InVif = Dp->index; -- } -- else if(BIT_TST(route->vifBits, Dp->index)) { -- IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for Vif %d to %d", Dp->index, Dp->threshold); -- mrDesc.TtlVc[ Dp->index ] = Dp->threshold; -- } -+ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) { -+ if (o->flood >= 0) { -+ if(Ix == (unsigned) o->flood) { -+ IF_DEBUG log(LOG_DEBUG, 0, "Identified Input VIF #%d as DOWNSTREAM.", Dp->index); -+ mrDesc.InVif = Dp->index; -+ } -+ else if(Dp->state == IF_STATE_UPSTREAM) { -+ IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for UPSTREAM Vif %d to %d", Dp->index, Dp->threshold); -+ mrDesc.TtlVc[ Dp->index ] = Dp->threshold; -+ } -+ else if(BIT_TST(route->vifBits, Dp->index)) { -+ IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for DOWNSTREAM Vif %d to %d", Dp->index, Dp->threshold); -+ mrDesc.TtlVc[ Dp->index ] = Dp->threshold; -+ } -+ } else { -+ if(Dp->state == IF_STATE_UPSTREAM) { -+ IF_DEBUG log(LOG_DEBUG, 0, "Identified VIF #%d as upstream.", Dp->index); -+ mrDesc.InVif = Dp->index; -+ } -+ else if(BIT_TST(route->vifBits, Dp->index)) { -+ IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for Vif %d to %d", Dp->index, Dp->threshold); -+ mrDesc.TtlVc[ Dp->index ] = Dp->threshold; -+ } -+ } - } - - // Do the actual Kernel route update... -@@ -625,9 +715,6 @@ - // Delete the route from Kernel... - delMRoute( &mrDesc ); - } -- -- } else { -- log(LOG_NOTICE, 0, "Route is not active. No kernel updates done."); - } - - return 1; -@@ -647,16 +734,17 @@ - log(LOG_DEBUG, 0, "No routes in table..."); - } else { - do { -- /* -- log(LOG_DEBUG, 0, "#%d: Src: %s, Dst: %s, Age:%d, St: %s, Prev: 0x%08x, T: 0x%08x, Next: 0x%08x", -- rcount, inetFmt(croute->originAddr, s1), inetFmt(croute->group, s2), -- croute->ageValue,(croute->originAddr>0?"A":"I"), -- croute->prevroute, croute, croute->nextroute); -- */ -- log(LOG_DEBUG, 0, "#%d: Src: %s, Dst: %s, Age:%d, St: %s, OutVifs: 0x%08x", -- rcount, inetFmt(croute->originAddr, s1), inetFmt(croute->group, s2), -- croute->ageValue,(croute->originAddr>0?"A":"I"), -- croute->vifBits); -+ log(LOG_DEBUG, 0, "#%d: Dst: %s, Age:%d, St: %s, OutVifs: 0x%08x", -+ rcount, inetFmt(croute->group, s2), -+ croute->ageValue,(TAILQ_EMPTY(&croute->originList)?"I":"A"), -+ croute->vifBits); -+ { -+ struct Origin *o; -+ TAILQ_FOREACH(o, &croute->originList, next) { -+ log(LOG_DEBUG, 0, "#%d: Origin: %s floodIf %d pktcnt %d", -+ rcount, inetFmt(o->originAddr, s1), o->flood, o->pktcnt); -+ } -+ } - - croute = croute->nextroute; - ---- src/syslog.c.orig 2005-05-24 16:48:19.000000000 +0100 -+++ src/syslog.c 2009-03-18 14:38:38.000000000 +0000 -@@ -53,12 +53,16 @@ - ** is logged to 'stderr'. - ** - */ -+#ifdef DEVEL_LOGGING -+void _log( int Serverity, int Errno, const char *func, int line, const char *FmtSt, ... ) -+#else - void log( int Serverity, int Errno, const char *FmtSt, ... ) -+#endif - { - const char ServVc[][ 5 ] = { "EMER", "ALER", "CRIT", "ERRO", - "Warn", "Note", "Info", "Debu" }; - -- const char *ServPt = Serverity < 0 || Serverity >= VCMC( ServVc ) ? -+ const char *ServPt = Serverity < 0 || Serverity >= (int) VCMC( ServVc ) ? - "!unknown serverity!" : ServVc[ Serverity ]; - - const char *ErrSt = (Errno <= 0) ? NULL : (const char *)strerror( Errno ); -@@ -69,6 +73,9 @@ - - va_start( ArgPt, FmtSt ); - Ln = snprintf( LogLastMsg, sizeof( LogLastMsg ), "%s: ", ServPt ); -+#ifdef DEVEL_LOGGING -+ Ln += snprintf( LogLastMsg + Ln, sizeof( LogLastMsg ) - Ln, "%s():%d: ", func, line); -+#endif - Ln += vsnprintf( LogLastMsg + Ln, sizeof( LogLastMsg ) - Ln, FmtSt, ArgPt ); - if( ErrSt ) - snprintf( LogLastMsg + Ln, sizeof( LogLastMsg ) - Ln, "; Errno(%d): %s", Errno, ErrSt );