From 86a08269137ad38f2d34ab5b2b2131018986b931 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Mon, 16 Jul 2012 14:17:58 -0700 Subject: [PATCH] rspreload: Make socket_fallback() call more generic socket_fallback is used to switch from an rsocket to a normal socket in the case of failures. Rename the call and make it more generic, so that it can switch between an rsocket and a normal socket in either direction. This will be used to support fork(). Signed-off-by: Sean Hefty --- src/preload.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/preload.c b/src/preload.c index 2750b301..69597e05 100644 --- a/src/preload.c +++ b/src/preload.c @@ -300,6 +300,68 @@ err: return ret; } +/* + * Convert between an rsocket and a normal socket. The new socket should have the + * same settings and bindings as the current socket. We currently only handle + * setting a few of the more common values. + */ +static int +transpose_socket(int index, int *fd, enum fd_type new_type, + int (*socket_new)(int domain, int type, int protocol), + int (*shutdown_old)(int socket, int how), + int (*close_old)(int socket), + int (*getsockname_old)(int socket, struct sockaddr *addr, + socklen_t *addrlen), + int (*getsockopt_old)(int socket, int level, int optname, + void *optval, socklen_t *optlen), + int (*setsockopt_new)(int socket, int level, int optname, + const void *optval, socklen_t optlen), + int (*fcntl_old)(int socket, int cmd, ... /* arg */), + int (*fcntl_new)(int socket, int cmd, ... /* arg */)) +{ + socklen_t len = 0; + int new_fd, param, ret; + + ret = getsockname_old(*fd, NULL, &len); + if (ret) + return ret; + + param = (len == sizeof(struct sockaddr_in6)) ? PF_INET6 : PF_INET; + new_fd = socket_new(param, SOCK_STREAM, 0); + if (new_fd < 0) + return new_fd; + + ret = fcntl_old(*fd, F_GETFL); + if (ret > 0) + ret = fcntl_new(new_fd, F_SETFL, ret); + if (ret) + goto err; + + len = sizeof param; + ret = getsockopt_old(*fd, SOL_SOCKET, SO_REUSEADDR, ¶m, &len); + if (param && !ret) + ret = setsockopt_new(new_fd, SOL_SOCKET, SO_REUSEADDR, ¶m, len); + if (ret) + goto err; + + len = sizeof param; + ret = getsockopt_old(*fd, IPPROTO_TCP, TCP_NODELAY, ¶m, &len); + if (param && !ret) + ret = setsockopt_new(new_fd, IPPROTO_TCP, TCP_NODELAY, ¶m, len); + if (ret) + goto err; + + shutdown_old(*fd, SHUT_RDWR); + close_old(*fd); + fd_store(socket, new_fd, new_type); + *fd = new_fd; + return 0; + +err: + real_close(new_fd); + return ret; +} + /* * Use defaults on failure. */ -- 2.45.2