Skip to content
Browse files

Fixed socket descriptor detection method used by nodelay option

  • Loading branch information...
1 parent 7ba9e2d commit cecf787811d5db9136d911105fa7e9d551b6790d @bwlewis committed Feb 28, 2014
Showing with 53 additions and 8 deletions.
  1. +10 −6 R/redis-internal.R
  2. +43 −2 src/libsock.c
View
16 R/redis-internal.R
@@ -17,16 +17,20 @@
stopifnot(is.character(host))
stopifnot(is.numeric(port))
stopifnot(is.logical(nodelay))
-# We track the file descriptor of the new connection in a sneaky way
- fds <- rownames(showConnections(all=TRUE))
+# We track the file descriptor of the new connection in a crude way
+ fds <- .Call("OPEN_FD",PACKAGE="rredis")
+# fds <- rownames(showConnections(all=TRUE)) # this doesn't work FYI
con <- socketConnection(host, port, open="a+b",
blocking=TRUE, timeout=timeout)
- fd <- rownames(showConnections(all=TRUE))
- fd <- as.integer(setdiff(fd,fds))
- if(nodelay)
+ fd <- as.integer(setdiff(.Call("OPEN_FD",PACKAGE="rredis"),fds))
+ if(length(fd)>0 && nodelay)
{
Nagle <- .Call("SOCK_NAGLE",fd,1L,PACKAGE="rredis")
- if(Nagle!=1) warning("Unable to set nodelay.")
+ if(Nagle!=1)
+ {
+ nodelay <- FALSE
+ warning("Unable to set nodelay.")
+ }
}
# Stash state in the redis enivronment describing this connection:
assign('fd',fd,envir=envir)
View
45 src/libsock.c
@@ -8,31 +8,72 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h> // TCP_NODELAY
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
+#define CHECKFD 8192
#endif
#include <R.h>
+#define USE_RINTERNALS
#include <Rinternals.h>
+#include <R_ext/Connections.h>
+
+/* Crudely report open file descriptors on unix-like systems This is used to
+ * infer the active socket descriptor to apply TCP_NODELAY. This is a
+ * provisional approach. In the next package version, we'll define a new
+ * R_new_custom_connection object for rredis instead.
+ */
+SEXP OPEN_FD()
+{
+#ifdef WIN32
+ return R_NilValue;
+#endif
+ SEXP ans;
+ struct stat s;
+ int j, k, l = 0;
+ int buf[CHECKFD];
+ for(j=0;j<CHECKFD;++j)
+ {
+ k = fstat(j,&s);
+ if(k>=0)
+ {
+ buf[l] = j;
+ l++;
+ }
+ }
+ PROTECT (ans = allocVector (INTSXP, l));
+ for(j=0;j<l;++j)
+ {
+ INTEGER(ans)[j] = buf[j];
+ }
+ UNPROTECT (1);
+ return ans;
+}
+
/* Set the Nagle socket option for socket S to an integer value VAL,
* returning the set value.
*/
SEXP SOCK_NAGLE(SEXP S, SEXP VAL)
{
+ socklen_t len;
int val = INTEGER(VAL)[0];
#ifdef WIN32
SOCKET s = (SOCKET)INTEGER(S)[0];
#else
int s = INTEGER(S)[0];
#endif
- if(val==1)
+ len = sizeof(val);
+ if(val>=0)
{
- setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+ val = (int)(setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const void *)&val, len) == 0);
+ if(val<0) error("Error setting TCP_NODELAY");
}
+ if(getsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&val, &len) < 0) error("Error setting TCP_NODELAY");
return ScalarInteger(val);
}

0 comments on commit cecf787

Please sign in to comment.
Something went wrong with that request. Please try again.