diff options
Diffstat (limited to 'sshnodelay.c')
-rw-r--r-- | sshnodelay.c | 49 |
1 files changed, 45 insertions, 4 deletions
diff --git a/sshnodelay.c b/sshnodelay.c index 7518089..a9f307c 100644 --- a/sshnodelay.c +++ b/sshnodelay.c @@ -5,14 +5,55 @@ #include <netinet/in.h> #include <netinet/tcp.h> -int connect(int sock, const struct sockaddr *addr, socklen_t addrlen) +/* Wrapper around connect(2) to explicitly set TCP_NODELAY. */ +static int nodelay_connect( + int (*real_connect)(int, const struct sockaddr *, socklen_t), + int sock, const struct sockaddr *addr, socklen_t addrlen) { - int (*next_connect)(int, const struct sockaddr *, socklen_t) = - dlsym(RTLD_NEXT, "connect"); - int res = next_connect(sock, addr, addrlen); + int res = real_connect(sock, addr, addrlen); if (!res && addr->sa_family == AF_INET) { int opt = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); } return res; } + +#if __APPLE__ + +/* OS X does not have LD_PRELOAD but has DYLD_INSERT_LIBRARIES. The right + * environment variable is set by sshfs.c when attempting to load the + * sshnodelay workaround. + * + * However, things are not that simple: DYLD_INSERT_LIBRARIES does not + * behave exactly like LD_PRELOAD. Instead, the dyld dynamic linker will + * look for __DATA __interpose sections on the libraries given via the + * DYLD_INSERT_LIBRARIES variable. The contents of this section are pairs + * of replacement functions and functions to be replaced, respectively. + * Prepare such section here. */ + +int custom_connect(int sock, const struct sockaddr *addr, socklen_t addrlen); + +typedef struct interpose_s { + void *new_func; + void *orig_func; +} interpose_t; + +static const interpose_t interposers[] \ + __attribute__ ((section("__DATA, __interpose"))) = { + { (void *)custom_connect, (void *)connect }, +}; + +int custom_connect(int sock, const struct sockaddr *addr, socklen_t addrlen) +{ + return nodelay_connect(connect, sock, addr, addrlen); +} + +#else /* !__APPLE__ */ + +int connect(int sock, const struct sockaddr *addr, socklen_t addrlen) +{ + return nodelay_connect(dlsym(RTLD_NEXT, "connect"), + sock, addr, addrlen); +} + +#endif /* !__APPLE__ */ |