From: Sean Hefty Date: Mon, 16 Jul 2012 21:18:52 +0000 (-0700) Subject: Refresh of transpose X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=018fff2b15218aa621bcbd991530d483b86ac3d2;p=~shefty%2Flibrdmacm.git Refresh of transpose --- diff --git a/src/preload.c b/src/preload.c index 2750b301..8b9fbafd 100644 --- a/src/preload.c +++ b/src/preload.c @@ -92,10 +92,12 @@ static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; static int sq_size; static int rq_size; static int sq_inline; +static int fork_support; enum fd_type { fd_normal, - fd_rsocket + fd_rsocket, + fd_fork }; struct fd_info { @@ -207,6 +209,10 @@ void getenv_options(void) var = getenv("RS_INLINE"); if (var) sq_inline = atoi(var); + + var = getenv("RDMAV_FORK_SAFE"); + if (var) + fork_support = atoi(var); } static void init_preload(void) @@ -300,6 +306,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. */ @@ -332,8 +400,16 @@ int socket(int domain, int type, int protocol) ret = rsocket(domain, type, protocol); recursive = 0; if (ret >= 0) { - fd_store(index, ret, fd_rsocket); - set_rsocket_options(ret); + if (fork_support) { + rclose(ret); + ret = real_socket(domain, type, protocol); + if (ret < 0) + return ret; + fd_store(index, ret, fd_fork); + } else { + fd_store(index, ret, fd_rsocket); + set_rsocket_options(ret); + } return index; } fd_close(index, &ret); @@ -388,6 +464,29 @@ int accept(int socket, struct sockaddr *addr, socklen_t *addrlen) } } +static int connect_fork(int socket, const struct sockaddr *addr, socklen_t addrlen) +{ + uint32_t msg; + int rs, fd, ret; + + fd = fd_getd(socket); + ret = real_connect(fd, addr, addrlen); + if (!ret) + return ret; + + ret = real_read(fd, &msg, sizeof msg); + if (ret != sizeof msg) + return ret; + + rs = rsocket(domain, type, protocol); + + real_shutdown(fd, SHUT_RDWR); + real_close(fd); + + fd_store(socket, fd, fd_rsocket); + return connect(socket, addr, addrlen); +} + int connect(int socket, const struct sockaddr *addr, socklen_t addrlen) { struct sockaddr_in *sin;