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