--- embedaddon/rsync/socket.c 2013/10/14 07:51:14 1.1.1.2 +++ embedaddon/rsync/socket.c 2021/03/17 00:32:36 1.1.1.4 @@ -3,7 +3,7 @@ * * Copyright (C) 1992-2001 Andrew Tridgell * Copyright (C) 2001, 2002 Martin Pool - * Copyright (C) 2003-2013 Wayne Davison + * Copyright (C) 2003-2020 Wayne Davison * * 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 @@ -26,6 +26,7 @@ #include "rsync.h" #include "itypes.h" +#include "ifuncs.h" #ifdef HAVE_NETINET_IN_SYSTM_H #include #endif @@ -38,6 +39,9 @@ extern char *bind_address; extern char *sockopts; extern int default_af_hint; extern int connect_timeout; +extern int pid_file_fd; +extern int diffserv; +extern char *congestion_alg; #ifdef HAVE_SIGACTION static struct sigaction sigact; @@ -48,8 +52,7 @@ static int sock_exec(const char *prog); /* Establish a proxy connection on an open socket to a web proxy by using the * CONNECT method. If proxy_user and proxy_pass are not NULL, they are used to * authenticate to the proxy using the "Basic" proxy-authorization protocol. */ -static int establish_proxy_connection(int fd, char *host, int port, - char *proxy_user, char *proxy_pass) +static int establish_proxy_connection(int fd, char *host, int port, char *proxy_user, char *proxy_pass) { char *cp, buffer[1024]; char *authhdr, authbuf[1024]; @@ -73,9 +76,8 @@ static int establish_proxy_connection(int fd, char *ho authhdr = ""; } - snprintf(buffer, sizeof buffer, "CONNECT %s:%d HTTP/1.0%s%s\r\n\r\n", - host, port, authhdr, authbuf); - len = strlen(buffer); + len = snprintf(buffer, sizeof buffer, "CONNECT %s:%d HTTP/1.0%s%s\r\n\r\n", host, port, authhdr, authbuf); + assert(len > 0 && len < (int)sizeof buffer); if (write(fd, buffer, len) != len) { rsyserr(FERROR, errno, "failed to write to proxy"); return -1; @@ -161,11 +163,42 @@ int try_bind_local(int s, int ai_family, int ai_sockty } /* connect() timeout handler based on alarm() */ -static RETSIGTYPE contimeout_handler(UNUSED(int val)) +static void contimeout_handler(UNUSED(int val)) { connect_timeout = -1; } +/* Set special socket options + * + * Diffserv is a value in the range of 0-63, and needs to be shifted left + * 2 places AND treated differently for ipv4 and ipv6. + * Setting TCP congestion control is rather Linux specific (at the moment) + * and sends a varying length string to setsockopt rather than an integer + * or character. +*/ + +void set_special_sockopts(int s) +{ +#if defined(TCP_CONGESTION) + if (congestion_alg) { + if (setsockopt(s, SOL_TCP, TCP_CONGESTION, congestion_alg, strlen(congestion_alg)) == -1) + rprintf(FINFO, "Couldn't set %s congestion algorithm\n", congestion_alg); + } +#endif + +/* setting the diffserv/tos bits is different on ipv6 and + * ipv4, so we just hammer down on both and ignore the result + * And ipv6 demands an int for v. I didn't write the spec. + */ + if (diffserv) { + int v = (diffserv & 63) <<2; + setsockopt(s,IPPROTO_IP, IP_TOS, &v, sizeof(v)); +#if defined(IPV6_TCLASS) + setsockopt(s,IPPROTO_IPV6, IPV6_TCLASS, &v, sizeof(v)); +#endif + } +} + /* Open a socket to a tcp remote host with the specified port. * * Based on code from Warren. Proxy support by Stephen Rothwell. @@ -182,8 +215,7 @@ static RETSIGTYPE contimeout_handler(UNUSED(int val)) * bind_addr: local address to use. Normally NULL to bind the wildcard address. * * af_hint: address family, e.g. AF_INET or AF_INET6. */ -int open_socket_out(char *host, int port, const char *bind_addr, - int af_hint) +int open_socket_out(char *host, int port, const char *bind_addr, int af_hint) { int type = SOCK_STREAM; int error, s, j, addr_cnt, *errnos; @@ -195,7 +227,7 @@ int open_socket_out(char *host, int port, const char * char *proxy_user = NULL, *proxy_pass = NULL; /* if we have a RSYNC_PROXY env variable then redirect our - * connetcion via a web proxy at the given address. */ + * connection via a web proxy at the given address. */ h = getenv("RSYNC_PROXY"); proxied = h != NULL && *h != '\0'; @@ -250,8 +282,6 @@ int open_socket_out(char *host, int port, const char * for (res = res0, addr_cnt = 0; res; res = res->ai_next, addr_cnt++) {} errnos = new_array0(int, addr_cnt); - if (!errnos) - out_of_memory("open_socket_out"); s = -1; /* Try to connect to all addresses for this machine until we get @@ -275,6 +305,7 @@ int open_socket_out(char *host, int port, const char * alarm(connect_timeout); } + set_special_sockopts(s); set_socket_options(s, sockopts); while (connect(s, res->ai_addr, res->ai_addrlen) < 0) { if (connect_timeout < 0) @@ -294,9 +325,7 @@ int open_socket_out(char *host, int port, const char * continue; } - if (proxied - && establish_proxy_connection(s, host, port, - proxy_user, proxy_pass) != 0) { + if (proxied && establish_proxy_connection(s, host, port, proxy_user, proxy_pass) != 0) { close(s); s = -1; continue; @@ -340,8 +369,7 @@ int open_socket_out(char *host, int port, const char * * This is based on the Samba LIBSMB_PROG feature. * * bind_addr: local address to use. Normally NULL to get the stack default. */ -int open_socket_out_wrapped(char *host, int port, const char *bind_addr, - int af_hint) +int open_socket_out_wrapped(char *host, int port, const char *bind_addr, int af_hint) { char *prog = getenv("RSYNC_CONNECT_PROG"); @@ -359,8 +387,7 @@ int open_socket_out_wrapped(char *host, int port, cons len += hlen; } f = prog; - if (!(prog = new_array(char, len))) - out_of_memory("open_socket_out_wrapped"); + prog = new_array(char, len); for (t = prog; *f; f++) { if (*f == '%') { switch (*++f) { @@ -428,8 +455,6 @@ static int *open_socket_in(int type, int port, const c socks = new_array(int, maxs + 1); errmsgs = new_array(char *, maxs); - if (!socks || !errmsgs) - out_of_memory("open_socket_in"); /* We may not be able to create the socket, if for example the * machine knows about IPv6 in the C library, but not in the @@ -449,6 +474,7 @@ static int *open_socket_in(int type, int port, const c continue; } + set_special_sockopts(s); setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof one); if (sockopts) @@ -458,9 +484,8 @@ static int *open_socket_in(int type, int port, const c #ifdef IPV6_V6ONLY if (resp->ai_family == AF_INET6) { - if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, - (char *)&one, sizeof one) < 0 - && default_af_hint != AF_INET6) { + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof one) < 0 + && default_af_hint != AF_INET6) { close(s); continue; } @@ -529,10 +554,20 @@ int is_a_socket(int fd) } -static RETSIGTYPE sigchld_handler(UNUSED(int val)) +static void sigchld_handler(UNUSED(int val)) { #ifdef WNOHANG - while (waitpid(-1, NULL, WNOHANG) > 0) {} + int status; + while (waitpid(-1, &status, WNOHANG) > 0) { + if (WIFSIGNALED(status)) { + rprintf(FLOG, + "rsync error: (3) Child proccess has unexpectedly died with signal %d\n", + WTERMSIG(status)); + } else if (WIFEXITED(status) && WEXITSTATUS(status) == RERR_WECRASHED) { + rprintf(FLOG, + "rsync error: (3) Child proccess has CRASHED.\n"); + } + } #endif #ifndef HAVE_SIGACTION signal(SIGCHLD, sigchld_handler); @@ -544,6 +579,16 @@ void start_accept_loop(int port, int (*fn)(int, int)) { fd_set deffds; int *sp, maxfd, i; +#ifdef HAVE_LIBSLP + time_t next_slp_refresh; + short slp_timeout = lp_use_slp() ? lp_slp_refresh() : 0; + if (slp_timeout) { + if (slp_timeout < SLP_MIN_TIMEOUT) + slp_timeout = SLP_MIN_TIMEOUT; + /* re-register before slp times out */ + slp_timeout -= 15; + } +#endif #ifdef HAVE_SIGACTION sigact.sa_flags = SA_NOCLDSTOP; @@ -561,8 +606,7 @@ void start_accept_loop(int port, int (*fn)(int, int)) rsyserr(FERROR, errno, "listen() on socket failed"); #ifdef INET6 if (errno == EADDRINUSE && i > 0) { - rprintf(FINFO, - "Try using --ipv4 or --ipv6 to avoid this listen() error.\n"); + rprintf(FINFO, "Try using --ipv4 or --ipv6 to avoid this listen() error.\n"); } #endif exit_cleanup(RERR_SOCKETIO); @@ -572,15 +616,26 @@ void start_accept_loop(int port, int (*fn)(int, int)) maxfd = sp[i]; } +#ifdef HAVE_LIBSLP + next_slp_refresh = time(NULL) + slp_timeout; +#endif + /* 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 sockaddr_storage addr; socklen_t addrlen = sizeof addr; +#ifdef HAVE_LIBSLP + struct timeval slp_tv; + slp_tv.tv_sec = 10; + slp_tv.tv_usec = 0; +#endif + /* close log file before the potentially very long select so * file can be trimmed by another process instead of growing * forever */ @@ -592,13 +647,23 @@ void start_accept_loop(int port, int (*fn)(int, int)) fds = deffds; #endif - if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 1) +#ifdef HAVE_LIBSLP + 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; + } +#else + sel_ret = select(maxfd + 1, &fds, NULL, NULL, NULL); +#endif + if (sel_ret < 1) continue; for (i = 0, fd = -1; sp[i] >= 0; i++) { if (FD_ISSET(sp[i], &fds)) { - fd = accept(sp[i], (struct sockaddr *)&addr, - &addrlen); + fd = accept(sp[i], (struct sockaddr *)&addr, &addrlen); break; } } @@ -610,6 +675,8 @@ void start_accept_loop(int port, int (*fn)(int, int)) if ((pid = fork()) == 0) { int ret; + if (pid_file_fd >= 0) + close(pid_file_fd); for (i = 0; sp[i] >= 0; i++) close(sp[i]); /* Re-open log file in child before possibly giving @@ -690,9 +757,6 @@ void set_socket_options(int fd, char *options) options = strdup(options); - if (!options) - out_of_memory("set_socket_options"); - for (tok = strtok(options, " \t,"); tok; tok = strtok(NULL," \t,")) { int ret=0,i; int value = 1; @@ -797,8 +861,7 @@ static int socketpair_tcp(int fd[2]) set_blocking(fd[1]); if (connect_done == 0) { - if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0 - && errno != EISCONN) + if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0 && errno != EISCONN) goto failed; } @@ -820,7 +883,7 @@ static int socketpair_tcp(int fd[2]) * stdout. This is used to fake a connection to a daemon for testing -- not * for the normal case of running SSH. * - * Retruns a socket which is attached to a subprocess running "prog". stdin and + * Returns a socket which is attached to a subprocess running "prog". stdin and * stdout are attached. stderr is left attached to the original stderr. */ static int sock_exec(const char *prog) { @@ -847,7 +910,7 @@ static int sock_exec(const char *prog) fprintf(stderr, "Failed to run \"%s\"\n", prog); exit(1); } - exit(system(prog)); + exit(shell_exec(prog)); } close(fd[1]);