File extensions.diff of Package openslp.3206

--- ./common/slp_compare.c.orig	2012-12-12 19:12:43.000000000 +0000
+++ ./common/slp_compare.c	2014-04-10 14:54:49.730301497 +0000
@@ -414,6 +414,16 @@ int SLPCompareNamingAuth(size_t srvtypel
    if (namingauthlen == 0xffff)
       return 0;            /* match all naming authorities */
 
+    /* skip "service:" */
+   if(srvtypelen > 8 && strncasecmp(srvtype, "service:", 8) == 0)
+   {   
+      srvtypelen -= 8;
+      srvtype += 8;
+   }   
+   dot = memchr(srvtype, ':', srvtypelen);
+   if (dot)
+      srvtypelen = dot - srvtype;
+
    dot = memchr(srvtype, '.', srvtypelen);
    if (!namingauthlen)
       return dot? 1: 0;    /* IANA naming authority */
--- ./common/slp_message.h.orig	2012-12-07 20:13:28.000000000 +0000
+++ ./common/slp_message.h	2014-04-10 14:54:49.730301497 +0000
@@ -127,6 +127,11 @@
 #define SLP_REG_SOURCE_LOCAL     2  /* from localhost or IPC */
 #define SLP_REG_SOURCE_STATIC    3  /* from the slp.reg file */
 
+#define SLP_REG_WATCH_TCP        (1<<0)
+#define SLP_REG_WATCH_UDP        (1<<1)
+#define SLP_REG_WATCH_CHECKING   (1<<8)
+#define SLP_REG_WATCH_DEAD       (1<<9)
+
 /** SLP Extension IDs */
 
 /** @todo Deprecate the use of the experimental version of the PID watcher
@@ -275,6 +280,8 @@ typedef struct _SLPSrvReg
    SLPAuthBlock * autharray;
    /* The following are used for OpenSLP specific extensions */
    uint32_t pid;
+   int watchport;
+   int watchflags;
    int source;    /*!< convenience */
 } SLPSrvReg;
 
--- ./common/slp_property.c.orig	2012-12-10 23:31:53.000000000 +0000
+++ ./common/slp_property.c	2014-04-10 14:54:49.730301497 +0000
@@ -80,12 +80,17 @@ static SLPList s_PropertyList = {0, 0, 0
 
 /** The (optional) application-specified property file - module static. */
 static char s_AppPropertyFile[MAX_PATH] = "";
+static FILE *s_AppPropertyFp;
 
 /** The (optional) environment-specified property file - module static. */
 static char s_EnvPropertyFile[MAX_PATH] = "";
+static FILE *s_EnvPropertyFp;
 
 /** The (optional) global property file - module static. */
 static char s_GlobalPropertyFile[MAX_PATH] = "";
+static FILE *s_GlobalPropertyFp;
+
+static int s_UsePropertyFps = 0;
 
 /** The database lock - module static. */
 static SLPMutexHandle s_PropDbLock;
@@ -285,9 +290,9 @@ static void InitializeMTUPropertyValue()
  *
  * @internal
  */
-static bool ReadFileProperties(char const * conffile)
+static bool ReadFileProperties(char const * conffile, FILE *conffp)
 {
-   FILE * fp;
+   FILE * fp = NULL;
    char * alloced;
    bool retval = false;
 
@@ -297,8 +302,11 @@ static bool ReadFileProperties(char cons
    if ((alloced = xmalloc(CONFFILE_RDBUFSZ)) == 0)
       return false;
 
+   if (conffp)
+      rewind(conffp);
+
    /* open configuration file for read - missing file returns false */
-   if ((fp = fopen(conffile, "r")) != 0)
+   if ((fp = s_UsePropertyFps ? conffp : fopen(conffile, "r")) != 0)
    {
       /* read a line at a time - max 4k characters per line */
       while (fgets(alloced, CONFFILE_RDBUFSZ, fp))
@@ -356,7 +364,8 @@ static bool ReadFileProperties(char cons
          if (*valuestart)
             SLPPropertySet(namestart, valuestart, 0);
       }
-      fclose(fp);
+      if (!s_UsePropertyFps)
+         fclose(fp);
       retval = true;
    }
    xfree(alloced);
@@ -383,21 +392,32 @@ static int ReadPropertyFiles(void)
    if (SetDefaultValues() != 0)
       return -1;
 
+   if (s_UsePropertyFps == 1)
+   {
+      if (*s_GlobalPropertyFile)
+         s_GlobalPropertyFp = fopen(s_GlobalPropertyFile, "r");
+      if (*s_EnvPropertyFile)
+         s_EnvPropertyFp = fopen(s_EnvPropertyFile, "r");
+      if (*s_AppPropertyFile)
+         s_AppPropertyFp = fopen(s_AppPropertyFile, "r");
+      s_UsePropertyFps = 2;
+   }
+
    /* read global, and then app configuration files */
    if (*s_GlobalPropertyFile)
-      if (ReadFileProperties(s_GlobalPropertyFile))
+      if (ReadFileProperties(s_GlobalPropertyFile, s_GlobalPropertyFp))
          SLPPropertySet("net.slp.OpenSLPConfigFile",
                s_GlobalPropertyFile, SLP_PA_READONLY);
 
    /* read environment specified configuration file */
    if (*s_EnvPropertyFile)
-      if (ReadFileProperties(s_EnvPropertyFile))
+      if (ReadFileProperties(s_EnvPropertyFile, s_EnvPropertyFp))
          SLPPropertySet("net.slp.EnvConfigFile",
                s_EnvPropertyFile, SLP_PA_READONLY);
 
    /* if set, read application-specified configuration file */
    if (*s_AppPropertyFile)
-      if (ReadFileProperties(s_AppPropertyFile))
+      if (ReadFileProperties(s_AppPropertyFile, s_AppPropertyFp))
          SLPPropertySet("net.slp.AppConfigFile",
                s_AppPropertyFile, SLP_PA_READONLY);
 
@@ -865,6 +885,11 @@ int SLPPropertyInit(const char * gconffi
    return sts;
 }
 
+void SLPPropertyKeepFps()
+{
+   s_UsePropertyFps = 1;
+}
+
 /** Release all globally held resources held by the property module.
  *
  * Free all associated property database memory, and destroy the database
@@ -878,6 +903,14 @@ int SLPPropertyInit(const char * gconffi
 void SLPPropertyExit(void)
 {
    SLPPropertyCleanup();
+   if (s_GlobalPropertyFp)
+      fclose(s_GlobalPropertyFp);
+   if (s_EnvPropertyFp)
+      fclose(s_EnvPropertyFp);
+   if (s_AppPropertyFp)
+      fclose(s_AppPropertyFp);
+   s_GlobalPropertyFp = s_EnvPropertyFp = s_AppPropertyFp = NULL;
+   s_UsePropertyFps = 0;
    SLPMutexDestroy(s_PropDbLock);
    s_PropertiesInitialized = false;
 }
--- ./common/slp_property.h.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./common/slp_property.h	2014-04-10 14:54:49.730301497 +0000
@@ -66,6 +66,7 @@ int SLPPropertySetAppConfFile(const char
 int SLPPropertyReinit(void);
 int SLPPropertyInit(const char * gconffile);
 void SLPPropertyExit(void);
+void SLPPropertyKeepFps(void);
 
 /*! Special function to access MTU configuration property value. This provides
  *  fast access to the MTU value both in client libraries and server program.
--- ./common/slp_spi.c.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./common/slp_spi.c	2014-04-10 14:54:49.730301497 +0000
@@ -426,6 +426,17 @@ int SLPSpiCanSign(SLPSpiHandle hspi, siz
          spistrlen, spistr) != 0;
 }
 
+void SLPSpiFill(SLPSpiHandle hspi)
+{
+   SLPSpiEntry* entry = (SLPSpiEntry*)hspi->cache.head;
+   while (entry)
+   {
+      if (entry->keytype != SLPSPI_KEY_TYPE_PRIVATE || hspi->cacheprivate)
+         entry->key = SLPSpiReadKeyFile(entry->keyfilename, entry->keytype);
+      entry = (SLPSpiEntry*)entry->listitem.next;
+   }
+}
+
 #endif   /* ENABLE_SLPv2_SECURITY */
 
 /*=========================================================================*/
--- ./common/slp_spi.h.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./common/slp_spi.h	2014-04-10 14:54:49.730301497 +0000
@@ -106,6 +106,8 @@ int SLPSpiCanVerify(SLPSpiHandle hspi, s
 
 int SLPSpiCanSign(SLPSpiHandle hspi, size_t spistrlen, const char * spistr);
 
+void SLPSpiFill(SLPSpiHandle hspi);
+
 #endif   /* ENABLE_SLPv2_SECURITY */
 
 /*! @} */
--- ./libslp/libslp_findsrvs.c.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./libslp/libslp_findsrvs.c	2014-04-10 14:54:49.731301477 +0000
@@ -64,7 +64,7 @@
  */
 static SLPBoolean CollateToSLPSrvURLCallback(SLPHandle hSLP, 
       const char * pcSrvURL, unsigned short sLifetime, 
-      SLPError errorcode)
+      SLPError errorcode, void *peeraddr)
 {
    int maxResults;
    SLPHandleInfo * handle = hSLP;
@@ -110,13 +110,19 @@ static SLPBoolean CollateToSLPSrvURLCall
    if (collateditem == 0)
    {
       collateditem = xmalloc(sizeof(SLPSrvUrlCollatedItem) 
-            + strlen(pcSrvURL) + 1);
+            + strlen(pcSrvURL) + 1 + sizeof(struct sockaddr_storage));
       if (collateditem)
       {
          memset(collateditem, 0, sizeof(SLPSrvUrlCollatedItem));
          collateditem->srvurl = (char *)(collateditem + 1);
          strcpy(collateditem->srvurl, pcSrvURL);
          collateditem->lifetime = sLifetime;
+         if (((struct sockaddr_storage *)peeraddr)->ss_family == AF_INET)
+            memcpy(collateditem->srvurl + strlen(pcSrvURL) + 1, peeraddr, sizeof(struct sockaddr_in));
+         else if (((struct sockaddr_storage *)peeraddr)->ss_family == AF_INET6)
+            memcpy(collateditem->srvurl + strlen(pcSrvURL) + 1, peeraddr, sizeof(struct sockaddr_in6));
+         else
+            memset(collateditem->srvurl + strlen(pcSrvURL) + 1, 0, sizeof(struct sockaddr_storage));
 
          /* Add the new item to the collated list. */
          SLPListLinkTail(&handle->collatedsrvurls, 
@@ -144,6 +150,37 @@ CLEANUP:
    return SLP_FALSE;
 }
 
+char * SLPAPI SLPGetPeer(SLPHandle hSLP, const char *pcURL)
+{
+   SLPHandleInfo * handle = hSLP;
+   SLPSrvUrlCollatedItem * collateditem;
+   struct sockaddr_storage addr;
+
+   /*------------------------------*/
+   /* check for invalid parameters */
+   /*------------------------------*/
+   if(handle == 0 || handle->sig != SLP_HANDLE_SIG
+        || pcURL == 0 || pcURL[0] == 0)
+      return 0;
+
+   collateditem = (SLPSrvUrlCollatedItem *)handle->collatedsrvurls.head;
+   while (collateditem)
+   {
+      if (strcmp(collateditem->srvurl, pcURL) == 0)
+      {
+          memcpy((char *)&addr, collateditem->srvurl + strlen(collateditem->srvurl) + 1, sizeof(struct sockaddr_storage));
+          if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6)
+          {
+              char addr_str[INET6_ADDRSTRLEN];
+              return xstrdup(SLPNetSockAddrStorageToString(&addr, addr_str, sizeof(addr_str)));
+          }
+          return 0;
+      }
+      collateditem = (SLPSrvUrlCollatedItem*)collateditem->listitem.next;
+   }
+   return 0;
+}
+
 /** SLPFindSrvs callback routine for NetworkRqstRply.
  *
  * @param[in] errorcode - The network operation error code.
@@ -168,7 +205,7 @@ static SLPBoolean ProcessSrvRplyCallback
 
    /* Check the errorcode and bail if it is set. */
    if (errorcode != SLP_OK)
-      return CollateToSLPSrvURLCallback(handle, 0, 0, errorcode);
+      return CollateToSLPSrvURLCallback(handle, 0, 0, errorcode, peeraddr);
 
    /* parse the replybuf */
    replymsg = SLPMessageAlloc();
@@ -191,7 +228,7 @@ static SLPBoolean ProcessSrvRplyCallback
                   continue; /* Authentication failed, skip this URLEntry. */
 #endif
                result = CollateToSLPSrvURLCallback(handle, urlentry[i].url, 
-                     (unsigned short)urlentry[i].lifetime, SLP_OK);
+                     (unsigned short)urlentry[i].lifetime, SLP_OK, peeraddr);
                if (result == SLP_FALSE)
                   break;
             } 
@@ -210,7 +247,7 @@ static SLPBoolean ProcessSrvRplyCallback
 #endif
             result = CollateToSLPSrvURLCallback(handle, 
                   replymsg->body.daadvert.url, SLP_LIFETIME_MAXIMUM, 
-                  SLP_OK);
+                  SLP_OK, peeraddr);
          }
          else if (replymsg->header.functionid == SLP_FUNCT_SAADVERT)
          {
@@ -225,7 +262,7 @@ static SLPBoolean ProcessSrvRplyCallback
 #endif
             result = CollateToSLPSrvURLCallback(handle, 
                   replymsg->body.saadvert.url, SLP_LIFETIME_MAXIMUM, 
-                  SLP_OK);
+                  SLP_OK, peeraddr);
          }
       }
       SLPMessageFree(replymsg);
--- ./libslp/slp.h.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./libslp/slp.h	2014-04-10 14:54:49.731301477 +0000
@@ -606,6 +606,15 @@ SLPEXP SLPError SLPAPI SLPAssociateIP(
       SLPHandle      hSLP, 
       const char *   unicast_ip);
 
+/*=========================================================================
+ * SLPGetPeer() - return the peer info corresponding to a service url.
+ *                may only be called from SLPSrvURLCallback.
+ *                the returned memory needs to be freed with SLPFree()
+ */
+SLPEXP char * SLPAPI SLPGetPeer(
+      SLPHandle hSLP,
+      const char *pcURL);
+
 #if __cplusplus
 }
 #endif
--- ./libslpattr/libslpattr.c.orig	2012-12-10 23:31:53.000000000 +0000
+++ ./libslpattr/libslpattr.c	2014-04-10 14:54:49.731301477 +0000
@@ -393,6 +393,9 @@ static char * unescape_into(char * dest,
       (*cur)++;
    }
 
+   if (type_guess == TYPE_UNKNOWN)
+      return 0;		/* parse error */
+
    *type = type_guess;
    return 1;
 }
--- ./slpd/slpd_database.c.orig	2012-12-10 23:31:53.000000000 +0000
+++ ./slpd/slpd_database.c	2014-04-10 14:54:49.731301477 +0000
@@ -49,6 +49,7 @@
 
 #define _GNU_SOURCE
 #include <string.h>
+#include <dirent.h>
 
 #include "../libslpattr/libslpattr.h"
 #include "slpd_database.h"
@@ -75,6 +76,9 @@
 
 static IndexTreeNode *srvtype_index_tree = (IndexTreeNode *)0;
 
+extern char *reg_file_dir;
+static FILE *regfileFP;
+
 #ifdef ENABLE_PREDICATES
 /** A structure to hold a tag and its index tree
  */
@@ -793,6 +797,9 @@ static int SLPDDatabaseSrvRqstTestEntry(
    /* entry reg is the SrvReg message from the database */
    entryreg = &entry->msg->body.srvreg;
 
+   if ((entryreg->watchflags & SLP_REG_WATCH_DEAD) != 0)
+      return 0;
+
    /* check the service type */
    if (SLPCompareSrvType(srvrqst->srvtypelen, srvrqst->srvtype,
          entryreg->srvtypelen, entryreg->srvtype) == 0
@@ -1347,6 +1354,8 @@ int SLPDDatabaseSrvTypeRqstStart(SLPMess
 
             /* entry reg is the SrvReg message from the database */
             entryreg = &entry->msg->body.srvreg;
+            if ((entryreg->watchflags & SLP_REG_WATCH_DEAD) != 0)
+               continue;
 
             if (SLPCompareNamingAuth(entryreg->srvtypelen, entryreg->srvtype,
                      srvtyperqst->namingauthlen, srvtyperqst->namingauth) == 0
@@ -1416,6 +1425,8 @@ static int SLPDDatabaseAttrRqstProcessEn
    int i;
 #endif
 
+   if ((entryreg->watchflags & SLP_REG_WATCH_DEAD) != 0)
+      return 0;
    if (SLPCompareString(attrrqst->urllen, attrrqst->url,
             entryreg->urlentry.urllen, entryreg->urlentry.url) == 0
          || SLPCompareSrvType(attrrqst->urllen, attrrqst->url,
@@ -1689,18 +1700,18 @@ void * SLPDDatabaseEnumStart(void)
 SLPMessage * SLPDDatabaseEnum(void * eh, SLPMessage ** msg, SLPBuffer * buf)
 {
    SLPDatabaseEntry * entry;
-   entry = SLPDatabaseEnum((SLPDatabaseHandle)eh);
-   if (entry)
+
+   while ((entry = SLPDatabaseEnum((SLPDatabaseHandle)eh)) != 0)
    {
+      if ((entry->msg->body.srvreg.watchflags & SLP_REG_WATCH_DEAD) != 0)
+         continue;
       *msg = entry->msg;
       *buf = entry->buf;
+      return *msg;
    }
-   else
-   {
-      *msg = 0;
-      *buf = 0;
-   }
-   return *msg;
+   *msg = 0;
+   *buf = 0;
+   return 0;
 }
 
 /** End an enumeration started by SLPDDatabaseEnumStart.
@@ -1826,7 +1837,10 @@ int SLPDDatabaseInit(const char * regfil
 #endif /* ENABLE_PREDICATES */
 
    /* Call the reinit function */
-   return SLPDDatabaseReInit(regfile);
+   if (regfileFP)
+      fclose(regfileFP);
+   regfileFP = fopen(regfile, "r");
+   return SLPDDatabaseReInit();
 }
 
 /** Re-initialize the database with changed registrations from a regfile.
@@ -1835,13 +1849,14 @@ int SLPDDatabaseInit(const char * regfil
  *
  * @return Zzero on success, or a non-zero value on error.
  */
-int SLPDDatabaseReInit(const char * regfile)
+int SLPDDatabaseReInit()
 {
    SLPDatabaseHandle dh;
    SLPDatabaseEntry * entry;
    SLPMessage * msg;
    SLPBuffer buf;
-   FILE * fd;
+   DIR * dirfp;
+   struct dirent * direntry;
 
    /* open the database handle and remove all the static registrations
       (the registrations from the /etc/slp.reg) file. */
@@ -1861,26 +1876,170 @@ int SLPDDatabaseReInit(const char * regf
    }
 
    /* read static registration file if any */
-   if (regfile)
+   if (regfileFP)
    {
-      fd = fopen(regfile, "rb");
-      if (fd)
+      rewind(regfileFP);
+      while (SLPDRegFileReadSrvReg(regfileFP, &msg, &buf) == 0)
       {
-         while (SLPDRegFileReadSrvReg(fd, &msg, &buf) == 0)
+         if (SLPDDatabaseReg(msg, buf) != SLP_ERROR_OK)
          {
-            if (SLPDDatabaseReg(msg, buf) != SLP_ERROR_OK)
+            /* Only if the reg *didn't* succeed do we free the memory */
+            SLPMessageFree(msg);
+            SLPBufferFree(buf);
+         }
+      }
+   }
+   dirfp = opendir(reg_file_dir);
+   while (dirfp && (direntry = readdir(dirfp)) != 0)
+   {
+      if (direntry->d_name && direntry->d_name[0] != '.' )
+      {
+         FILE * fp;
+         char filename[1024];
+         snprintf( filename, 1023, "%s/%s", reg_file_dir, direntry->d_name );
+         if (strlen(filename)>4 &&
+            strcmp(filename+strlen(filename)-4, ".reg") == 0 &&
+            (fp = fopen(filename,"rb")) != 0)
+         {
+            while (SLPDRegFileReadSrvReg(fp, &msg, &buf) == 0)
             {
-               /* Only if the reg *didn't* succeed do we free the memory */
-               SLPMessageFree(msg);
-               SLPBufferFree(buf);
+               if (SLPDDatabaseReg(msg, buf) != SLP_ERROR_OK)
+               {
+                  /* Only if the reg *didn't* succeed do we free the memory */
+                  SLPMessageFree(msg);
+                  SLPBufferFree(buf);
+               }
             }
+            fclose(fp);
          }
-         fclose(fd);
       }
    }
+   if (dirfp)
+      closedir(dirfp);
    return 0;
 }
 
+static void SLPDDatabaseWatcher_fd(int fd, int flag, unsigned char *porthash)
+{
+    SLPDatabaseHandle dh;
+    SLPDatabaseEntry * entry;
+    SLPSrvReg * srvreg;
+    char buf[4096], *p[6];
+    int l, o, i, j, k, c, n, port;
+
+    if (fd < 0)
+       return;
+    lseek(fd, (off_t)0, SEEK_SET);
+    o = 0;
+    while ((l = read(fd, buf + o, sizeof(buf) - o)) > 0) {
+       l += o;
+       n = 0;
+       for (;;) {
+           for (i = n; i < l; i++)
+               if (buf[i] == '\n')
+                   break;
+           if (i == l) {
+               if (l > n)
+                   memmove(buf, buf + n, l - n);
+               o = l > n ? l - n : 0;
+               break;
+           }
+           k = 0;
+           for (j = n; j < i; j++) {
+               c = buf[j];
+               if (!(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'F') && !(c >= 'a' && c <= 'f'))
+                   buf[j] = 0;
+               else if ((j == n || buf[j - 1] == 0) && k < 6)
+                   p[k++] = buf + j;
+           }
+           n = i + 1;
+           if (k < 6 || strlen(p[1]) < 8)
+               continue;
+           if (strlen(p[1]) == 8 && strtol(p[1], (char **)0, 16) == htonl(0x7f000001))
+               continue;
+           if ((flag & SLP_REG_WATCH_TCP) != 0 && strtol(p[5], (char **)0, 16) != 10)
+               continue;
+           port = strtol(p[2], (char **)0, 16);
+           if (!(porthash[(port / 8) & 255] & (1 << (port & 7))))
+               continue;
+           dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
+           while ((entry = SLPDatabaseEnum(dh)) != 0) {
+               srvreg = &(entry->msg->body.srvreg);
+               if (!(srvreg->watchflags & flag))
+                   continue;
+               if (port == srvreg->watchport)
+                   srvreg->watchflags &= ~SLP_REG_WATCH_CHECKING;
+           }
+           SLPDatabaseClose(dh);
+       }
+    }
+}
+
+void SLPDDatabaseWatcher(void)
+{
+    static int initialized = 0;
+    static int proctcp, procudp, proctcp6, procudp6;
+    unsigned char porthash[256];
+    int flags, port;
+    SLPDatabaseHandle dh;
+    SLPDatabaseEntry*   entry;
+    SLPSrvReg*          srvreg;
+
+    if (!initialized) {
+       proctcp = open("/proc/net/tcp_listen", O_RDONLY);
+       if (proctcp == -1)
+         proctcp = open("/proc/net/tcp", O_RDONLY);
+       procudp = open("/proc/net/udp", O_RDONLY);
+       proctcp6 = open("/proc/net/tcp6_listen", O_RDONLY);
+       if (proctcp6 == -1)
+         proctcp6 = open("/proc/net/tcp6", O_RDONLY);
+       procudp6 = open("/proc/net/udp6", O_RDONLY);
+       initialized = 1;
+    }
+    flags = 0;
+    memset(porthash,0,sizeof(porthash));
+    dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
+    while ((entry = SLPDatabaseEnum(dh)) != 0) {
+       srvreg = &(entry->msg->body.srvreg);
+       if (!srvreg->watchflags)
+           continue;
+       flags |= srvreg->watchflags;
+       port = srvreg->watchport;
+       porthash[(port / 8) & 255] |= 1 << (port & 7);
+       srvreg->watchflags |= SLP_REG_WATCH_CHECKING;
+    }
+    SLPDatabaseClose(dh);
+    if ((flags & SLP_REG_WATCH_TCP) != 0) {
+       SLPDDatabaseWatcher_fd(proctcp, SLP_REG_WATCH_TCP, porthash);
+       SLPDDatabaseWatcher_fd(proctcp6, SLP_REG_WATCH_TCP, porthash);
+    }
+    if ((flags & SLP_REG_WATCH_UDP) != 0) {
+       SLPDDatabaseWatcher_fd(procudp, SLP_REG_WATCH_UDP, porthash);
+       SLPDDatabaseWatcher_fd(procudp6, SLP_REG_WATCH_UDP, porthash);
+    }
+    dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
+    while ((entry = SLPDatabaseEnum(dh)) != 0) {
+       srvreg = &(entry->msg->body.srvreg);
+       if (!srvreg->watchflags)
+           continue;
+       switch (srvreg->watchflags & (SLP_REG_WATCH_CHECKING | SLP_REG_WATCH_DEAD)) {
+       case SLP_REG_WATCH_CHECKING:
+           srvreg->watchflags |= SLP_REG_WATCH_DEAD;
+           SLPDKnownDADeRegisterWithAllDas(entry->msg, entry->buf);
+           SLPDLogRegistration("port dead",entry);
+           break;
+       case SLP_REG_WATCH_DEAD:
+           srvreg->watchflags ^= SLP_REG_WATCH_DEAD;
+           SLPDKnownDARegisterWithAllDas(entry->msg, entry->buf);
+           SLPDLogRegistration("port living",entry);
+           break;
+       }
+       srvreg->watchflags &= ~SLP_REG_WATCH_CHECKING;
+    }
+    SLPDatabaseClose(dh);
+}
+
+
 #ifdef DEBUG
 /** Cleans up all resources used by the database.
  */
--- ./slpd/slpd_database.h.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./slpd/slpd_database.h	2014-04-10 14:54:49.732301459 +0000
@@ -103,7 +103,9 @@ SLPMessage * SLPDDatabaseEnum(void * eh,
 void SLPDDatabaseEnumEnd(void * eh);
 int SLPDDatabaseIsEmpty(void);
 int SLPDDatabaseInit(const char * regfile);
-int SLPDDatabaseReInit(const char * regfile);
+int SLPDDatabaseReInit();
+void SLPDDatabaseWatcher(void);
+
 
 #ifdef DEBUG
 void SLPDDatabaseDeinit(void);
--- ./slpd/slpd_knownda.c.orig	2012-12-10 23:31:53.000000000 +0000
+++ ./slpd/slpd_knownda.c	2014-04-10 14:54:49.732301459 +0000
@@ -1836,7 +1836,7 @@ void SLPDKnownDARegisterWithAllDas(SLPMe
 /* Returns: None                                                           */
 /*=========================================================================*/
 {
-   if (msg->header.functionid == SLP_FUNCT_SRVDEREG)
+   if (msg->header.functionid == SLP_FUNCT_SRVREG)
    {
       /* Simply echo the message through as is */
       SLPDKnownDAEcho(msg, buf);
--- ./slpd/slpd_log.c.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./slpd/slpd_log.c	2014-04-10 14:54:49.732301459 +0000
@@ -298,6 +298,7 @@ static void SLPDLogSrvTypeRqstMessage(SL
 {
    (void)srvtyperqst;
    SLPDLog("Message SRVTYPERQST:\n");
+   SLPDLogBuffer("   scope = ", srvtyperqst->scopelistlen, srvtyperqst->scopelist);
 }
 
 /** Logs information about a SrvTypeReply message to the log file.
--- ./slpd/slpd_main.c.orig	2012-12-10 23:31:53.000000000 +0000
+++ ./slpd/slpd_main.c	2014-04-10 14:54:49.732301459 +0000
@@ -66,6 +66,8 @@ int G_SIGINT;     /* Signal being used f
 int G_SIGUSR1;    /* Signal being used to dump information about the database */
 #endif
 
+char *reg_file_dir = "/etc/slp.reg.d";
+
 /** Configures fd_set objects with sockets.
  *
  * @param[in] socklist - The list of sockets that is being currently
@@ -288,11 +290,13 @@ void HandleSigHup(void)
 
 #ifdef ENABLE_SLPv2_SECURITY
    /* Re-initialize SPI stuff*/
+#if 0	/* does not work in chroot, sorry */
    SLPDSpiInit(G_SlpdCommandLine.spifile);
 #endif
+#endif
 
    /* Re-read the static registration file (slp.reg)*/
-   SLPDDatabaseReInit(G_SlpdCommandLine.regfile);
+   SLPDDatabaseReInit();
 
    /* Reopen listening sockets */
    SLPDIncomingReinit();
@@ -318,6 +322,7 @@ void HandleSigAlrm(void)
    SLPDKnownDAStaleDACheck(SLPD_AGE_INTERVAL);
    SLPDKnownDAActiveDiscovery(SLPD_AGE_INTERVAL);
    SLPDDatabaseAge(SLPD_AGE_INTERVAL, G_SlpdProperty.isDA);
+   SLPDDatabaseWatcher();
 }
 
 #ifdef DEBUG
@@ -487,11 +492,18 @@ static int DropPrivileges()
    struct passwd * pwent = getpwnam("daemon");
    if (pwent)
    {
+      if (chroot(reg_file_dir))
+         return 1;
+      reg_file_dir = ".";
+
       if (setgroups(1, &pwent->pw_gid) < 0 || setgid(pwent->pw_gid) < 0
             || setuid(pwent->pw_uid) < 0)
       {
          /* TODO: should we log here and return fail */
+         return 1;
       }
+   } else {
+       return 1;
    }
 #endif
    return 0;
@@ -639,6 +651,7 @@ int main(int argc, char * argv[])
 #endif
 
    /* initialize for the first time */
+   SLPPropertyKeepFps();  /* do not close file descriptors */
    SLPDPropertyReinit();  /*So we get any property-related log messages*/
    if (
 #ifdef ENABLE_SLPv2_SECURITY
@@ -653,6 +666,9 @@ int main(int argc, char * argv[])
    if (G_SlpdProperty.port != SLP_RESERVED_PORT)
       SLPDLog("Using port %d instead of default %d\n", G_SlpdProperty.port, SLP_RESERVED_PORT);
 
+   /* init watcher */
+   SLPDDatabaseWatcher();
+
    /* drop privileges to reduce security risk */
    if (DropPrivileges())
       SLPDFatal("Could not drop privileges\n");
--- ./slpd/slpd_property.c.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./slpd/slpd_property.c	2014-04-10 14:55:49.894966122 +0000
@@ -50,6 +50,24 @@
  */
 SLPDProperty G_SlpdProperty;
 
+static char *SLPDGetCanonHostname()
+{
+   char host[MAX_HOST_NAME];
+ 
+   if(gethostname(host, MAX_HOST_NAME) == 0)
+   {
+      struct addrinfo hints, * ifaddr;
+
+      memset(&hints, 0, sizeof(hints));
+      hints.ai_socktype = SOCK_STREAM;
+      hints.ai_family = AF_UNSPEC;
+      hints.ai_flags = AI_CANONNAME;
+      if (getaddrinfo(host, 0, &hints, &ifaddr) == 0 && ifaddr->ai_canonname && strchr(ifaddr->ai_canonname, '.') != 0)
+         return xstrdup(ifaddr->ai_canonname);
+   }
+   return xstrdup("localhost");
+}
+
 /** Reinitialize the slpd property management subsystem.
  *
  * Clears and rereads configuration parameters from files into the system.
@@ -226,6 +244,9 @@ void SLPDPropertyReinit(void)
    G_SlpdProperty.nextActiveDiscovery = 0;   /* ensures xmit on first call to SLPDKnownDAActiveDiscovery() */
    G_SlpdProperty.nextPassiveDAAdvert = 0;   /* ensures xmit on first call to SLPDKnownDAPassiveDiscovery()*/
 
+   /* set up hostname */
+   G_SlpdProperty.myHostname = SLPDGetCanonHostname();
+   G_SlpdProperty.myHostnameLen = strlen(G_SlpdProperty.myHostname);
 }
 
 /** Initialize the slpd property management subsystem.
@@ -266,6 +287,7 @@ void SLPDPropertyDeinit(void)
    xfree(G_SlpdProperty.ifaceInfo.iface_addr);
    xfree(G_SlpdProperty.ifaceInfo.bcast_addr);
 
+   xfree(G_SlpdProperty.myHostname);
    SLPPropertyExit();
 }
 
--- ./slpd/slpd_property.h.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./slpd/slpd_property.h	2014-04-10 14:54:49.732301459 +0000
@@ -73,6 +73,8 @@ typedef struct _SLPDProperty
    uint16_t port;
    size_t localeLen;
    char * locale;
+   size_t myHostnameLen;
+   char * myHostname;
 
    int indexingPropertiesSet;           /** Indexes are only maintained from startup,
                                          *  and may not be switched on and off without
--- ./slpd/slpd_regfile.c.orig	2012-12-10 23:31:53.000000000 +0000
+++ ./slpd/slpd_regfile.c	2014-04-10 14:54:49.732301459 +0000
@@ -130,6 +130,7 @@ int SLPDRegFileReadSrvReg(FILE * fd, SLP
 {
    char * slider1;
    char * slider2;
+   char * p;
    char line[4096];
 
    struct sockaddr_storage peer;
@@ -154,6 +155,8 @@ int SLPDRegFileReadSrvReg(FILE * fd, SLP
    unsigned char * attrauth = 0;
    int attrauthlen = 0;
 #endif
+   int watchport = 0;
+   int watchflags = 0;
 
    /* give the out params an initial NULL value */
    *buf = 0;
@@ -180,8 +183,18 @@ int SLPDRegFileReadSrvReg(FILE * fd, SLP
          result = SLP_ERROR_INTERNAL_ERROR;
          goto CLEANUP;
       }
+      /* replace "$HOSTNAME" string in url */
+      while ((p = strchr(url, '$')) && !strncmp(p, "$HOSTNAME", 9))
+      {
+         char *_url = xmalloc(strlen(url) - 9 + G_SlpdProperty.myHostnameLen + 1);
+         strncpy(_url, url, p - url);
+         strncpy(_url + (p - url), G_SlpdProperty.myHostname, G_SlpdProperty.myHostnameLen);
+         strcpy(_url + (p - url) + G_SlpdProperty.myHostnameLen, url + (p - url) + 9);
+         xfree(url);
+         url = _url;
+      }
       urllen = strlen(url);
-
+ 
       /* derive srvtype from srvurl */
       srvtype = strstr(slider1, "://");
       if (srvtype == 0)
@@ -313,6 +326,24 @@ int SLPDRegFileReadSrvReg(FILE * fd, SLP
             }
          }
       }
+      else if(strncasecmp(slider1, "tcp-port", 8) == 0 || strncasecmp(slider1, "watch-port-tcp", 14) == 0)
+      {
+         slider2 = strchr(slider1,'=');
+         if (slider2)
+         {
+            watchport = atoi(slider2 + 1);
+            watchflags |= SLP_REG_WATCH_TCP;
+         }
+      }
+      else if(strncasecmp(slider1, "watch-port-udp", 14) == 0)
+      {
+         slider2 = strchr(slider1,'=');
+         if (slider2)
+         {
+            watchport = atoi(slider2 + 1);
+            watchflags |= SLP_REG_WATCH_UDP;
+         }
+      }
       else
       {
          /* line contains an attribute (slow but it works)*/
@@ -517,6 +548,8 @@ int SLPDRegFileReadSrvReg(FILE * fd, SLP
    ((struct sockaddr_in *)&peer)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    result = SLPMessageParseBuffer(&peer, &peer, *buf, *msg);
    (*msg)->body.srvreg.source = SLP_REG_SOURCE_STATIC;
+   (*msg)->body.srvreg.watchflags = watchflags ? (watchflags | SLP_REG_WATCH_DEAD) : 0;
+   (*msg)->body.srvreg.watchport = watchport;
 
 CLEANUP:
 
--- ./slpd/slpd_spi.c.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./slpd/slpd_spi.c	2014-04-10 14:54:49.733301445 +0000
@@ -66,6 +66,8 @@ int SLPDSpiInit(const char * spifile)
       G_SlpdSpiHandle = 0;
    }
    G_SlpdSpiHandle = SLPSpiOpen(spifile,1);
+   if (G_SlpdSpiHandle)
+      SLPSpiFill(G_SlpdSpiHandle);
    return G_SlpdSpiHandle == 0;
 }
 
--- ./slptool/slptool.c.orig	2013-06-08 02:50:38.000000000 +0000
+++ ./slptool/slptool.c	2014-04-10 14:54:49.733301445 +0000
@@ -187,7 +187,17 @@ static SLPBoolean mySrvUrlCallback(SLPHa
    (void)cookie;
 
    if (errcode == SLP_OK)
+   {
+      SLPToolCommandLine* cmdline = cookie;
+      if (cmdline->printpeerinfo)
+      {
+         char *peer = SLPGetPeer(hslp, srvurl);
+         printf("%s\t", peer ? peer : "?");
+         if (peer)
+	    SLPFree(peer);
+      }
       printf("%s,%i\n", srvurl, lifetime);
+   }
 
    return SLP_TRUE;
 }
@@ -218,7 +228,7 @@ void FindSrvs(SLPToolCommandLine * cmdli
       }
 #endif
       result = SLPFindSrvs(hslp, cmdline->cmdparam1, cmdline->scopes,
-                     cmdline->cmdparam2, mySrvUrlCallback, 0);
+                     cmdline->cmdparam2, mySrvUrlCallback, cmdline);
       if (result != SLP_OK)
          printf("errorcode: %i\n", result);
       SLPClose(hslp);
@@ -413,6 +423,11 @@ int ParseCommandLine(int argc, char * ar
             return 1;
       }
 #endif
+      else if (strcasecmp(argv[i], "-p") == 0
+            || strcasecmp(argv[i], "--peerinfo") == 0)
+      {
+         cmdline->printpeerinfo = SLP_TRUE;
+      }
       else if (strcasecmp(argv[i], "findsrvs") == 0)
       {
          cmdline->cmd = FINDSRVS;
@@ -519,6 +534,7 @@ void DisplayUsage()
 #ifndef UNICAST_NOT_SUPPORTED
    printf("      -u (or --unicastifc) followed by a single interface.\n");
 #endif
+   printf("      -p (or --peerinfo) also display the address of the answering server.\n");
    printf("\n");
    printf("   command-and-arguments may be:\n");
    printf("      findsrvs service-type [filter]\n");
--- ./slptool/slptool.h.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./slptool/slptool.h	2014-04-10 14:54:49.733301445 +0000
@@ -107,6 +107,7 @@ typedef struct _SLPToolCommandLine
    const char * cmdparam1;
    const char * cmdparam2;
    const char * cmdparam3;
+   SLPBoolean printpeerinfo;
 } SLPToolCommandLine;
 
 void FindSrvs(SLPToolCommandLine * cmdline);