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