diff --git a/src/anet.c b/src/anet.c index 4fe811a1..514da8fa 100644 --- a/src/anet.c +++ b/src/anet.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -177,6 +178,43 @@ int anetTcpNonBlockConnect(char *err, char *addr, int port) return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK); } +int anetUnixGenericConnect(char *err, char *path, int flags) +{ + int s; + struct sockaddr_un sa; + + if ((s = socket(AF_LOCAL,SOCK_STREAM,0)) == -1) { + anetSetError(err, "creating socket: %s\n", strerror(errno)); + return ANET_ERR; + } + sa.sun_family = AF_LOCAL; + strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1); + if (flags & ANET_CONNECT_NONBLOCK) { + if (anetNonBlock(err,s) != ANET_OK) + return ANET_ERR; + } + if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) == -1) { + if (errno == EINPROGRESS && + flags & ANET_CONNECT_NONBLOCK) + return s; + + anetSetError(err, "connect: %s\n", strerror(errno)); + close(s); + return ANET_ERR; + } + return s; +} + +int anetUnixConnect(char *err, char *path) +{ + return anetUnixGenericConnect(err,path,ANET_CONNECT_NONE); +} + +int anetUnixNonBlockConnect(char *err, char *path) +{ + return anetUnixGenericConnect(err,path,ANET_CONNECT_NONBLOCK); +} + /* Like read(2) but make sure 'count' is read before to return * (unless error or EOF condition is encountered) */ int anetRead(int fd, char *buf, int count) @@ -245,6 +283,31 @@ int anetTcpServer(char *err, int port, char *bindaddr) return s; } +int anetUnixServer(char *err, char *path) +{ + int s; + struct sockaddr_un sa; + + if ((s = socket(AF_LOCAL,SOCK_STREAM,0)) == -1) { + anetSetError(err, "socket: %s\n", strerror(errno)); + return ANET_ERR; + } + memset(&sa,0,sizeof(sa)); + sa.sun_family = AF_LOCAL; + strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1); + if (bind(s,(struct sockaddr*)&sa,SUN_LEN(&sa)) == -1) { + anetSetError(err, "bind: %s\n", strerror(errno)); + close(s); + return ANET_ERR; + } + if (listen(s, 511) == -1) { /* the magic 511 constant is from nginx */ + anetSetError(err, "listen: %s\n", strerror(errno)); + close(s); + return ANET_ERR; + } + return s; +} + int anetAccept(char *err, int serversock, char *ip, int *port) { int fd; diff --git a/src/anet.h b/src/anet.h index ce0f4778..10db3d2f 100644 --- a/src/anet.h +++ b/src/anet.h @@ -37,9 +37,12 @@ int anetTcpConnect(char *err, char *addr, int port); int anetTcpNonBlockConnect(char *err, char *addr, int port); +int anetUnixConnect(char *err, char *path); +int anetUnixNonBlockConnect(char *err, char *path); int anetRead(int fd, char *buf, int count); int anetResolve(char *err, char *host, char *ipbuf); int anetTcpServer(char *err, int port, char *bindaddr); +int anetUnixServer(char *err, char *path); int anetAccept(char *err, int serversock, char *ip, int *port); int anetWrite(int fd, char *buf, int count); int anetNonBlock(char *err, int fd); diff --git a/src/redis-benchmark.c b/src/redis-benchmark.c index 123d8118..b3e729f1 100644 --- a/src/redis-benchmark.c +++ b/src/redis-benchmark.c @@ -71,6 +71,7 @@ static struct config { aeEventLoop *el; char *hostip; int hostport; + char *hostsocket; int keepalive; long long start; long long totlatency; @@ -340,7 +341,11 @@ static client createClient(void) { client c = zmalloc(sizeof(struct _client)); char err[ANET_ERR_LEN]; - c->fd = anetTcpNonBlockConnect(err,config.hostip,config.hostport); + if (config.hostsocket == NULL) + c->fd = anetTcpNonBlockConnect(err,config.hostip,config.hostport); + else + c->fd = anetUnixNonBlockConnect(err,config.hostsocket); + if (c->fd == ANET_ERR) { zfree(c); fprintf(stderr,"Connect: %s\n",err); @@ -436,6 +441,9 @@ void parseOptions(int argc, char **argv) { } else if (!strcmp(argv[i],"-p") && !lastarg) { config.hostport = atoi(argv[i+1]); i++; + } else if (!strcmp(argv[i],"-s") && !lastarg) { + config.hostsocket = argv[i+1]; + i++; } else if (!strcmp(argv[i],"-d") && !lastarg) { config.datasize = atoi(argv[i+1]); i++; @@ -459,7 +467,8 @@ void parseOptions(int argc, char **argv) { printf("Wrong option '%s' or option argument missing\n\n",argv[i]); printf("Usage: redis-benchmark [-h ] [-p ] [-c ] [-n [-k ]\n\n"); printf(" -h Server hostname (default 127.0.0.1)\n"); - printf(" -p Server port (default 6379)\n"); + printf(" -p Server port (default 6379)\n"); + printf(" -s Server socket (overrides host and port)\n"); printf(" -c Number of parallel connections (default 50)\n"); printf(" -n Total number of requests (default 10000)\n"); printf(" -d Data size of SET/GET value in bytes (default 2)\n"); @@ -505,6 +514,7 @@ int main(int argc, char **argv) { config.hostip = "127.0.0.1"; config.hostport = 6379; + config.hostsocket = NULL; parseOptions(argc,argv); diff --git a/src/redis.c b/src/redis.c index c8b1c781..397dd65a 100644 --- a/src/redis.c +++ b/src/redis.c @@ -773,9 +773,16 @@ void initServer() { createSharedObjects(); server.el = aeCreateEventLoop(); server.db = zmalloc(sizeof(redisDb)*server.dbnum); - server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr); + if (server.bindaddr == NULL || inet_aton(server.bindaddr,NULL)) { + /* Either no address given, or it can be correctly parsed. */ + server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr); + } else { + /* Bind to a socket */ + unlink(server.bindaddr); /* don't care if this fails */ + server.fd = anetUnixServer(server.neterr,server.bindaddr); + } if (server.fd == -1) { - redisLog(REDIS_WARNING, "Opening TCP port: %s", server.neterr); + redisLog(REDIS_WARNING, "Opening port/socket: %s", server.neterr); exit(1); } for (j = 0; j < server.dbnum; j++) {