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