From 9978080ec09f62c426e6a1b81598a2f33bd91cd1 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Thu, 2 Feb 2006 11:53:38 +0000 Subject: [PATCH] A patch for Service Location Protocol support (derived from a patch found in a SUSE src rpm). --- slp.diff | 520 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 slp.diff diff --git a/slp.diff b/slp.diff new file mode 100644 index 0000000..fbc0ab4 --- /dev/null +++ b/slp.diff @@ -0,0 +1,520 @@ +This adds Service Location Protocol support. + +After applying this patch, run these commands for a successful build: + + autoconf + autoheader + ./configure --enable-slp + make proto + make + +--- orig/Makefile.in 2006-01-14 08:14:29 ++++ Makefile.in 2006-02-02 00:00:00 +@@ -12,6 +12,8 @@ CFLAGS=@CFLAGS@ + CPPFLAGS=@CPPFLAGS@ + EXEEXT=@EXEEXT@ + LDFLAGS=@LDFLAGS@ ++LIBSLP=@LIBSLP@ ++SLPOBJ=@SLPOBJ@ + + INSTALLCMD=@INSTALL@ + INSTALLMAN=@INSTALL@ +@@ -35,7 +37,7 @@ OBJS1=rsync.o generator.o receiver.o cle + OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \ + fileio.o batch.o clientname.o chmod.o + OBJS3=progress.o pipe.o +-DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o ++DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o $(SLPOBJ) + popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \ + popt/popthelp.o popt/poptparse.o + OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@ +@@ -69,7 +71,7 @@ install-strip: + $(MAKE) INSTALL_STRIP='-s' install + + rsync$(EXEEXT): $(OBJS) +- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) ++ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(LIBSLP) + + $(OBJS): $(HEADERS) + +--- orig/clientserver.c 2006-02-01 19:37:05 ++++ clientserver.c 2006-02-02 11:32:24 +@@ -832,6 +832,13 @@ int daemon_main(void) + * address too. In fact, why not just do inet_ntop on the + * local address??? */ + ++#ifdef HAVE_LIBSLP ++ if (register_services()) { ++ rprintf(FINFO, ++ "Couldn't register with service discovery protocol, continuing anyway\n"); ++ } ++#endif ++ + if (((pid_file = lp_pid_file()) != NULL) && (*pid_file != '\0')) { + char pidbuf[16]; + int fd; +--- orig/configure.in 2006-02-02 02:41:09 ++++ configure.in 2006-02-02 11:30:00 +@@ -535,6 +535,29 @@ if test $rsync_cv_chown_follows_symlink + AC_DEFINE(CHOWN_MODIFIES_SYMLINK, 1, [Define to 1 if chown modifies symlinks.]) + fi + ++AC_ARG_ENABLE(slp, [ --disable-slp turn off SLP support, defaults to on]) ++AC_ARG_WITH(openslp-libs, [ --with-openslp-libs set directory for OpenSLP library], ++ LDFLAGS="-L$withval $LDFLAGS" ++ DSOFLAGS="-L$withval $DSOFLAGS",) ++AC_ARG_WITH(openslp-includes, [ --with-openslp-includes set directory for OpenSLP includes], ++ CFLAGS="-I$withval $CFLAGS" ++ CXXFLAGS="-I$withval $CXXFLAGS" ++ CPPFLAGS="-I$withval $CPPFLAGS",) ++ ++LIBSLP="" ++SLPOBJ="" ++ ++if test x$enable_slp != xno; then ++ AC_CHECK_HEADER(slp.h, ++ AC_CHECK_LIB(slp, SLPOpen, ++ AC_DEFINE(HAVE_LIBSLP, 1, [Define to 1 for SLP support]) ++ SLPOBJ="srvreg.o srvloc.o" ++ LIBSLP="-lslp")) ++fi ++ ++AC_SUBST(LIBSLP) ++AC_SUBST(SLPOBJ) ++ + AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[ + AC_TRY_RUN([ + #include +--- orig/loadparm.c 2006-01-30 21:47:45 ++++ loadparm.c 2006-02-02 10:38:12 +@@ -105,6 +105,7 @@ typedef struct + char *socket_options; + + int rsync_port; ++ int slp_refresh; + int syslog_facility; + } global; + +@@ -286,6 +287,7 @@ static struct parm_struct parm_table[] = + {"motd file", P_STRING, P_GLOBAL,&Globals.motd_file, NULL,0}, + {"pid file", P_STRING, P_GLOBAL,&Globals.pid_file, NULL,0}, + {"port", P_INTEGER,P_GLOBAL,&Globals.rsync_port, NULL,0}, ++ {"slp refresh", P_INTEGER,P_GLOBAL,&Globals.slp_refresh, NULL,0}, + {"socket options", P_STRING, P_GLOBAL,&Globals.socket_options, NULL,0}, + {"syslog facility", P_ENUM, P_GLOBAL,&Globals.syslog_facility,enum_facilities,0}, + +@@ -379,6 +381,7 @@ FN_GLOBAL_STRING(lp_pid_file, &Globals.p + FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options) + + FN_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port) ++FN_GLOBAL_INTEGER(lp_slp_refresh, &Globals.slp_refresh) + FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility) + + FN_LOCAL_STRING(lp_auth_users, auth_users) +--- orig/main.c 2006-02-02 02:41:09 ++++ main.c 2006-02-02 11:33:24 +@@ -952,6 +952,18 @@ static int start_client(int argc, char * + if (!read_batch) { /* for read_batch, NO source is specified */ + argc--; + shell_path = check_for_hostspec(argv[0], &shell_machine, &rsync_port); ++ ++ if (shell_machine && !shell_machine[0]) { ++#ifdef HAVE_LIBSLP ++ /* User entered just rsync:// URI */ ++ print_service_list(); ++ exit_cleanup(0); ++#else /* No SLP, die here */ ++ rprintf(FINFO, "No SLP support, cannot browse\n"); ++ exit_cleanup(RERR_SYNTAX); ++#endif ++ } ++ + if (shell_path) { /* source is remote */ + char *dummy1; + int dummy2; +--- orig/options.c 2006-02-02 11:40:45 ++++ options.c 2006-02-02 11:41:16 +@@ -195,6 +195,7 @@ static void print_rsync_version(enum log + char const *hardlinks = "no "; + char const *links = "no "; + char const *ipv6 = "no "; ++ char const *slp = "no "; + STRUCT_STAT *dumstat; + + #ifdef HAVE_SOCKETPAIR +@@ -217,6 +218,10 @@ static void print_rsync_version(enum log + ipv6 = ""; + #endif + ++#if HAVE_LIBSLP ++ slp = ""; ++#endif ++ + rprintf(f, "%s version %s protocol version %d\n", + RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION); + rprintf(f, "Copyright (C) 1996-2006 by Andrew Tridgell, Wayne Davison, and others.\n"); +@@ -229,9 +234,9 @@ static void print_rsync_version(enum log + /* Note that this field may not have type ino_t. It depends + * on the complicated interaction between largefile feature + * macros. */ +- rprintf(f, " %sinplace, %sIPv6, " ++ rprintf(f, " %sinplace, %sIPv6, %sSLP, " + "%d-bit system inums, %d-bit internal inums\n", +- have_inplace, ipv6, ++ have_inplace, ipv6, slp, + (int) (sizeof dumstat->st_ino * 8), + (int) (sizeof (int64) * 8)); + #ifdef MAINTAINER_MODE +--- orig/rsync.h 2006-02-02 02:41:09 ++++ rsync.h 2006-02-02 00:00:00 +@@ -154,6 +154,9 @@ + #define SIGNIFICANT_ITEM_FLAGS (~(\ + ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE)) + ++/* this is the minimum we'll use, irrespective of config setting */ ++/* definately don't set to less than about 30 seconds */ ++#define SLP_MIN_TIMEOUT 120 + + /* Log-message categories. Only FERROR and FINFO get sent over the socket. + * FLOG and FCLIENT are only used on the daemon side for custom logging, +--- orig/rsync.yo 2006-01-31 03:05:44 ++++ rsync.yo 2006-02-02 10:44:29 +@@ -137,7 +137,12 @@ particular rsync daemon by leaving off t + + quote(tt(rsync somehost.mydomain.com::)) + +-See the following section for more details. ++And, if Service Location Protocol is available, the following will list the ++available rsync servers: ++ ++quote(tt(rsync rsync://)) ++ ++See the following section for even more usage details. + + manpagesection(ADVANCED USAGE) + +--- orig/rsyncd.conf 2006-02-02 00:00:00 ++++ rsyncd.conf 2006-02-02 00:00:00 +@@ -0,0 +1,3 @@ ++ ++slp refresh = 300 ++ +--- orig/rsyncd.conf.yo 2006-01-31 02:30:18 ++++ rsyncd.conf.yo 2006-02-02 10:40:24 +@@ -119,6 +119,15 @@ details on some of the options you may b + special socket options are set. These settings are superseded by the + bf(--sockopts) command-line option. + ++dit(bf(slp refresh)) This option is used to determine how long service ++advertisements are valid (measured in seconds), and is only applicable if ++you have Service Location Protocol support compiled in. If this option is ++not set or is set to zero, then service advertisements never time out. If ++this is set to less than 120 seconds, then 120 seconds is used. If it is ++set to more than 65535, then 65535 is used (which is a limitation of SLP). ++Using 3600 (one hour) is a good number if you tend to change your ++configuration. ++ + enddit() + + +@@ -540,6 +549,7 @@ use chroot = no + max connections = 4 + syslog facility = local5 + pid file = /var/run/rsyncd.pid ++slp refresh = 3600 + + [ftp] + path = /var/ftp/pub +--- orig/socket.c 2006-02-02 02:41:09 ++++ socket.c 2006-02-02 10:28:15 +@@ -447,6 +447,14 @@ void start_accept_loop(int port, int (*f + { + fd_set deffds; + int *sp, maxfd, i; ++ time_t next_slp_refresh; ++ short slp_timeout = lp_slp_refresh(); ++ if (slp_timeout) { ++ if (slp_timeout < SLP_MIN_TIMEOUT) ++ slp_timeout = SLP_MIN_TIMEOUT; ++ /* re-register before slp times out */ ++ slp_timeout -= 15; ++ } + + #if defined HAVE_SIGACTION && defined HAVE_SIGPROCMASK + sigact.sa_flags = SA_NOCLDSTOP; +@@ -475,14 +483,20 @@ void start_accept_loop(int port, int (*f + maxfd = sp[i]; + } + ++ next_slp_refresh = time(NULL) + slp_timeout; ++ + /* now accept incoming connections - forking a new process + * for each incoming connection */ + while (1) { + fd_set fds; + pid_t pid; + int fd; ++ int sel_ret; ++ struct timeval slp_tv; + struct sockaddr_storage addr; + socklen_t addrlen = sizeof addr; ++ slp_tv.tv_sec = 10; ++ slp_tv.tv_usec = 0; + + /* close log file before the potentially very long select so + * file can be trimmed by another process instead of growing +@@ -494,8 +508,13 @@ void start_accept_loop(int port, int (*f + #else + fds = deffds; + #endif +- +- if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1) ++ sel_ret = select(maxfd + 1, &fds, NULL, NULL, slp_timeout ? &slp_tv: NULL); ++ if (sel_ret == 0 && slp_timeout && time(NULL) > next_slp_refresh) { ++ rprintf(FINFO, "Service registration expired, refreshing it\n"); ++ register_services(); ++ next_slp_refresh = time(NULL) + slp_timeout; ++ } ++ if (sel_ret != 1) + continue; + + for (i = 0, fd = -1; sp[i] >= 0; i++) { +--- orig/srvloc.c 2006-02-02 11:19:54 ++++ srvloc.c 2006-02-02 11:19:54 +@@ -0,0 +1,105 @@ ++/* -*- c-file-style: "linux"; -*- ++ ++ Copyright (C) 2002 by Brad Hards ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++/* This file implements the service location functionality */ ++/* Basically, it uses normal Service Location Protocol API */ ++ ++/* It is really a cheap hack - just to show how it might work ++ in a real application. ++*/ ++ ++#include "rsync.h" ++ ++#include ++#include ++#include ++ ++/* This one just prints out the attributes */ ++static SLPBoolean getAttrCallback(UNUSED(SLPHandle hslp), const char *attrlist, ++ SLPError errcode, UNUSED(void *cookie)) ++{ ++ char *cleanstr; ++ ++ if (errcode == SLP_OK) { ++ if (!strcmp(attrlist, "(comment=)")) { ++ rprintf(FINFO, "\t(No description)\n"); ++ } else { ++ cleanstr = strrchr(attrlist, ')') ; ++ *cleanstr = ' '; /* remove last ')' */ ++ rprintf(FINFO, "\t%s\n", strchr(attrlist, '=') + 1); ++ } ++ } ++ return SLP_FALSE; ++} ++ ++SLPBoolean getSLPSrvURLCallback(UNUSED(SLPHandle hslp), const char *srvurl, ++ UNUSED(unsigned short lifetime), SLPError errcode, ++ void *cookie) ++{ ++ SLPError result; ++ SLPHandle attrhslp; ++ ++ if (errcode == SLP_OK) { ++ /* chop service: off the front */ ++ rprintf(FINFO, " %s ", (strchr(srvurl, ':') + 1)); ++ /* check for any attributes */ ++ if (SLPOpen("en", SLP_FALSE,&attrhslp) == SLP_OK) { ++ result = SLPFindAttrs(attrhslp, srvurl, ++ "", /* return all attributes */ ++ "", /* use configured scopes */ ++ getAttrCallback, NULL); ++ if (result != SLP_OK) { ++ rprintf(FERROR, "errorcode: %i\n",result); ++ } ++ SLPClose(attrhslp); ++ } ++ *(SLPError*)cookie = SLP_OK; ++ } else { ++ *(SLPError*)cookie = errcode; ++ } ++ ++ ++ /* Return SLP_TRUE because we want to be called again ++ * if more services were found. */ ++ ++ return SLP_TRUE; ++} ++ ++int print_service_list(void) ++{ ++ SLPError err; ++ SLPError callbackerr; ++ SLPHandle hslp; ++ ++ err = SLPOpen("en",SLP_FALSE,&hslp); ++ if (err != SLP_OK) { ++ rprintf(FERROR, "Error opening slp handle %i\n", err); ++ return err; ++ } ++ ++ SLPFindSrvs(hslp, "rsync", ++ 0, /* use configured scopes */ ++ 0, /* no attr filter */ ++ getSLPSrvURLCallback, &callbackerr); ++ ++ /* Now that we're done using slp, close the slp handle */ ++ SLPClose(hslp); ++ ++ return 0; ++} +--- orig/srvreg.c 2006-02-02 11:20:37 ++++ srvreg.c 2006-02-02 11:20:37 +@@ -0,0 +1,128 @@ ++/* -*- c-file-style: "linux"; -*- ++ ++ Copyright (C) 2002 by Brad Hards ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++/* This file implements the service registration functionality */ ++ ++/* Basically, it uses normal Service Location Protocol API */ ++ ++#include "rsync.h" ++#include "slp.h" ++#include "netdb.h" ++ ++extern int rsync_port; ++ ++static void slp_callback(UNUSED(SLPHandle hslp), SLPError errcode, void *cookie) ++{ ++ /* return the error code in the cookie */ ++ *(SLPError*)cookie = errcode; ++ ++ /* You could do something else here like print out ++ * the errcode, etc. Remember, as a general rule, ++ * do not try to do too much in a callback because ++ * it is being executed by the same thread that is ++ * reading slp packets from the wire. */ ++} ++ ++int register_services(void) ++{ ++ SLPError err, callbackerr; ++ SLPHandle hslp; ++ int n; ++ int i; ++ char srv[120]; ++ char attr[120]; ++ char localhost[256]; ++ extern char *config_file; ++ short timeout; ++ struct addrinfo aih, *ai = 0; ++ ++ if (!lp_load(config_file, 0)) { ++ exit_cleanup(RERR_SYNTAX); ++ } ++ ++ n = lp_numservices(); ++ ++ if (0 == lp_slp_refresh()) ++ timeout = SLP_LIFETIME_MAXIMUM; /* don't expire, ever */ ++ else if (SLP_MIN_TIMEOUT > lp_slp_refresh()) ++ timeout = SLP_MIN_TIMEOUT; /* use a reasonable minimum */ ++ else if (SLP_LIFETIME_MAXIMUM <= lp_slp_refresh()) ++ timeout = (SLP_LIFETIME_MAXIMUM - 1); /* as long as possible */ ++ else ++ timeout = lp_slp_refresh(); ++ ++ rprintf(FINFO, "rsyncd registering %d service%s with slpd for %d seconds:\n", n, ((n==1)? "":"s"), timeout); ++ err = SLPOpen("en",SLP_FALSE,&hslp); ++ if (err != SLP_OK) { ++ rprintf(FINFO, "Error opening slp handle %i\n",err); ++ return err; ++ } ++ if (gethostname(localhost, sizeof localhost)) { ++ rprintf(FINFO, "Could not get hostname: %s\n", strerror(errno)); ++ return err; ++ } ++ memset(&aih, 0, sizeof aih); ++ aih.ai_family = PF_UNSPEC; ++ aih.ai_flags = AI_CANONNAME; ++ if (0 != (err = getaddrinfo(localhost, 0, &aih, &ai)) || !ai) { ++ rprintf(FINFO, "Could not resolve hostname: %s\n", gai_strerror(err)); ++ return err; ++ } ++ /* Register each service with SLP */ ++ for (i = 0; i < n; i++) { ++ if (!lp_list(i)) ++ continue; ++ ++ snprintf(srv, sizeof srv, "service:rsync://%s:%d/%s", ++ ai->ai_canonname, ++ rsync_port, ++ lp_name(i)); ++ rprintf(FINFO, " %s\n", srv); ++ if (lp_comment(i)) { ++ snprintf(attr, sizeof attr, "(comment=%s)", ++ lp_comment(i)); ++ } ++ err = SLPReg(hslp, ++ srv, /* service to register */ ++ timeout, ++ 0, /* this is ignored */ ++ attr, /* attributes */ ++ SLP_TRUE, /* new registration - don't change this */ ++ slp_callback, /* callback */ ++ &callbackerr); ++ ++ /* err may contain an error code that occurred as the slp library ++ * _prepared_ to make the call. */ ++ if (err != SLP_OK || callbackerr != SLP_OK) ++ rprintf(FINFO, "Error registering service with slp %i\n", err); ++ ++ /* callbackerr may contain an error code (that was assigned through ++ * the callback cookie) that occurred as slp packets were sent on ++ * the wire. */ ++ if (callbackerr != SLP_OK) ++ rprintf(FINFO, "Error registering service with slp %i\n",callbackerr); ++ } ++ ++ /* Now that we're done using slp, close the slp handle */ ++ freeaddrinfo(ai); ++ SLPClose(hslp); ++ ++ /* refresh is done in main select loop */ ++ return 0; ++} -- 2.34.1