File openslp.initda.diff of Package openslp.3206

--- ./common/slp_message.h.orig	2016-09-13 10:56:06.324486007 +0000
+++ ./common/slp_message.h	2016-09-13 10:56:14.214459554 +0000
@@ -126,6 +126,7 @@
 #define SLP_REG_SOURCE_REMOTE    1  /* from a remote host    */
 #define SLP_REG_SOURCE_LOCAL     2  /* from localhost or IPC */
 #define SLP_REG_SOURCE_STATIC    3  /* from the slp.reg file */
+#define SLP_REG_SOURCE_PULL_PEER_DA 4 /* from another DA pulled at startup */
 
 #define SLP_REG_WATCH_TCP        (1<<0)
 #define SLP_REG_WATCH_UDP        (1<<1)
--- ./common/slp_property.c.orig	2016-09-13 10:56:06.324486007 +0000
+++ ./common/slp_property.c	2016-09-13 10:56:14.215459551 +0000
@@ -176,6 +176,11 @@ static int SetDefaultValues(void)
    /* Additional properties that are specific to IPv6 */
       {"net.slp.useIPv6", "false", 0},
       {"net.slp.useIPv4", "true", 0},
+
+      {"net.slp.DASyncReg", "false", 0},
+      {"net.slp.isDABackup", "false", 0},
+      {"net.slp.DABackupInterval", "900", 0},
+      {"net.slp.DABackupLocalReg", "false", 0},
    };
 
    int i;
--- ./etc/slp.conf.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./etc/slp.conf	2016-09-13 10:56:14.215459551 +0000
@@ -23,6 +23,20 @@
 # which DAs to use.  (Default is to use dynamic DA discovery)
 ;net.slp.DAAddresses = myDa1,myDa2,myDa3
 
+# Enables backup of registrations to /etc/slp.reg.d/slpd/DABackup.
+;net.slp.isDABackup = true
+
+# A 32 bit integer giving the number of seconds for the DABackup file update.
+# Default is 15 minutes (900 seconds). Ignored if isDA is false.
+;net.slp.DABackupInterval = 900
+
+# Include local registrations in the backup, too. The default is false.
+;net.slp.DABackupLocalReg = true
+
+# Enables slpd to sync service registration between SLP DAs on startup
+# Default is false
+;net.slp.DASyncReg = true
+
 
 #----------------------------------------------------------------------------
 # DA Specific Configuration
--- ./slpd/Makefile.am.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./slpd/Makefile.am	2016-09-13 10:56:14.216459548 +0000
@@ -73,7 +73,8 @@ slpd_SOURCES = \
 	slpd_property.c \
 	slpd_regfile.c \
 	slpd_socket.c\
-	slpd_index.c
+	slpd_index.c \
+	slpd_initda.c
 
 noinst_HEADERS = \
 	$(slp_predicate_HDRS) \
@@ -90,7 +91,8 @@ noinst_HEADERS = \
 	slpd_regfile.h \
 	slpd_incoming.h \
 	slpd_socket.h\
-	slpd_index.h
+	slpd_index.h \
+	slpd_initda.h
     
 #if you're building on Irix, replace .la with .a below
 slpd_LDADD = ../common/libcommonslpd.la ../libslpattr/libslpattr.la
--- ./slpd/slpd_database.c.orig	2016-09-13 10:56:06.332485980 +0000
+++ ./slpd/slpd_database.c	2016-09-13 10:56:14.217459544 +0000
@@ -50,6 +50,7 @@
 #define _GNU_SOURCE
 #include <string.h>
 #include <dirent.h>
+#include <time.h>
 #include <sys/socket.h>
 #include <linux/netlink.h>
 #include <linux/inet_diag.h>
@@ -531,7 +532,7 @@ int SLPDDatabaseReg(SLPMessage * msg, SL
             {
                /* check to ensure the source addr is the same
                   as the original */
-               if (G_SlpdProperty.checkSourceAddr)
+               if (G_SlpdProperty.checkSourceAddr && entryreg->source != SLP_REG_SOURCE_PULL_PEER_DA)
                {
                   if ((entry->msg->peer.ss_family == AF_INET
                         && msg->peer.ss_family == AF_INET
@@ -567,6 +568,16 @@ int SLPDDatabaseReg(SLPMessage * msg, SL
                   return SLP_ERROR_AUTHENTICATION_FAILED;
                }
 #endif
+               if (reg->source == SLP_REG_SOURCE_PULL_PEER_DA && entryreg->source != SLP_REG_SOURCE_PULL_PEER_DA)
+               {
+                  /* Do not update not-pulled registrations with pulled ones */
+                  SLPDatabaseClose(dh);
+                  freeNormalisedSrvtype(pNormalisedSrvtype);
+                  if (attr)
+                     SLPAttrFree(attr);
+                  return SLP_ERROR_OK;
+               }
+
                /* Remove the identical entry */
                SLPDDatabaseRemove(dh, entry);
                break;
@@ -697,7 +708,7 @@ int SLPDDatabaseDeReg(SLPMessage * msg)
             {
                /* Check to ensure the source addr is the same as */
                /* the original */
-               if (G_SlpdProperty.checkSourceAddr)
+               if (G_SlpdProperty.checkSourceAddr && entryreg->source != SLP_REG_SOURCE_PULL_PEER_DA)
                {
                   if ((entry->msg->peer.ss_family == AF_INET
                         && msg->peer.ss_family == AF_INET
@@ -1054,7 +1065,7 @@ static int SLPDDatabaseSrvRqstStartScan(
 #ifdef ENABLE_PREDICATES
       SLPDPredicateTreeNode *parse_tree,
 #endif
-      SLPDDatabaseSrvRqstResult ** result)
+      SLPDDatabaseSrvRqstResult ** result, int nopulled)
 {
    SLPDatabaseHandle dh;
    SLPDatabaseEntry * entry;
@@ -1074,6 +1085,9 @@ static int SLPDDatabaseSrvRqstStartScan(
          if (entry == 0)
             return 0; /* This is the only successful way out */
 
+         if (nopulled && entry->msg->body.srvreg.source == SLP_REG_SOURCE_PULL_PEER_DA)
+            continue;
+
          if (SLPDDatabaseSrvRqstTestEntry(msg,
 #ifdef ENABLE_PREDICATES
                                           parse_tree,
@@ -1150,6 +1164,20 @@ int SLPDDatabaseSrvRqstStart(SLPMessage
          /* rewind enumeration in case we had to reallocate */
          SLPDatabaseRewind(dh);
 
+         if (srvrqst->predicatelen == 29 && !strncmp(srvrqst->predicate, "(!(openslp-pulled-from-da=*))", 29))
+         {
+            /* this is the special "no pulled entries" predicate used in DA syncing */
+            start_result = SLPDDatabaseSrvRqstStartScan(msg,
+#ifdef ENABLE_PREDICATES
+                                                        predicate_parse_tree,
+#endif
+                                                        result, 1);
+            if (start_result == 0)
+               return 0;
+             G_SlpdDatabase.urlcount *= 2;
+             continue;
+         }
+
          /* Check if we can use the srvtype index */
          if (G_SlpdProperty.srvtypeIsIndexed)
          {
@@ -1277,7 +1305,7 @@ int SLPDDatabaseSrvRqstStart(SLPMessage
 #ifdef ENABLE_PREDICATES
                                                            predicate_parse_tree,
 #endif
-                                                           result);
+                                                           result, 0);
          }
 #ifdef ENABLE_PREDICATES
          if (predicate_parse_tree)
@@ -1883,7 +1911,7 @@ int SLPDDatabaseReInit()
    if (regfileFP)
    {
       rewind(regfileFP);
-      while (SLPDRegFileReadSrvReg(regfileFP, &msg, &buf) == 0)
+      while (SLPDRegFileReadSrvReg(regfileFP, SLP_REG_SOURCE_STATIC, &msg, &buf) == 0)
       {
          if (SLPDDatabaseReg(msg, buf) != SLP_ERROR_OK)
          {
@@ -1905,7 +1933,7 @@ int SLPDDatabaseReInit()
             strcmp(filename+strlen(filename)-4, ".reg") == 0 &&
             (fp = fopen(filename,"rb")) != 0)
          {
-            while (SLPDRegFileReadSrvReg(fp, &msg, &buf) == 0)
+            while (SLPDRegFileReadSrvReg(fp, SLP_REG_SOURCE_STATIC, &msg, &buf) == 0)
             {
                if (SLPDDatabaseReg(msg, buf) != SLP_ERROR_OK)
                {
@@ -2211,6 +2239,65 @@ void SLPDDatabaseWatcher(void)
 }
 
 
+void SLPDDatabaseReadDABackup(FILE *fp)
+{
+    SLPMessage * msg;
+    SLPBuffer buf;
+    time_t timediff;
+    long l;
+
+    SLPDLog("Reading registration backup file...\n");
+    rewind(fp);
+    if (fscanf(fp, "# Update timestamp: %ld\n", &l) != 1)
+	return;
+    timediff = time(NULL) - (time_t)l;
+    if (timediff < 0)
+	timediff = 0;
+    while (SLPDRegFileReadSrvReg(fp, SLP_REG_SOURCE_REMOTE, &msg, &buf) == 0)
+    {
+	if (!G_SlpdProperty.DABackupLocalReg && msg->body.srvreg.source == SLP_REG_SOURCE_LOCAL)
+	{
+	    SLPMessageFree(msg);
+	    SLPBufferFree(buf);
+	    continue;
+	}
+	msg->body.srvreg.urlentry.lifetime -= timediff;
+	if (msg->body.srvreg.urlentry.lifetime > 0)
+	    SLPDDatabaseReg(msg, buf);
+	else
+	{
+	    SLPMessageFree(msg);
+	    SLPBufferFree(buf);
+	}
+    }
+}
+
+void SLPDDatabaseWriteDABackup(FILE *fp)
+{
+    SLPDatabaseHandle   dh;
+    SLPDatabaseEntry*   entry;
+
+    SLPDLog("Writing registration backup file...\n");
+    rewind(fp);
+    (void)ftruncate(fileno(fp), 0);
+    fprintf(fp, "# Update timestamp: %ld\n\n", (long)time(NULL));
+    dh = SLPDatabaseOpen(&G_SlpdDatabase.database);
+    if (dh)
+    {
+	while ((entry = SLPDatabaseEnum(dh)) != NULL)
+	{
+	    if (entry->msg->body.srvreg.source == SLP_REG_SOURCE_STATIC)
+		continue;
+	    if (!G_SlpdProperty.DABackupLocalReg && entry->msg->body.srvreg.source == SLP_REG_SOURCE_LOCAL)
+		continue;
+	    SLPDRegFileWriteSrvReg(fp, entry->msg);
+	}
+	SLPDatabaseClose(dh);
+    }
+    fflush(fp);
+}
+
+
 #ifdef DEBUG
 /** Cleans up all resources used by the database.
  */
--- ./slpd/slpd_database.h.orig	2016-09-13 10:56:06.326486000 +0000
+++ ./slpd/slpd_database.h	2016-09-13 10:56:14.217459544 +0000
@@ -105,7 +105,8 @@ int SLPDDatabaseIsEmpty(void);
 int SLPDDatabaseInit(const char * regfile);
 int SLPDDatabaseReInit();
 void SLPDDatabaseWatcher(void);
-
+void SLPDDatabaseReadDABackup(FILE *fp);
+void SLPDDatabaseWriteDABackup(FILE *fp);
 
 #ifdef DEBUG
 void SLPDDatabaseDeinit(void);
--- ./slpd/slpd_initda.c.orig	2016-09-13 10:56:14.218459541 +0000
+++ ./slpd/slpd_initda.c	2016-09-13 10:56:14.218459541 +0000
@@ -0,0 +1,396 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "slpd.h"
+#include "slp_message.h"
+#include "slp_property.h"
+#include "slp_network.h"
+#include "slpd_database.h"
+#include "slpd_regfile.h"
+#include "slpd_property.h"
+#include "slpd_log.h"
+
+
+#define SLP_NETWORK_TIMED_OUT		-19
+#define SLP_MEMORY_ALLOC_FAILED		-21
+#define SLP_NETWORK_ERROR		-23
+
+static int SLPDUnicastRqstRply(int sock, struct sockaddr_storage * destaddr, struct sockaddr_storage * localaddr,
+    const char * langtag, char * buf, char buftype, int bufsize,
+    int (*callback)(SLPMessage * message, void *cookie), void * cookie)
+{
+    struct timeval timeout;
+    SLPBuffer sendbuf = 0;
+    SLPBuffer recvbuf = 0;
+    SLPMessage * message = 0;
+    int result = 0;
+    int langtaglen = 0; 
+    int xid = 0;
+    int mtu = 0;
+    int size = 0;
+    int timeouts[1];
+
+    /* Save off a few things we don't want to recalculate */
+    langtaglen = strlen(langtag);
+    xid = SLPXidGenerate();
+    mtu = SLPPropertyAsInteger("net.slp.MTU");
+    sendbuf = SLPBufferAlloc(mtu);
+    if(sendbuf == 0)
+    {
+        result = SLP_MEMORY_ALLOC_FAILED;
+	goto FINISHED;
+    }
+    SLPPropertyAsIntegerVector("net.slp.unicastTimeouts", timeouts, 1);
+    timeout.tv_sec = timeouts[0] / 1000;
+    timeout.tv_usec = (timeouts[0] % 1000) * 1000;
+    size = 16 + langtaglen + bufsize;
+    if((sendbuf = SLPBufferRealloc(sendbuf, size)) == 0)
+    {
+	result = SLP_MEMORY_ALLOC_FAILED;
+	goto FINISHED;
+    }
+    sendbuf->curpos = sendbuf->start;
+
+    /* Add the header to the send buffer */
+    /*version*/
+    *sendbuf->curpos++ = 2;
+    /*function id*/
+    *sendbuf->curpos++ = buftype;
+    /*length*/
+    PutUINT24(&sendbuf->curpos, size);
+    /*flags*/
+    PutUINT16(&sendbuf->curpos, SLP_FLAG_UCAST);  /*this is a unicast */
+    /*ext offset*/
+    PutUINT24(&sendbuf->curpos, 0);
+    /*xid*/
+    PutUINT16(&sendbuf->curpos, xid);
+    /*lang tag len*/
+    PutUINT16(&sendbuf->curpos, langtaglen);
+    /*lang tag*/
+    memcpy(sendbuf->curpos, langtag, langtaglen);
+    sendbuf->curpos += langtaglen;
+    /*prlist*/
+    PutUINT16(&sendbuf->curpos, 0);
+
+    /* Add the rest of the message */
+    memcpy(sendbuf->curpos, buf, bufsize);
+    sendbuf->curpos += bufsize;
+
+    /* send the send buffer */
+    result = SLPNetworkSendMessage(sock, SOCK_STREAM, sendbuf, sendbuf->curpos - sendbuf->start, destaddr, &timeout);
+    if (result != 0)
+    {
+	result = errno == ETIMEDOUT ? SLP_NETWORK_TIMED_OUT : SLP_NETWORK_ERROR;
+	goto FINISHED;
+    }
+    result = SLPNetworkRecvMessage(sock, SOCK_STREAM, &recvbuf, destaddr, &timeout);
+    if (result != 0)
+    {
+	result = errno == ETIMEDOUT ? SLP_NETWORK_TIMED_OUT : SLP_NETWORK_ERROR;
+	goto FINISHED;
+    }
+    if(AS_UINT16(recvbuf->start + 10) != xid)
+    {
+	result = SLP_NETWORK_ERROR;
+	goto FINISHED;
+    }
+    message = SLPMessageAlloc();
+    result = SLPMessageParseBuffer(destaddr, localaddr, recvbuf, message);
+    if (result == 0)
+    {
+	result = callback(message, cookie);
+    }
+FINISHED:
+    SLPMessageFree(message);
+    SLPBufferFree(sendbuf);
+    SLPBufferFree(recvbuf);
+    return result;
+}
+
+typedef struct SLPURL {
+    struct SLPURL *next;
+    struct SLPURL *last;
+    char *serviceURL;
+    char *attrs;
+    char* scopelist;
+    char* serviceType;      
+    unsigned short ltime;
+} SLPUrl;
+
+
+/* Cache collection structure */
+typedef struct SLPUrlList {
+    char * services; /* list of all services */
+    SLPUrl * slpUrl; /* linked list of URLs for all services */
+    SLPUrl * currentSLPUrl;  /* next location to be used for update */
+    char * currentScope;
+    char * currentServiceType;
+} SLPUrlList;  
+
+static SLPUrl * AllocateSLPUrl()
+{
+    SLPUrl* slpUrl          = (SLPUrl*)malloc(sizeof(SLPUrl));
+    slpUrl->serviceURL      = NULL;
+    slpUrl->ltime           = 0;
+    slpUrl->scopelist       = NULL;
+    slpUrl->serviceType     = NULL;
+    slpUrl->attrs           = NULL;
+    slpUrl->next            = NULL;
+    slpUrl->last            = NULL;
+    return slpUrl;
+}
+
+
+static void CleanUpSLPUrlList(SLPUrlList* slpUrlList)
+{
+    SLPUrl* slpUrl,*slpUrlNext;
+
+    slpUrl = slpUrlList->slpUrl;
+    while(slpUrl)
+    {
+	if (slpUrl->serviceURL)
+	    free(slpUrl->serviceURL);
+	if (slpUrl->scopelist)
+	    free(slpUrl->scopelist);
+	if (slpUrl->serviceType)
+	    free(slpUrl->serviceType);
+	if (slpUrl->attrs)
+	    free(slpUrl->attrs);
+	slpUrlNext = slpUrl->next;
+	free(slpUrl);
+	slpUrl = slpUrlNext;
+    }
+    slpUrlList->slpUrl = NULL;
+    if (slpUrlList->currentScope != NULL)
+	free(slpUrlList->currentScope);
+    if(slpUrlList->services != NULL)
+	free(slpUrlList->services);
+    if(slpUrlList->currentServiceType != NULL)
+	free(slpUrlList->currentServiceType);
+    free(slpUrlList);
+}
+
+static int SLPSrvTCallBack(SLPMessage * message, void * cookie)
+{
+    if (message->header.functionid != SLP_FUNCT_SRVTYPERPLY)
+	return SLP_NETWORK_ERROR;
+    if (message->body.srvtyperply.errorcode != 0)
+	return message->body.srvtyperply.errorcode;
+    /* null terminate as in libslp */
+    ((char *)message->body.srvtyperply.srvtypelist)[message->body.srvtyperply.srvtypelistlen] = 0;
+    ((SLPUrlList*)cookie)->services = strdup(message->body.srvtyperply.srvtypelist);
+    return 0;
+}
+
+static int SLPSrvCallBack(SLPMessage * message, void * cookie)
+{
+    SLPUrl *slpUrl = NULL;
+    char scopelist[4096];
+    int i;
+    SLPUrlEntry *srvurl;
+
+    if (message->header.functionid != SLP_FUNCT_SRVRPLY)
+	return SLP_NETWORK_ERROR;
+    if (message->body.srvrply.errorcode != 0)
+	return message->body.srvrply.errorcode;
+    for (i=0; i<message->body.srvrply.urlcount; i++)
+    {
+	srvurl = message->body.srvrply.urlarray + i;
+	/* null terminate url as in libslp, overwrites authcount */
+	((char *)srvurl->url)[srvurl->urllen] = 0;
+        for (slpUrl = ((SLPUrlList*)cookie)->slpUrl; slpUrl ; slpUrl = slpUrl->next)
+        {
+	    /* Check whether the same service URL is available as part of different scope*/
+	    if( (slpUrl->serviceURL != NULL) && ( strcasecmp( slpUrl->serviceURL,srvurl->url) == 0))
+		break;
+	}
+	if (slpUrl)
+	{
+	    snprintf(scopelist,sizeof(scopelist),"%s,%s",slpUrl->scopelist,((SLPUrlList*)cookie)->currentScope);
+	    free(slpUrl->scopelist);
+	    slpUrl->scopelist = strdup(scopelist);
+	}
+	else
+	{
+	    slpUrl                  = AllocateSLPUrl();
+	    slpUrl->serviceURL      = strdup(srvurl->url);
+	    slpUrl->ltime           = srvurl->lifetime;
+	    slpUrl->scopelist       = strdup(((SLPUrlList*)cookie)->currentScope);
+	    slpUrl->serviceType     = strdup(((SLPUrlList*)cookie)->currentServiceType);
+	    slpUrl->attrs           = NULL;
+	    slpUrl->next            = ((SLPUrlList*)cookie)->slpUrl;
+	    if(((SLPUrlList*)cookie)->slpUrl)
+		((SLPUrlList*)cookie)->slpUrl->last = slpUrl;
+	    ((SLPUrlList*)cookie)->slpUrl= slpUrl;
+        }
+    }
+    return 0;
+}
+
+static int SLPSrvAttrCallBack(SLPMessage * message, void * cookie)
+{
+    SLPUrl *lslpUrl = ((SLPUrlList*)cookie)->currentSLPUrl;
+    if (message->header.functionid != SLP_FUNCT_ATTRRPLY)
+	return SLP_NETWORK_ERROR;
+    if (message->body.attrrply.errorcode != 0)
+	return message->body.attrrply.errorcode;
+
+    /* null terminate as in libslp */
+    ((char *)message->body.attrrply.attrlist)[message->body.attrrply.attrlistlen] = 0;
+    lslpUrl->attrs = strdup(message->body.attrrply.attrlist);
+    return 0;
+}
+
+static char * createreq(int * sizep, char * url, char * scope, char * predicate, char * spi)
+{
+  char *buf, *cur;
+  int urllen = url ? strlen(url) : 0;
+  int scopelen = scope ? strlen(scope) : 0;
+  int predicatelen = predicate ? strlen(predicate) : 0;
+  int spilen = spi ? strlen(spi) : 0;
+  buf = malloc(2 + urllen + 2 + scopelen + 2 + predicatelen + 2 + spilen);
+  cur = buf;
+  if (url)
+  {
+	TO_UINT16(cur, urllen);
+	cur += 2;
+	memcpy(cur, url, urllen);
+	cur += urllen;
+  }
+  if (scope)
+  {
+	TO_UINT16(cur, scopelen);
+	cur += 2;
+	memcpy(cur, scope, scopelen);
+	cur += scopelen;
+  }
+  if (predicate)
+  {
+	TO_UINT16(cur, predicatelen);
+	cur += 2;
+	memcpy(cur, predicate, predicatelen);
+	cur += predicatelen;
+  }
+  if (spi)
+  {
+	TO_UINT16(cur, spilen);
+	cur += 2;
+	memcpy(cur, spi, spilen);
+	cur += spilen;
+  }
+  *sizep = cur - buf;
+  return buf;
+}
+
+
+int getSLPServiceURLs(int sock, struct sockaddr_storage * destaddr, struct sockaddr_storage * localaddr)
+{
+    char *strng, *services;
+    int gresult = 0, result;
+    SLPUrl * slpUrl;
+    char *scope = NULL, *scopelist = NULL;
+    char scopeptr[4096],serviceptr[4096];
+    SLPMessage * msg;
+    SLPBuffer buf;
+    const char *langtag;
+    char *outbuf;
+    int bufsize;
+    char *srvtype, *srvtype_end;
+
+    SLPUrlList* slpUrlList  = (SLPUrlList*)malloc(sizeof(SLPUrlList));
+    slpUrlList->slpUrl      = NULL;
+    slpUrlList->services    = NULL;
+    slpUrlList->currentServiceType  = NULL;
+    slpUrlList->currentScope  = NULL;
+
+    langtag = SLPPropertyGet("net.slp.locale", 0, 0);
+
+    scopelist = strdup(G_SlpdProperty.useScopes);
+
+    for(scope = strtok_r(scopelist,",",(char**)&scopeptr); scope ; scope = strtok_r(NULL,",",(char**)&scopeptr))
+    {
+	slpUrlList->currentScope = strdup(scope);
+	outbuf = createreq(&bufsize, "", scope, NULL, NULL);
+	TO_UINT16(outbuf, 0xffff); /* 0xffff indicates all service types */
+	result = SLPDUnicastRqstRply(sock, destaddr, localaddr, langtag, outbuf, SLP_FUNCT_SRVTYPERQST, bufsize, SLPSrvTCallBack, slpUrlList);
+	free(outbuf);
+	if (result)
+	{
+	    gresult = result;	/* remember error with that scope */
+	    SLPDLog("Error: SLPFindSrvTypes %d\n",result);
+	    continue;
+	}
+	if(slpUrlList->services)
+	{
+	    services = strdup(slpUrlList->services);
+	    for(strng = strtok_r(services, ",",(char**)&serviceptr); strng ; strng = strtok_r(NULL, ",",(char**)&serviceptr))
+	    {
+		if (!strcasecmp(strng, SLP_SA_SERVICE_TYPE))
+		    continue;
+		if (!strcasecmp(strng, SLP_DA_SERVICE_TYPE))
+		    continue;
+		slpUrlList->currentServiceType = strdup(strng);
+		outbuf = createreq(&bufsize, strng, scope, "", "");
+		result = SLPDUnicastRqstRply(sock, destaddr, localaddr, langtag, outbuf, SLP_FUNCT_SRVRQST, bufsize, SLPSrvCallBack, slpUrlList);
+		free(outbuf);
+		free(slpUrlList->currentServiceType);
+		slpUrlList->currentServiceType = NULL;
+		if(result != 0)
+		{
+		    SLPDLog("Error: SLPFindSrvs %d\n", result);
+		    continue;
+		}
+	    }
+	    free(services);
+	}
+	if (slpUrlList->currentScope != NULL)
+	{
+	    free(slpUrlList->currentScope);
+	    slpUrlList->currentScope = NULL;
+	}
+	if(slpUrlList->services != NULL)
+	{
+	    free(slpUrlList->services);
+	    slpUrlList->services = NULL;
+	}
+    }
+
+    /* we now have collected all services, fetch the attributes */
+
+    for(slpUrl = slpUrlList->slpUrl; slpUrl ; slpUrl = slpUrl->next)
+    {
+	slpUrl->attrs = NULL;
+	slpUrlList->currentSLPUrl = slpUrl;
+	outbuf = createreq(&bufsize, slpUrl->serviceURL, slpUrl->scopelist, "", "");
+	result = SLPDUnicastRqstRply(sock, destaddr, localaddr, langtag, outbuf, SLP_FUNCT_ATTRRQST, bufsize, SLPSrvAttrCallBack, slpUrlList);
+	free(outbuf);
+	if(result != 0)
+	{
+	    SLPDLog("Error: SLPFindAttrs %d\n", result);
+	    continue;
+	}
+	srvtype = strdup(slpUrl->serviceURL);
+	srvtype_end = strstr(srvtype, "://");
+	if (srvtype_end)
+	    *srvtype_end = 0;
+	if (SLPDCreateSrvReg(SLP_REG_SOURCE_PULL_PEER_DA,
+                             strlen(slpUrl->serviceURL), slpUrl->serviceURL,
+                             strlen(langtag), (char *)langtag,
+                             strlen(srvtype), srvtype,
+                             strlen(slpUrl->scopelist), slpUrl->scopelist,
+                             slpUrl->attrs ? strlen(slpUrl->attrs) : 0, slpUrl->attrs,
+                             slpUrl->ltime, &msg, &buf) == 0)
+	{
+	    msg->peer = *destaddr;
+	    SLPDDatabaseReg(msg, buf);
+	}
+	free(srvtype);
+    }
+
+    CleanUpSLPUrlList(slpUrlList);
+    if(scopelist != NULL)
+	free(scopelist);
+    return gresult;
+}
+
--- ./slpd/slpd_initda.h.orig	2016-09-13 10:56:14.218459541 +0000
+++ ./slpd/slpd_initda.h	2016-09-13 10:56:14.218459541 +0000
@@ -0,0 +1,16 @@
+#ifndef SLPD_INITDA_H_INCLUDED
+#define SLPD_INITDA_H_INCLUDED
+
+#include "slpd.h"
+
+/*=========================================================================*/
+/* common code includes                                                    */
+/*=========================================================================*/
+#include "slpd_socket.h"
+
+
+int getSLPServiceURLs(int sock, struct sockaddr_storage *destaddr, struct sockaddr_storage *localaddr);
+
+#endif	/* SLPD_INITDA_H_INCLUDED */
+
+/*=========================================================================*/
--- ./slpd/slpd_log.c.orig	2016-09-13 10:56:06.326486000 +0000
+++ ./slpd/slpd_log.c	2016-09-13 10:56:14.219459537 +0000
@@ -509,6 +509,12 @@ void SLPDLogRegistration(const char * pr
          case SLP_REG_SOURCE_STATIC:
             SLPDLog("static (slp.reg)\n");
             break;
+
+         case SLP_REG_SOURCE_PULL_PEER_DA:
+            SLPDLog("pulled from peer DA (%s)\n",
+                  SLPNetSockAddrStorageToString(&entry->msg->peer, 
+                        addr_str, sizeof(addr_str)));
+            break;
       }
       SLPDLogBuffer("    service-url = ",
             entry->msg->body.srvreg.urlentry.urllen,
--- ./slpd/slpd_main.c.orig	2016-09-13 10:56:06.326486000 +0000
+++ ./slpd/slpd_main.c	2016-09-13 10:57:32.988195569 +0000
@@ -57,6 +57,7 @@
 #include "slp_xmalloc.h"
 #include "slp_xid.h"
 #include "slp_net.h"
+#include "slp_network.h"
 
 int G_SIGALRM;
 int G_SIGTERM;
@@ -65,8 +66,27 @@ int G_SIGHUP;
 int G_SIGINT;     /* Signal being used for dumping registrations */
 int G_SIGUSR1;    /* Signal being used to dump information about the database */
 #endif
+#include "slpd_initda.h"
 
 char *reg_file_dir = "/etc/slp.reg.d";
+FILE *DABackupfp;
+
+static void SLPDOpenDABackupFile()
+{
+   FILE *fp;
+   char filename[1024];
+   snprintf(filename, sizeof(filename), "%s/slpd/%s", reg_file_dir, "DABackup");
+
+   fp = fopen(filename, "a+");
+   if (!DABackupfp && !fp)
+      SLPDLog("Could not open DABackup file\n");
+   if (fp)
+   {
+      if (DABackupfp)
+         fclose(DABackupfp);
+      DABackupfp = fp;
+   }
+}
 
 /** Configures fd_set objects with sockets.
  *
@@ -214,6 +234,10 @@ void HandleSigTerm(void)
    SLPDLog("SLPD daemon shutting down\n");
    SLPDLog("****************************************\n");
 
+   /* write backup file if configured */
+   if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup && DABackupfp)
+      SLPDDatabaseWriteDABackup(DABackupfp);
+
    /* unregister with all DAs */
    SLPDKnownDADeinit();
 
@@ -282,6 +306,10 @@ void HandleSigHup(void)
    SLPDLog("SLPD daemon reset by SIGHUP\n");
    SLPDLog("****************************************\n\n");
 
+   /* write backup file if configured */
+   if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup && DABackupfp)
+      SLPDDatabaseWriteDABackup(DABackupfp);
+
    /* unregister with all DAs */
    SLPDKnownDADeinit();
 
@@ -298,6 +326,10 @@ void HandleSigHup(void)
    /* Re-read the static registration file (slp.reg)*/
    SLPDDatabaseReInit();
 
+   /* Re-read the backup file if configured */
+   if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup && DABackupfp)
+      SLPDDatabaseReadDABackup(DABackupfp);
+
    /* Reopen listening sockets */
    SLPDIncomingReinit();
 
@@ -666,6 +698,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);
 
+   if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup)
+      SLPDOpenDABackupFile();
+
    /* init watcher */
    SLPDDatabaseWatcher();
 
@@ -677,6 +712,43 @@ int main(int argc, char * argv[])
    if (SetUpSignalHandlers())
       SLPDFatal("Error setting up signal handlers.\n");
 
+   if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup && DABackupfp)
+   {
+      SLPDDatabaseReadDABackup(DABackupfp);
+   }
+
+   if((G_SlpdProperty.isDA) && (G_SlpdProperty.DASyncReg))
+   {
+      /* HACK: at that point in time all outgoing sockets are DA connections
+       * and the incoming sockets are our interfaces */
+      SLPDLog("Pulling service list from other DAs...\n");
+      SLPDSocket* sock = (SLPDSocket*)G_OutgoingSocketList.head;
+      while (sock)
+      {
+         SLPDSocket* isock = (SLPDSocket*)G_IncomingSocketList.head;
+
+         /* make sure we're not connecting to ourself */
+         while (isock)
+         {
+             if (SLPNetCompareAddrs(&sock->peeraddr, &isock->peeraddr) == 0)
+                break;
+             isock = (SLPDSocket*)isock->listitem.next;
+         }
+         if (!isock)
+	 {
+	    int s = SLPNetworkConnectStream(&sock->peeraddr, 0);
+	    if (s >= 0)
+	    {
+	       int result = getSLPServiceURLs(s, &sock->peeraddr, &sock->localaddr);
+	       close(s);
+	       if (result == 0)
+		  break;
+	    }
+	 }
+         sock = (SLPDSocket*)sock->listitem.next;
+      }
+   }
+
    /* Set up alarm to age database -- a shorter start, so SAs register with us quickly on our startup */
    alarm(2);
 
@@ -748,6 +820,22 @@ HANDLE_SIGNAL:
       }
 #endif
 
+      if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup && DABackupfp)
+      {
+         static time_t lastbck;
+         time_t now;
+
+         now = time(NULL);
+         if (!lastbck)
+            lastbck = now;
+         if (now - lastbck > G_SlpdProperty.DABackupInterval)
+         {
+            SLPDLog("Updating registration backup file\n");
+            SLPDDatabaseWriteDABackup(DABackupfp);
+            lastbck = now;
+         }
+      }
+
    } /* End of main loop */
 
    /* Got SIGTERM */
--- ./slpd/slpd_property.c.orig	2016-09-13 10:56:06.330485986 +0000
+++ ./slpd/slpd_property.c	2016-09-13 10:56:14.220459534 +0000
@@ -248,6 +248,11 @@ void SLPDPropertyReinit(void)
    /* set up hostname */
    G_SlpdProperty.myHostname = SLPDGetCanonHostname();
    G_SlpdProperty.myHostnameLen = strlen(G_SlpdProperty.myHostname);
+
+   G_SlpdProperty.DASyncReg = SLPPropertyAsBoolean("net.slp.DASyncReg");
+   G_SlpdProperty.isDABackup = SLPPropertyAsBoolean("net.slp.isDABackup");
+   G_SlpdProperty.DABackupInterval = SLPPropertyAsInteger("net.slp.DABackupInterval");
+   G_SlpdProperty.DABackupLocalReg = SLPPropertyAsBoolean("net.slp.DABackupLocalReg");
 }
 
 /** Initialize the slpd property management subsystem.
--- ./slpd/slpd_property.h.orig	2016-09-13 10:56:06.330485986 +0000
+++ ./slpd/slpd_property.h	2016-09-13 10:56:14.220459534 +0000
@@ -117,6 +117,11 @@ typedef struct _SLPDProperty
    int MTU;
    int useDHCP;
    int oversizedUDP;
+
+   int DASyncReg;
+   int isDABackup;
+   int DABackupInterval;
+   int DABackupLocalReg;
 } SLPDProperty;
 
 extern SLPDProperty G_SlpdProperty;
--- ./slpd/slpd_regfile.c.orig	2016-09-13 10:56:06.327485996 +0000
+++ ./slpd/slpd_regfile.c	2016-09-13 10:56:14.221459531 +0000
@@ -108,15 +108,190 @@ static char * RegFileReadLine(FILE * fd,
    return line;
 }
 
+/** Create a SrcReg Message from given data.
+ * Don't look at this too hard or you'll be sick.  This is by far
+ * the most horrible code in OpenSLP.  Please volunteer to rewrite it!
+ *
+ * "THANK GOODNESS this function is only called at startup" -- Matt
+ *
+ * @note Eventually the caller needs to call SLPBufferFree and
+ *    SLPMessageFree to free memory.
+ */
+int SLPDCreateSrvReg(int source, int urllen, char * url,
+                     int langtaglen, char * langtag,
+                     int srvtypelen, char * srvtype,
+                     int scopelistlen, char * scopelist,
+                     int attrlistlen, char * attrlist,
+                     int lifetime, SLPMessage ** msg, SLPBuffer * buf)
+{
+   struct sockaddr_storage peer;
+   int result = 0;
+   size_t bufsize = 0;
+   SLPBuffer tmp;
+#ifdef ENABLE_SLPv2_SECURITY
+   unsigned char * urlauth = 0;
+   int urlauthlen = 0;
+   unsigned char * attrauth = 0;
+   int attrauthlen = 0;
+#endif
+
+#ifdef ENABLE_SLPv2_SECURITY
+   /* generate authentication blocks */
+   if (G_SlpdProperty.securityEnabled)
+   {
+      SLPAuthSignUrl(G_SlpdSpiHandle, 0, 0, urllen, url,
+            &urlauthlen, &urlauth);
+      SLPAuthSignString(G_SlpdSpiHandle, 0, 0, attrlistlen, attrlist,
+            &attrauthlen, &attrauth);
+   }
+#endif
+
+   /* allocate buffer for the SrvReg Message */
+   bufsize = 14 + langtaglen;    /* 14 bytes for header    */
+   bufsize += urllen + 6;        /*  1 byte for reserved   */
+                                 /*  2 bytes for lifetime  */
+                                 /*  2 bytes for urllen    */
+                                 /*  1 byte for authcount  */
+   bufsize += srvtypelen + 2;    /*  2 bytes for len field */
+   bufsize += scopelistlen + 2;  /*  2 bytes for len field */
+   bufsize += attrlistlen + 2;   /*  2 bytes for len field */
+   bufsize += 1;                 /*  1 byte for authcount  */
+
+#ifdef ENABLE_SLPv2_SECURITY
+   bufsize += urlauthlen;
+   bufsize += attrauthlen;
+#endif
+
+   tmp = *buf = SLPBufferAlloc(bufsize);
+   if (tmp == 0)
+   {
+      result = SLP_ERROR_INTERNAL_ERROR;
+      goto CLEANUP;
+   }
+
+   /* now build the SrvReg Message */
+
+   /* version */
+   *tmp->curpos++ = 2;
+
+   /* function id */
+   *tmp->curpos++ = SLP_FUNCT_SRVREG;
+
+   /* length */
+   PutUINT24(&tmp->curpos, bufsize);
+
+   /* flags */
+   PutUINT16(&tmp->curpos, 0);
+
+   /* ext offset */
+   PutUINT24(&tmp->curpos, 0);
+
+   /* xid */
+   PutUINT16(&tmp->curpos, 0);
+
+   /* lang tag len */
+   PutUINT16(&tmp->curpos, langtaglen);
+
+   /* lang tag */
+   memcpy(tmp->curpos, langtag, langtaglen);
+   tmp->curpos += langtaglen;
+
+   /* url-entry reserved */
+   *tmp->curpos++ = 0;
+
+   /* url-entry lifetime */
+   PutUINT16(&tmp->curpos, lifetime);
+
+   /* url-entry urllen */
+   PutUINT16(&tmp->curpos, urllen);
+
+   /* url-entry url */
+   memcpy(tmp->curpos, url, urllen);
+   tmp->curpos += urllen;
+
+   /* url-entry authblock */
+#ifdef ENABLE_SLPv2_SECURITY
+   if (urlauth)
+   {
+      /* authcount */
+      *tmp->curpos++ = 1;
+
+      /* authblock */
+      memcpy(tmp->curpos, urlauth, urlauthlen);
+      tmp->curpos += urlauthlen;
+   }
+   else
+#endif
+      *tmp->curpos++ = 0;
+
+   /* service type */
+   PutUINT16(&tmp->curpos, srvtypelen);
+   memcpy(tmp->curpos, srvtype, srvtypelen);
+   tmp->curpos += srvtypelen;
+
+   /* scope list */
+   PutUINT16(&tmp->curpos, scopelistlen);
+   memcpy(tmp->curpos, scopelist, scopelistlen);
+   tmp->curpos += scopelistlen;
+
+   /* attr list */
+   PutUINT16(&tmp->curpos, attrlistlen);
+   memcpy(tmp->curpos, attrlist, attrlistlen);
+   tmp->curpos += attrlistlen;
+
+   /* attribute auth block */
+#ifdef ENABLE_SLPv2_SECURITY
+   if (attrauth)
+   {
+      /* authcount */
+      *tmp->curpos++ = 1;
+
+      /* authblock */
+      memcpy(tmp->curpos, attrauth, attrauthlen);
+      tmp->curpos += attrauthlen;
+   }
+   else
+#endif
+      *tmp->curpos++ = 0;
+
+   /* okay, now comes the really stupid (and lazy part) */
+   *msg = SLPMessageAlloc();
+   if (*msg == 0)
+   {
+      SLPBufferFree(*buf);
+      *buf = 0;
+      result = SLP_ERROR_INTERNAL_ERROR;
+      goto CLEANUP;
+   }
+
+   /* this should be ok even if we are not supporting IPv4,
+    * since it's a static service
+    */
+   memset(&peer, 0, sizeof(struct sockaddr_in));
+   peer.ss_family = AF_UNSPEC;
+   ((struct sockaddr_in *)&peer)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+   result = SLPMessageParseBuffer(&peer, &peer, *buf, *msg);
+   (*msg)->body.srvreg.source = source;
+
+CLEANUP:
+
+#ifdef ENABLE_SLPv2_SECURITY
+   xfree(urlauth);
+   xfree(attrauth);
+#endif
+
+   return result;
+}
+
+
+
 /** Read service registrations from a text file.
  *
  * A really big and nasty function that reads service registrations from
- * from a file. Don't look at this too hard or you'll be sick. This is by
- * far the most horrible code in OpenSLP. Please volunteer to rewrite it!
- *
- * "THANK GOODNESS this function is only called at startup" -- Matt
+ * from a file.
  *
  * @param[in] fd - The file to read from.
+ * @param[in] source - The registration type (SLP_REG_SOURCE_STATIC)
  * @param[out] msg - A message describing the SrvReg in buf.
  * @param[out] buf - The buffer used to hold @p message data.
  *
@@ -126,16 +301,14 @@ static char * RegFileReadLine(FILE * fd,
  * @note Eventually the caller needs to call SLPBufferFree and
  *    SLPMessageFree to free memory.
  */
-int SLPDRegFileReadSrvReg(FILE * fd, SLPMessage ** msg, SLPBuffer * buf)
+int SLPDRegFileReadSrvReg(FILE * fd, int source, SLPMessage ** msg, SLPBuffer * buf)
 {
    char * slider1;
    char * slider2;
    char * p;
    char line[4096];
 
-   struct sockaddr_storage peer;
    int result = 0;
-   size_t bufsize = 0;
    size_t langtaglen = 0;
    char * langtag = 0;
    size_t scopelistlen = 0;
@@ -147,14 +320,8 @@ int SLPDRegFileReadSrvReg(FILE * fd, SLP
    char * srvtype = 0;
    size_t attrlistlen = 0;
    char * attrlist = 0;
-   SLPBuffer tmp;
+   char * peerip = 0;
 
-#ifdef ENABLE_SLPv2_SECURITY
-   unsigned char * urlauth = 0;
-   int urlauthlen = 0;
-   unsigned char * attrauth = 0;
-   int attrauthlen = 0;
-#endif
    int watchport = 0;
    int watchflags = 0;
 
@@ -184,7 +351,7 @@ int SLPDRegFileReadSrvReg(FILE * fd, SLP
          goto CLEANUP;
       }
       /* replace "$HOSTNAME" string in url */
-      while ((p = strchr(url, '$')) && !strncmp(p, "$HOSTNAME", 9))
+      while (source == SLP_REG_SOURCE_STATIC && (p = strchr(url, '$')) && !strncmp(p, "$HOSTNAME", 9))
       {
          char *_url = xmalloc(strlen(url) - 9 + G_SlpdProperty.myHostnameLen + 1);
          strncpy(_url, url, p - url);
@@ -326,6 +493,15 @@ int SLPDRegFileReadSrvReg(FILE * fd, SLP
             }
          }
       }
+      else if(strncasecmp(slider1,"slp-source",10) == 0 && source != SLP_REG_SOURCE_STATIC)
+      {
+         slider2 = strchr(slider1,'=');
+         if(slider2)
+         {
+            slider2++;
+            peerip=xstrdup(TrimWhitespace(slider2));
+         }
+      }
       else if(strncasecmp(slider1, "tcp-port", 8) == 0 || strncasecmp(slider1, "watch-port-tcp", 14) == 0)
       {
          slider2 = strchr(slider1,'=');
@@ -383,7 +559,7 @@ int SLPDRegFileReadSrvReg(FILE * fd, SLP
 
          /* we need special case for keywords (why do we need these)
             they seem like a waste of code.  Why not just use booleans */
-         if (strchr(slider1, '='))
+         if (strchr(slider1, '=') && source == SLP_REG_SOURCE_STATIC)
          {
             /* normal attribute (with '=') */
             strcat(attrlist, "(");
@@ -411,146 +587,37 @@ int SLPDRegFileReadSrvReg(FILE * fd, SLP
       scopelistlen = G_SlpdProperty.useScopesLen;
    }
 
-#ifdef ENABLE_SLPv2_SECURITY
-   /* generate authentication blocks */
-   if (G_SlpdProperty.securityEnabled)
-   {
-      SLPAuthSignUrl(G_SlpdSpiHandle, 0, 0, urllen, url,
-            &urlauthlen, &urlauth);
-      SLPAuthSignString(G_SlpdSpiHandle, 0, 0, attrlistlen, attrlist,
-            &attrauthlen, &attrauth);
-   }
-#endif
-
-   /* allocate buffer for the SrvReg Message */
-   bufsize = 14 + langtaglen;    /* 14 bytes for header    */
-   bufsize += urllen + 6;        /*  1 byte for reserved   */
-                                 /*  2 bytes for lifetime  */
-                                 /*  2 bytes for urllen    */
-                                 /*  1 byte for authcount  */
-   bufsize += srvtypelen + 2;    /*  2 bytes for len field */
-   bufsize += scopelistlen + 2;  /*  2 bytes for len field */
-   bufsize += attrlistlen + 2;   /*  2 bytes for len field */
-   bufsize += 1;                 /*  1 byte for authcount  */
-
-#ifdef ENABLE_SLPv2_SECURITY
-   bufsize += urlauthlen;
-   bufsize += attrauthlen;
-#endif
+   result = SLPDCreateSrvReg(source, urllen, url, langtaglen, langtag, srvtypelen, srvtype,
+                             scopelistlen, scopelist, attrlistlen, attrlist, lifetime, msg, buf);
 
-   tmp = *buf = SLPBufferAlloc(bufsize);
-   if (tmp == 0)
-   {
-      result = SLP_ERROR_INTERNAL_ERROR;
+   if (result)
       goto CLEANUP;
-   }
-
-   /* now build the SrvReg Message */
-
-   /* version */
-   *tmp->curpos++ = 2;
-
-   /* function id */
-   *tmp->curpos++ = SLP_FUNCT_SRVREG;
-
-   /* length */
-   PutUINT24(&tmp->curpos, bufsize);
-
-   /* flags */
-   PutUINT16(&tmp->curpos, 0);
-
-   /* ext offset */
-   PutUINT24(&tmp->curpos, 0);
-
-   /* xid */
-   PutUINT16(&tmp->curpos, 0);
-
-   /* lang tag len */
-   PutUINT16(&tmp->curpos, langtaglen);
-
-   /* lang tag */
-   memcpy(tmp->curpos, langtag, langtaglen);
-   tmp->curpos += langtaglen;
-
-   /* url-entry reserved */
-   *tmp->curpos++ = 0;
-
-   /* url-entry lifetime */
-   PutUINT16(&tmp->curpos, lifetime);
-
-   /* url-entry urllen */
-   PutUINT16(&tmp->curpos, urllen);
-
-   /* url-entry url */
-   memcpy(tmp->curpos, url, urllen);
-   tmp->curpos += urllen;
-
-   /* url-entry authblock */
-#ifdef ENABLE_SLPv2_SECURITY
-   if (urlauth)
-   {
-      /* authcount */
-      *tmp->curpos++ = 1;
-
-      /* authblock */
-      memcpy(tmp->curpos, urlauth, urlauthlen);
-      tmp->curpos += urlauthlen;
-   }
-   else
-#endif
-      *tmp->curpos++ = 0;
 
-   /* service type */
-   PutUINT16(&tmp->curpos, srvtypelen);
-   memcpy(tmp->curpos, srvtype, srvtypelen);
-   tmp->curpos += srvtypelen;
-
-   /* scope list */
-   PutUINT16(&tmp->curpos, scopelistlen);
-   memcpy(tmp->curpos, scopelist, scopelistlen);
-   tmp->curpos += scopelistlen;
-
-   /* attr list */
-   PutUINT16(&tmp->curpos, attrlistlen);
-   memcpy(tmp->curpos, attrlist, attrlistlen);
-   tmp->curpos += attrlistlen;
-
-   /* attribute auth block */
-#ifdef ENABLE_SLPv2_SECURITY
-   if (attrauth)
+   if (source == SLP_REG_SOURCE_STATIC)
    {
-      /* authcount */
-      *tmp->curpos++ = 1;
-
-      /* authblock */
-      memcpy(tmp->curpos, attrauth, attrauthlen);
-      tmp->curpos += attrauthlen;
+      (*msg)->body.srvreg.watchflags = watchflags ? (watchflags | SLP_REG_WATCH_DEAD) : 0;
+      (*msg)->body.srvreg.watchport = watchport;
    }
-   else
-#endif
-      *tmp->curpos++ = 0;
 
-   /* okay, now comes the really stupid (and lazy part) */
-   *msg = SLPMessageAlloc();
-   if (*msg == 0)
+   if (peerip && source != SLP_REG_SOURCE_STATIC)
    {
-      SLPBufferFree(*buf);
-      *buf = 0;
-      result = SLP_ERROR_INTERNAL_ERROR;
-      goto CLEANUP;
+      if (!strncmp(peerip, "pulled-from-da-", 15))
+      {
+         int one = 1;
+         SLPIfaceStringToSockaddrs(peerip + 15, &(*msg)->peer, &one);
+         (*msg)->body.srvreg.source = SLP_REG_SOURCE_PULL_PEER_DA;
+      }
+      else if (!strcmp(peerip, "local"))
+      {
+         (*msg)->body.srvreg.source = SLP_REG_SOURCE_LOCAL;
+      }
+      else
+      {
+         int one = 1;
+         SLPIfaceStringToSockaddrs(peerip, &(*msg)->peer, &one);
+      }
    }
 
-   /* this should be ok even if we are not supporting IPv4,
-    * since it's a static service
-    */
-   memset(&peer, 0, sizeof(struct sockaddr_in));
-   peer.ss_family = AF_UNSPEC;
-   ((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:
 
    /* check for errors and free memory */
@@ -578,12 +645,31 @@ CLEANUP:
    xfree(url);
    xfree(srvtype);
    xfree(attrlist);
+   xfree(peerip);
 
-#ifdef ENABLE_SLPv2_SECURITY
-   xfree(urlauth);
-   xfree(attrauth);
-#endif
+   return result;
+}
+
+int SLPDRegFileWriteSrvReg(FILE * fd, SLPMessage * msg)
+{
+   int result = 0;
+   char addr_str[INET6_ADDRSTRLEN];
 
+   if (fd)
+   {
+      fprintf(fd, "%s,%s,%d\n", msg->body.srvreg.urlentry.url, msg->header.langtag, msg->body.srvreg.urlentry.lifetime);
+      if (msg->body.srvreg.source == SLP_REG_SOURCE_PULL_PEER_DA)
+         fprintf(fd, "slp-source=pulled-from-da-%s\n", SLPNetSockAddrStorageToString(&msg->peer, addr_str, sizeof(addr_str)));
+      else if (msg->body.srvreg.source == SLP_REG_SOURCE_LOCAL)
+         fprintf(fd, "slp-source=local\n");
+      else
+         fprintf(fd, "slp-source=%s\n", SLPNetSockAddrStorageToString(&msg->peer, addr_str, sizeof(addr_str)));
+      if (msg->body.srvreg.scopelistlen)
+         fprintf(fd, "scopes=%.*s\n", (int)msg->body.srvreg.scopelistlen, msg->body.srvreg.scopelist);
+      if(msg->body.srvreg.attrlistlen)
+         fprintf(fd, "%.*s\n", (int)msg->body.srvreg.attrlistlen, msg->body.srvreg.attrlist);
+      fprintf(fd, "\n");
+   }
    return result;
 }
 
--- ./slpd/slpd_regfile.h.orig	2012-11-28 17:07:04.000000000 +0000
+++ ./slpd/slpd_regfile.h	2016-09-13 10:56:14.221459531 +0000
@@ -53,7 +53,12 @@
 #include "slp_message.h"
 #include "slpd.h"
 
-int SLPDRegFileReadSrvReg(FILE * fd, SLPMessage ** msg, SLPBuffer * buf);
+int SLPDCreateSrvReg(int source, int urllen, char * url, int langtaglen, char * langtag,
+                     int srvtypelen, char * srvtype, int scopelistlen, char * scopelist,
+                     int attrlistlen, char * attrlist, int lifetime, SLPMessage ** msg, SLPBuffer * buf);
+
+int SLPDRegFileReadSrvReg(FILE * fd, int source, SLPMessage ** msg, SLPBuffer * buf);
+int SLPDRegFileWriteSrvReg(FILE * fd, SLPMessage * msg);
 
 /*! @} */