Fix alignment issue on 64-bit. Solution from Steve Ortiz.
[rsync/rsync-patches.git] / slp.diff
CommitLineData
9978080e
WD
1This adds Service Location Protocol support.
2
03019e41 3To use this patch, run these commands for a successful build:
9978080e 4
03019e41 5 patch -p1 <patches/slp.diff
27e96866 6 ./prepare-source
9978080e 7 ./configure --enable-slp
9978080e
WD
8 make
9
6bc8e4ec
WD
10TODO: the configure changes should abort if the user requests --enable-slp
11and we can't honor that request.
12
c1ff70aa 13based-on: a01e3b490eb36ccf9e704840e1b6683dab867550
cc3e685d
WD
14diff --git a/Makefile.in b/Makefile.in
15--- a/Makefile.in
16+++ b/Makefile.in
03019e41 17@@ -13,6 +13,8 @@ CFLAGS=@CFLAGS@
9978080e
WD
18 CPPFLAGS=@CPPFLAGS@
19 EXEEXT=@EXEEXT@
20 LDFLAGS=@LDFLAGS@
21+LIBSLP=@LIBSLP@
22+SLPOBJ=@SLPOBJ@
23
24 INSTALLCMD=@INSTALL@
25 INSTALLMAN=@INSTALL@
fc557362 26@@ -38,7 +40,7 @@ OBJS1=flist.o rsync.o generator.o receiver.o cleanup.o sender.o exclude.o \
790ba11a 27 OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \
5795bf59 28 fileio.o batch.o clientname.o chmod.o acls.o xattrs.o
9978080e
WD
29 OBJS3=progress.o pipe.o
30-DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
31+DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o $(SLPOBJ)
32 popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
33 popt/popthelp.o popt/poptparse.o
34 OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
fc557362 35@@ -74,7 +76,7 @@ install-strip:
9978080e
WD
36 $(MAKE) INSTALL_STRIP='-s' install
37
38 rsync$(EXEEXT): $(OBJS)
39- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
40+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(LIBSLP)
41
42 $(OBJS): $(HEADERS)
f2863bc0 43 $(CHECK_OBJS): $(HEADERS)
cc3e685d
WD
44diff --git a/clientserver.c b/clientserver.c
45--- a/clientserver.c
46+++ b/clientserver.c
5214a41b 47@@ -1159,6 +1159,13 @@ int daemon_main(void)
9978080e
WD
48 * address too. In fact, why not just do inet_ntop on the
49 * local address??? */
50
51+#ifdef HAVE_LIBSLP
52+ if (register_services()) {
53+ rprintf(FINFO,
54+ "Couldn't register with service discovery protocol, continuing anyway\n");
55+ }
56+#endif
57+
9f085fa3
WD
58 start_accept_loop(rsync_port, start_daemon);
59 return -1;
60 }
cc3e685d
WD
61diff --git a/configure.in b/configure.in
62--- a/configure.in
63+++ b/configure.in
c1ff70aa 64@@ -683,6 +683,29 @@ if test $rsync_cv_can_hardlink_special = yes; then
1898c899 65 AC_DEFINE(CAN_HARDLINK_SPECIAL, 1, [Define to 1 if link() can hard-link special files.])
9978080e
WD
66 fi
67
68+AC_ARG_ENABLE(slp, [ --disable-slp turn off SLP support, defaults to on])
69+AC_ARG_WITH(openslp-libs, [ --with-openslp-libs set directory for OpenSLP library],
70+ LDFLAGS="-L$withval $LDFLAGS"
71+ DSOFLAGS="-L$withval $DSOFLAGS",)
72+AC_ARG_WITH(openslp-includes, [ --with-openslp-includes set directory for OpenSLP includes],
73+ CFLAGS="-I$withval $CFLAGS"
74+ CXXFLAGS="-I$withval $CXXFLAGS"
75+ CPPFLAGS="-I$withval $CPPFLAGS",)
76+
77+LIBSLP=""
78+SLPOBJ=""
79+
80+if test x$enable_slp != xno; then
81+ AC_CHECK_HEADER(slp.h,
82+ AC_CHECK_LIB(slp, SLPOpen,
83+ AC_DEFINE(HAVE_LIBSLP, 1, [Define to 1 for SLP support])
84+ SLPOBJ="srvreg.o srvloc.o"
85+ LIBSLP="-lslp"))
86+fi
87+
88+AC_SUBST(LIBSLP)
89+AC_SUBST(SLPOBJ)
90+
91 AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
92 AC_TRY_RUN([
93 #include <sys/types.h>
cc3e685d
WD
94diff --git a/loadparm.c b/loadparm.c
95--- a/loadparm.c
96+++ b/loadparm.c
72e5645e 97@@ -98,6 +98,9 @@ typedef struct {
9978080e
WD
98 char *socket_options;
99
100 int rsync_port;
6bc8e4ec 101+#ifdef HAVE_LIBSLP
9978080e 102+ int slp_refresh;
6bc8e4ec 103+#endif
fc557362 104 } global_vars;
9978080e 105
fc557362 106 /* This structure describes a single section. Their order must match the
72e5645e 107@@ -312,6 +315,9 @@ static struct parm_struct parm_table[] =
fc557362
WD
108 {"motd file", P_STRING, P_GLOBAL,&Vars.g.motd_file, NULL,0},
109 {"pid file", P_STRING, P_GLOBAL,&Vars.g.pid_file, NULL,0},
110 {"port", P_INTEGER,P_GLOBAL,&Vars.g.rsync_port, NULL,0},
6bc8e4ec 111+#ifdef HAVE_LIBSLP
fc557362 112+ {"slp refresh", P_INTEGER,P_GLOBAL,&Vars.g.slp_refresh, NULL,0},
6bc8e4ec 113+#endif
fc557362 114 {"socket options", P_STRING, P_GLOBAL,&Vars.g.socket_options, NULL,0},
9978080e 115
fc557362 116 {"auth users", P_STRING, P_LOCAL, &Vars.l.auth_users, NULL,0},
72e5645e 117@@ -443,6 +449,9 @@ FN_GLOBAL_STRING(lp_pid_file, &Vars.g.pid_file)
fc557362 118 FN_GLOBAL_STRING(lp_socket_options, &Vars.g.socket_options)
9978080e 119
fc557362 120 FN_GLOBAL_INTEGER(lp_rsync_port, &Vars.g.rsync_port)
6bc8e4ec 121+#ifdef HAVE_LIBSLP
fc557362 122+FN_GLOBAL_INTEGER(lp_slp_refresh, &Vars.g.slp_refresh)
6bc8e4ec 123+#endif
9978080e
WD
124
125 FN_LOCAL_STRING(lp_auth_users, auth_users)
85096e5e 126 FN_LOCAL_STRING(lp_charset, charset)
cc3e685d
WD
127diff --git a/main.c b/main.c
128--- a/main.c
129+++ b/main.c
c1ff70aa 130@@ -1238,6 +1238,18 @@ static int start_client(int argc, char *argv[])
3731f97b 131
9978080e 132 if (!read_batch) { /* for read_batch, NO source is specified */
790ba11a 133 char *path = check_for_hostspec(argv[0], &shell_machine, &rsync_port);
9978080e
WD
134+
135+ if (shell_machine && !shell_machine[0]) {
136+#ifdef HAVE_LIBSLP
137+ /* User entered just rsync:// URI */
138+ print_service_list();
139+ exit_cleanup(0);
140+#else /* No SLP, die here */
141+ rprintf(FINFO, "No SLP support, cannot browse\n");
142+ exit_cleanup(RERR_SYNTAX);
143+#endif
144+ }
145+
790ba11a 146 if (path) { /* source is remote */
9f085fa3
WD
147 char *dummy_host;
148 int dummy_port = 0;
cc3e685d
WD
149diff --git a/options.c b/options.c
150--- a/options.c
151+++ b/options.c
72e5645e 152@@ -567,6 +567,7 @@ static void print_rsync_version(enum logcode f)
9978080e 153 char const *links = "no ";
58b399b9 154 char const *iconv = "no ";
9978080e
WD
155 char const *ipv6 = "no ";
156+ char const *slp = "no ";
157 STRUCT_STAT *dumstat;
158
ac2da598 159 #if SUBPROTOCOL_VERSION != 0
72e5645e
WD
160@@ -600,6 +601,9 @@ static void print_rsync_version(enum logcode f)
161 #ifdef CAN_SET_SYMLINK_TIMES
85096e5e 162 symtimes = "";
9978080e 163 #endif
9978080e
WD
164+#if HAVE_LIBSLP
165+ slp = "";
166+#endif
ac2da598
WD
167
168 rprintf(f, "%s version %s protocol version %d%s\n",
169 RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol);
72e5645e 170@@ -613,8 +617,8 @@ static void print_rsync_version(enum logcode f)
5e3c6c93
WD
171 (int)(sizeof (int64) * 8));
172 rprintf(f, " %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n",
173 got_socketpair, hardlinks, links, ipv6, have_inplace);
85096e5e
WD
174- rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes\n",
175- have_inplace, acls, xattrs, iconv, symtimes);
176+ rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sSLP\n",
177+ have_inplace, acls, xattrs, iconv, symtimes, slp);
5e3c6c93 178
9978080e 179 #ifdef MAINTAINER_MODE
5e3c6c93 180 rprintf(f, "Panic Action: \"%s\"\n", get_panic_action());
cc3e685d
WD
181diff --git a/rsync.h b/rsync.h
182--- a/rsync.h
183+++ b/rsync.h
5214a41b 184@@ -199,6 +199,10 @@
9978080e
WD
185 #define SIGNIFICANT_ITEM_FLAGS (~(\
186 ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE))
187
188+/* this is the minimum we'll use, irrespective of config setting */
189+/* definately don't set to less than about 30 seconds */
190+#define SLP_MIN_TIMEOUT 120
76c553f7 191+
c0c7984e 192 #define CFN_KEEP_DOT_DIRS (1<<0)
76c553f7
WD
193 #define CFN_KEEP_TRAILING_SLASH (1<<1)
194 #define CFN_DROP_TRAILING_DOT_DIR (1<<2)
cc3e685d
WD
195diff --git a/rsync.yo b/rsync.yo
196--- a/rsync.yo
197+++ b/rsync.yo
abd3adb8 198@@ -148,7 +148,12 @@ particular rsync daemon by leaving off the module name:
9978080e
WD
199
200 quote(tt(rsync somehost.mydomain.com::))
201
202-See the following section for more details.
203+And, if Service Location Protocol is available, the following will list the
204+available rsync servers:
205+
206+quote(tt(rsync rsync://))
207+
208+See the following section for even more usage details.
209
210 manpagesection(ADVANCED USAGE)
211
cc3e685d
WD
212diff --git a/rsyncd.conf b/rsyncd.conf
213new file mode 100644
214--- /dev/null
215+++ b/rsyncd.conf
9978080e
WD
216@@ -0,0 +1,3 @@
217+
218+slp refresh = 300
219+
cc3e685d
WD
220diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo
221--- a/rsyncd.conf.yo
222+++ b/rsyncd.conf.yo
72e5645e 223@@ -120,6 +120,15 @@ details on some of the options you may be able to set. By default no
ae306a29
WD
224 special socket options are set. These settings can also be specified
225 via the bf(--sockopts) command-line option.
9978080e 226
e66d6d51 227+dit(bf(slp refresh)) This parameter is used to determine how long service
9978080e 228+advertisements are valid (measured in seconds), and is only applicable if
e66d6d51 229+you have Service Location Protocol support compiled in. If this is
9978080e
WD
230+not set or is set to zero, then service advertisements never time out. If
231+this is set to less than 120 seconds, then 120 seconds is used. If it is
232+set to more than 65535, then 65535 is used (which is a limitation of SLP).
233+Using 3600 (one hour) is a good number if you tend to change your
234+configuration.
235+
236 enddit()
237
ae306a29 238 manpagesection(MODULE PARAMETERS)
72e5645e 239@@ -766,6 +775,7 @@ use chroot = yes
9978080e
WD
240 max connections = 4
241 syslog facility = local5
242 pid file = /var/run/rsyncd.pid
243+slp refresh = 3600
244
245 [ftp]
85096e5e 246 path = /var/ftp/./pub
cc3e685d
WD
247diff --git a/socket.c b/socket.c
248--- a/socket.c
249+++ b/socket.c
e66d6d51 250@@ -530,6 +530,16 @@ void start_accept_loop(int port, int (*fn)(int, int))
9978080e
WD
251 {
252 fd_set deffds;
253 int *sp, maxfd, i;
6bc8e4ec 254+#ifdef HAVE_LIBSLP
9978080e
WD
255+ time_t next_slp_refresh;
256+ short slp_timeout = lp_slp_refresh();
257+ if (slp_timeout) {
258+ if (slp_timeout < SLP_MIN_TIMEOUT)
259+ slp_timeout = SLP_MIN_TIMEOUT;
260+ /* re-register before slp times out */
261+ slp_timeout -= 15;
262+ }
6bc8e4ec 263+#endif
9978080e 264
27e96866 265 #ifdef HAVE_SIGACTION
9978080e 266 sigact.sa_flags = SA_NOCLDSTOP;
e66d6d51 267@@ -558,14 +568,25 @@ void start_accept_loop(int port, int (*fn)(int, int))
9978080e
WD
268 maxfd = sp[i];
269 }
270
6bc8e4ec 271+#ifdef HAVE_LIBSLP
9978080e 272+ next_slp_refresh = time(NULL) + slp_timeout;
6bc8e4ec 273+#endif
9978080e
WD
274+
275 /* now accept incoming connections - forking a new process
276 * for each incoming connection */
277 while (1) {
278 fd_set fds;
279 pid_t pid;
280 int fd;
281+ int sel_ret;
9978080e
WD
282 struct sockaddr_storage addr;
283 socklen_t addrlen = sizeof addr;
6bc8e4ec
WD
284+#ifdef HAVE_LIBSLP
285+ struct timeval slp_tv;
286+
9978080e
WD
287+ slp_tv.tv_sec = 10;
288+ slp_tv.tv_usec = 0;
6bc8e4ec 289+#endif
9978080e
WD
290
291 /* close log file before the potentially very long select so
292 * file can be trimmed by another process instead of growing
fc557362 293@@ -578,7 +599,18 @@ void start_accept_loop(int port, int (*fn)(int, int))
9978080e
WD
294 fds = deffds;
295 #endif
fc557362
WD
296
297- if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 1)
6bc8e4ec
WD
298+#ifdef HAVE_LIBSLP
299+ sel_ret = select(maxfd + 1, &fds, NULL, NULL,
300+ slp_timeout ? &slp_tv : NULL);
9978080e 301+ if (sel_ret == 0 && slp_timeout && time(NULL) > next_slp_refresh) {
fc557362
WD
302+ rprintf(FINFO, "Service registration expired, refreshing it\n");
303+ register_services();
304+ next_slp_refresh = time(NULL) + slp_timeout;
9978080e 305+ }
6bc8e4ec
WD
306+#else
307+ sel_ret = select(maxfd + 1, &fds, NULL, NULL, NULL);
308+#endif
fc557362 309+ if (sel_ret < 1)
9978080e
WD
310 continue;
311
312 for (i = 0, fd = -1; sp[i] >= 0; i++) {
cc3e685d
WD
313diff --git a/srvloc.c b/srvloc.c
314new file mode 100644
315--- /dev/null
316+++ b/srvloc.c
6bc8e4ec 317@@ -0,0 +1,103 @@
9978080e
WD
318+/* -*- c-file-style: "linux"; -*-
319+
320+ Copyright (C) 2002 by Brad Hards <bradh@frogmouth.net>
321+
322+ This program is free software; you can redistribute it and/or modify
323+ it under the terms of the GNU General Public License as published by
324+ the Free Software Foundation; either version 2 of the License, or
325+ (at your option) any later version.
326+
327+ This program is distributed in the hope that it will be useful,
328+ but WITHOUT ANY WARRANTY; without even the implied warranty of
329+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
330+ GNU General Public License for more details.
331+
332+ You should have received a copy of the GNU General Public License
333+ along with this program; if not, write to the Free Software
334+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
335+*/
336+
337+/* This file implements the service location functionality */
338+/* Basically, it uses normal Service Location Protocol API */
339+
340+/* It is really a cheap hack - just to show how it might work
341+ in a real application.
342+*/
343+
344+#include "rsync.h"
345+
346+#include <slp.h>
347+#include <stdio.h>
348+#include <string.h>
349+
350+/* This one just prints out the attributes */
351+static SLPBoolean getAttrCallback(UNUSED(SLPHandle hslp), const char *attrlist,
352+ SLPError errcode, UNUSED(void *cookie))
353+{
354+ char *cleanstr;
355+
356+ if (errcode == SLP_OK) {
6bc8e4ec 357+ if (!strcmp(attrlist, "(comment=)"))
9978080e 358+ rprintf(FINFO, "\t(No description)\n");
6bc8e4ec 359+ else {
9978080e
WD
360+ cleanstr = strrchr(attrlist, ')') ;
361+ *cleanstr = ' '; /* remove last ')' */
362+ rprintf(FINFO, "\t%s\n", strchr(attrlist, '=') + 1);
363+ }
364+ }
365+ return SLP_FALSE;
366+}
367+
6bc8e4ec
WD
368+static SLPBoolean getSLPSrvURLCallback(UNUSED(SLPHandle hslp),
369+ const char *srvurl, UNUSED(unsigned short lifetime),
370+ SLPError errcode, void *cookie)
9978080e
WD
371+{
372+ SLPError result;
373+ SLPHandle attrhslp;
374+
375+ if (errcode == SLP_OK) {
376+ /* chop service: off the front */
377+ rprintf(FINFO, " %s ", (strchr(srvurl, ':') + 1));
378+ /* check for any attributes */
379+ if (SLPOpen("en", SLP_FALSE,&attrhslp) == SLP_OK) {
380+ result = SLPFindAttrs(attrhslp, srvurl,
381+ "", /* return all attributes */
382+ "", /* use configured scopes */
383+ getAttrCallback, NULL);
384+ if (result != SLP_OK) {
385+ rprintf(FERROR, "errorcode: %i\n",result);
386+ }
387+ SLPClose(attrhslp);
388+ }
389+ *(SLPError*)cookie = SLP_OK;
6bc8e4ec 390+ } else
9978080e 391+ *(SLPError*)cookie = errcode;
9978080e
WD
392+
393+ /* Return SLP_TRUE because we want to be called again
394+ * if more services were found. */
395+
396+ return SLP_TRUE;
397+}
398+
399+int print_service_list(void)
400+{
401+ SLPError err;
402+ SLPError callbackerr;
403+ SLPHandle hslp;
404+
405+ err = SLPOpen("en",SLP_FALSE,&hslp);
406+ if (err != SLP_OK) {
407+ rprintf(FERROR, "Error opening slp handle %i\n", err);
408+ return err;
409+ }
410+
411+ SLPFindSrvs(hslp, "rsync",
412+ 0, /* use configured scopes */
413+ 0, /* no attr filter */
414+ getSLPSrvURLCallback, &callbackerr);
415+
416+ /* Now that we're done using slp, close the slp handle */
417+ SLPClose(hslp);
418+
419+ return 0;
420+}
cc3e685d
WD
421diff --git a/srvreg.c b/srvreg.c
422new file mode 100644
423--- /dev/null
424+++ b/srvreg.c
9978080e
WD
425@@ -0,0 +1,128 @@
426+/* -*- c-file-style: "linux"; -*-
427+
428+ Copyright (C) 2002 by Brad Hards <bradh@frogmouth.net>
429+
430+ This program is free software; you can redistribute it and/or modify
431+ it under the terms of the GNU General Public License as published by
432+ the Free Software Foundation; either version 2 of the License, or
433+ (at your option) any later version.
434+
435+ This program is distributed in the hope that it will be useful,
436+ but WITHOUT ANY WARRANTY; without even the implied warranty of
437+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
438+ GNU General Public License for more details.
439+
440+ You should have received a copy of the GNU General Public License
441+ along with this program; if not, write to the Free Software
442+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
443+*/
444+
445+/* This file implements the service registration functionality */
446+
447+/* Basically, it uses normal Service Location Protocol API */
448+
449+#include "rsync.h"
450+#include "slp.h"
451+#include "netdb.h"
452+
453+extern int rsync_port;
454+
455+static void slp_callback(UNUSED(SLPHandle hslp), SLPError errcode, void *cookie)
456+{
457+ /* return the error code in the cookie */
458+ *(SLPError*)cookie = errcode;
459+
460+ /* You could do something else here like print out
461+ * the errcode, etc. Remember, as a general rule,
462+ * do not try to do too much in a callback because
463+ * it is being executed by the same thread that is
464+ * reading slp packets from the wire. */
465+}
466+
467+int register_services(void)
468+{
469+ SLPError err, callbackerr;
470+ SLPHandle hslp;
471+ int n;
472+ int i;
473+ char srv[120];
474+ char attr[120];
475+ char localhost[256];
476+ extern char *config_file;
477+ short timeout;
478+ struct addrinfo aih, *ai = 0;
479+
480+ if (!lp_load(config_file, 0)) {
481+ exit_cleanup(RERR_SYNTAX);
482+ }
483+
484+ n = lp_numservices();
485+
486+ if (0 == lp_slp_refresh())
487+ timeout = SLP_LIFETIME_MAXIMUM; /* don't expire, ever */
488+ else if (SLP_MIN_TIMEOUT > lp_slp_refresh())
489+ timeout = SLP_MIN_TIMEOUT; /* use a reasonable minimum */
490+ else if (SLP_LIFETIME_MAXIMUM <= lp_slp_refresh())
491+ timeout = (SLP_LIFETIME_MAXIMUM - 1); /* as long as possible */
492+ else
493+ timeout = lp_slp_refresh();
494+
495+ rprintf(FINFO, "rsyncd registering %d service%s with slpd for %d seconds:\n", n, ((n==1)? "":"s"), timeout);
496+ err = SLPOpen("en",SLP_FALSE,&hslp);
497+ if (err != SLP_OK) {
498+ rprintf(FINFO, "Error opening slp handle %i\n",err);
499+ return err;
500+ }
501+ if (gethostname(localhost, sizeof localhost)) {
502+ rprintf(FINFO, "Could not get hostname: %s\n", strerror(errno));
503+ return err;
504+ }
505+ memset(&aih, 0, sizeof aih);
506+ aih.ai_family = PF_UNSPEC;
507+ aih.ai_flags = AI_CANONNAME;
508+ if (0 != (err = getaddrinfo(localhost, 0, &aih, &ai)) || !ai) {
509+ rprintf(FINFO, "Could not resolve hostname: %s\n", gai_strerror(err));
510+ return err;
511+ }
512+ /* Register each service with SLP */
513+ for (i = 0; i < n; i++) {
514+ if (!lp_list(i))
515+ continue;
516+
517+ snprintf(srv, sizeof srv, "service:rsync://%s:%d/%s",
518+ ai->ai_canonname,
519+ rsync_port,
520+ lp_name(i));
521+ rprintf(FINFO, " %s\n", srv);
522+ if (lp_comment(i)) {
523+ snprintf(attr, sizeof attr, "(comment=%s)",
524+ lp_comment(i));
525+ }
526+ err = SLPReg(hslp,
527+ srv, /* service to register */
528+ timeout,
529+ 0, /* this is ignored */
530+ attr, /* attributes */
531+ SLP_TRUE, /* new registration - don't change this */
532+ slp_callback, /* callback */
533+ &callbackerr);
534+
535+ /* err may contain an error code that occurred as the slp library
536+ * _prepared_ to make the call. */
537+ if (err != SLP_OK || callbackerr != SLP_OK)
538+ rprintf(FINFO, "Error registering service with slp %i\n", err);
539+
540+ /* callbackerr may contain an error code (that was assigned through
541+ * the callback cookie) that occurred as slp packets were sent on
542+ * the wire. */
543+ if (callbackerr != SLP_OK)
544+ rprintf(FINFO, "Error registering service with slp %i\n",callbackerr);
545+ }
546+
547+ /* Now that we're done using slp, close the slp handle */
548+ freeaddrinfo(ai);
549+ SLPClose(hslp);
550+
551+ /* refresh is done in main select loop */
552+ return 0;
553+}