Commit eecd22ff authored by Martin Pool's avatar Martin Pool

Merge in the LIBSMB_PROG idea from samba, so that you can do

  RSYNC_CONNECT_PROG='./rsync --daemon' ./rsync -vvvvvv  localhost::

to test as a daemon without actually having to listen on a port.
parent add7e8fb
......@@ -78,7 +78,7 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
if (!user) user = getenv("USER");
if (!user) user = getenv("LOGNAME");
fd = open_socket_out(host, rsync_port, &socket_address);
fd = open_socket_out_wrapped (host, rsync_port, &socket_address);
if (fd == -1) {
exit_cleanup(RERR_SOCKETIO);
}
......
......@@ -533,3 +533,6 @@ size_t strlcat(char *d, const char *s, size_t bufsize);
#endif
#define exit_cleanup(code) _exit_cleanup(code, __FILE__, __LINE__)
extern int verbose;
/* -*- c-file-style: "linux" -*-
Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
Copyright (C) 2001 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
......@@ -90,10 +90,13 @@ static int establish_proxy_connection(int fd, char *host, int port)
}
/* open a socket to a tcp remote host with the specified port
based on code from Warren
proxy support by Stephen Rothwell */
int open_socket_out(char *host, int port, struct in_addr *address)
static int open_socket_out (char *host,
int port,
struct in_addr *address)
{
int type = SOCK_STREAM;
struct sockaddr_in sock_out;
......@@ -152,7 +155,8 @@ int open_socket_out(char *host, int port, struct in_addr *address)
}
if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
rprintf(FERROR,"failed to connect to %s - %s\n", h, strerror(errno));
rprintf (FERROR, RSYNC_NAME ": failed to connect to host %s: %s\n",
h, strerror(errno));
close(res);
return -1;
}
......@@ -166,6 +170,30 @@ int open_socket_out(char *host, int port, struct in_addr *address)
}
/**
* Open an outgoing socket, but allow for it to be intercepted by
* $RSYNC_CONNECT_PROG, which will execute a program across a TCP
* socketpair rather than really opening a socket.
*
* We use this primarily in testing to detect TCP flow bugs, but not
* cause security problems by really opening remote connections.
*
* This is based on the Samba LIBSMB_PROG feature.
**/
int open_socket_out_wrapped (char *host,
int port,
struct in_addr *address)
{
char *prog;
if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
return sock_exec (prog);
else
return open_socket_out (host, port, address);
}
/****************************************************************************
open a socket of the specified type, port and address for incoming data
****************************************************************************/
......@@ -185,7 +213,7 @@ static int open_socket_in(int type, int port, struct in_addr *address)
}
res = socket(AF_INET, type, 0);
if (res == -1) {
rprintf(FERROR,"socket failed: %s\n",
rprintf(FERROR, RSYNC_NAME ": socket failed: %s\n",
strerror(errno));
return -1;
}
......@@ -573,3 +601,107 @@ struct in_addr *ip_address(const char *str)
return &ret;
}
/*******************************************************************
this is like socketpair but uses tcp. It is used by the Samba
regression test code
The function guarantees that nobody else can attach to the socket,
or if they do that this function fails and the socket gets closed
returns 0 on success, -1 on failure
the resulting file descriptors are symmetrical
******************************************************************/
static int socketpair_tcp(int fd[2])
{
int listener;
struct sockaddr_in sock;
struct sockaddr_in sock2;
socklen_t socklen = sizeof(sock);
int connect_done = 0;
fd[0] = fd[1] = listener = -1;
memset(&sock, 0, sizeof(sock));
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
memset(&sock2, 0, sizeof(sock2));
#ifdef HAVE_SOCK_SIN_LEN
sock2.sin_len = sizeof(sock2);
#endif
sock2.sin_family = PF_INET;
bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
if (listen(listener, 1) != 0) goto failed;
if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
set_nonblocking(fd[1]);
sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
if (errno != EINPROGRESS) goto failed;
} else {
connect_done = 1;
}
if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
close(listener);
if (connect_done == 0) {
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
&& errno != EISCONN) goto failed;
}
set_blocking (fd[1]);
/* all OK! */
return 0;
failed:
if (fd[0] != -1) close(fd[0]);
if (fd[1] != -1) close(fd[1]);
if (listener != -1) close(listener);
return -1;
}
/*******************************************************************
run a program on a local tcp socket, this is used to launch smbd
when regression testing
the return value is a socket which is attached to a subprocess
running "prog". stdin and stdout are attached. stderr is left
attached to the original stderr
******************************************************************/
int sock_exec(const char *prog)
{
int fd[2];
if (socketpair_tcp(fd) != 0) {
rprintf (FERROR, RSYNC_NAME
": socketpair_tcp failed (%s)\n",
strerror(errno));
return -1;
}
if (fork() == 0) {
close(fd[0]);
close(0);
close(1);
dup(fd[1]);
dup(fd[1]);
if (verbose > 3)
fprintf (stderr,
RSYNC_NAME ": execute socket program \"%s\"\n",
prog);
exit (system (prog));
}
close (fd[1]);
return fd[0];
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment