Ver Fonte

Unix Domain Socket

ithewei há 5 anos atrás
pai
commit
1d5e82e2ea
10 ficheiros alterados com 202 adições e 108 exclusões
  1. 12 0
      Makefile.in
  2. 1 0
      README.md
  3. 107 60
      base/hsocket.c
  4. 61 28
      base/hsocket.h
  5. 2 0
      config.mk
  6. 9 9
      configure
  7. 6 8
      event/hloop.c
  8. 2 2
      event/nio.c
  9. 1 1
      protocol/icmp.c
  10. 1 0
      readme_cn.md

+ 12 - 0
Makefile.in

@@ -124,6 +124,18 @@ else
 	CPPFLAGS += -DNDEBUG
 endif
 
+ifeq ($(ENABLE_IPV6), yes)
+	CPPFLAGS += -DENABLE_IPV6
+endif
+
+ifeq ($(ENABLE_UDS), yes)
+	CPPFLAGS += -DENABLE_UDS
+endif
+
+ifeq ($(USE_MULTIMAP), yes)
+	CPPFLAGS += -DUSE_MULTIMAP
+endif
+
 CPPFLAGS += $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(addprefix -I, $(INCDIRS))
 CPPFLAGS += $(addprefix -I, $(SRCDIRS))

+ 1 - 0
README.md

@@ -11,6 +11,7 @@ but simpler apis and richer protocols.
 - cross-platform (Linux, Windows, Mac, Solaris)
 - event-loop (IO, timer, idle)
 - ENABLE_IPV6
+- ENABLE_UDS (Unix Domain Socket)
 - WITH_OPENSSL
 - http client/server (include https http1/x http2 grpc)
 - http web service, indexof service, api service (support RESTful API)

+ 107 - 60
base/hsocket.c

@@ -1,5 +1,10 @@
 #include "hsocket.h"
 
+static inline int socket_errno_nagative() {
+    int err = socket_errno();
+    return err > 0 ? -err : -1;
+}
+
 const char* socket_strerror(int err) {
 #ifdef OS_WIN
     static char buffer[128];
@@ -7,11 +12,11 @@ const char* socket_strerror(int err) {
     FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
         FORMAT_MESSAGE_IGNORE_INSERTS |
         FORMAT_MESSAGE_MAX_WIDTH_MASK,
-        0, err, 0, buffer, sizeof(buffer), NULL);
+        0, ABS(err), 0, buffer, sizeof(buffer), NULL);
 
     return buffer;
 #else
-    return strerror(err);
+    return strerror(ABS(err));
 #endif
 }
 
@@ -51,29 +56,12 @@ int Resolver(const char* host, sockaddr_u* addr) {
     return 0;
 }
 
-int Bind(int port, const char* host, int type) {
-#ifdef OS_WIN
-    static int s_wsa_initialized = 0;
-    if (s_wsa_initialized == 0) {
-        s_wsa_initialized = 1;
-        WSADATA wsadata;
-        WSAStartup(MAKEWORD(2,2), &wsadata);
-    }
-#endif
-    sockaddr_u localaddr;
-    socklen_t addrlen = sizeof(localaddr);
-    memset(&localaddr, 0, addrlen);
-    int ret = sockaddr_assign(&localaddr, host, port);
-    if (ret != 0) {
-        printf("unknown host: %s\n", host);
-        return ret;
-    }
-
+static int sockaddr_bind(sockaddr_u* localaddr, int type) {
     // socket -> setsockopt -> bind
-    int sockfd = socket(localaddr.sa.sa_family, type, 0);
+    int sockfd = socket(localaddr->sa.sa_family, type, 0);
     if (sockfd < 0) {
         perror("socket");
-        return -socket_errno();
+        return socket_errno_nagative();
     }
 
     // NOTE: SO_REUSEADDR means that you can reuse sockaddr of TIME_WAIT status
@@ -83,7 +71,7 @@ int Bind(int port, const char* host, int type) {
         goto error;
     }
 
-    if (bind(sockfd, &localaddr.sa, sockaddrlen(&localaddr)) < 0) {
+    if (bind(sockfd, &localaddr->sa, sockaddr_len(localaddr)) < 0) {
         perror("bind");
         goto error;
     }
@@ -91,65 +79,48 @@ int Bind(int port, const char* host, int type) {
     return sockfd;
 error:
     closesocket(sockfd);
-    return socket_errno() > 0 ? -socket_errno() : -1;
+    return socket_errno_nagative();
 }
 
-int Listen(int port, const char* host) {
-    int sockfd = Bind(port, host, SOCK_STREAM);
-    if (sockfd < 0) return sockfd;
-    if (listen(sockfd, SOMAXCONN) < 0) {
-        perror("listen");
-        goto error;
-    }
-    return sockfd;
-error:
-    closesocket(sockfd);
-    return socket_errno() > 0 ? -socket_errno() : -1;
-}
-
-int Connect(const char* host, int port, int nonblock) {
-    // Resolver -> socket -> nonblocking -> connect
-    sockaddr_u peeraddr;
-    socklen_t addrlen = sizeof(peeraddr);
-    memset(&peeraddr, 0, addrlen);
-    int ret = sockaddr_assign(&peeraddr, host, port);
-    if (ret != 0) {
-        //printf("unknown host: %s\n", host);
-        return ret;
-    }
-    int connfd = socket(peeraddr.sa.sa_family, SOCK_STREAM, 0);
+static int sockaddr_connect(sockaddr_u* peeraddr, int nonblock) {
+    // socket -> nonblocking -> connect
+    int connfd = socket(peeraddr->sa.sa_family, SOCK_STREAM, 0);
     if (connfd < 0) {
         perror("socket");
         return -socket_errno();
     }
+
     if (nonblock) {
         nonblocking(connfd);
     }
-    ret = connect(connfd, &peeraddr.sa, sockaddrlen(&peeraddr));
+
+    int ret = connect(connfd, &peeraddr->sa, sockaddr_len(peeraddr));
 #ifdef OS_WIN
     if (ret < 0 && socket_errno() != WSAEWOULDBLOCK) {
 #else
     if (ret < 0 && socket_errno() != EINPROGRESS) {
 #endif
         perror("connect");
-        goto error;
+        closesocket(connfd);
+        return socket_errno_nagative();
     }
     return connfd;
-error:
-    closesocket(connfd);
-    return socket_errno() > 0 ? -socket_errno() : -1;
 }
 
-int ConnectNonblock(const char* host, int port) {
-    return Connect(host, port, 1);
+static int ListenFD(int sockfd) {
+    if (sockfd < 0) return sockfd;
+    if (listen(sockfd, SOMAXCONN) < 0) {
+        perror("listen");
+        closesocket(sockfd);
+        return socket_errno_nagative();
+    }
+    return sockfd;
 }
 
-int ConnectTimeout(const char* host, int port, int ms) {
-    int connfd = Connect(host, port, 1);
-    if (connfd < 0) return connfd;
+static int ConnectFDTimeout(int connfd, int ms) {
     int err;
     socklen_t optlen = sizeof(err);
-    struct timeval tv = {ms/1000, (ms%1000)*1000};
+    struct timeval tv = { ms / 1000, (ms % 1000) * 1000 };
     fd_set writefds;
     FD_ZERO(&writefds);
     FD_SET(connfd, &writefds);
@@ -169,9 +140,85 @@ int ConnectTimeout(const char* host, int port, int ms) {
     return connfd;
 error:
     closesocket(connfd);
-    return socket_errno() > 0 ? -socket_errno() : -1;
+    return socket_errno_nagative();
+}
+
+int Bind(int port, const char* host, int type) {
+#ifdef OS_WIN
+    static int s_wsa_initialized = 0;
+    if (s_wsa_initialized == 0) {
+        s_wsa_initialized = 1;
+        WSADATA wsadata;
+        WSAStartup(MAKEWORD(2,2), &wsadata);
+    }
+#endif
+    sockaddr_u localaddr;
+    memset(&localaddr, 0, sizeof(localaddr));
+    int ret = sockaddr_set_ipport(&localaddr, host, port);
+    if (ret != 0) {
+        return ret > 0 ? -ret : ret;
+    }
+    return sockaddr_bind(&localaddr, type);
+}
+
+int Listen(int port, const char* host) {
+    int sockfd = Bind(port, host, SOCK_STREAM);
+    if (sockfd < 0) return sockfd;
+    return ListenFD(sockfd);
+}
+
+int Connect(const char* host, int port, int nonblock) {
+    sockaddr_u peeraddr;
+    memset(&peeraddr, 0, sizeof(peeraddr));
+    int ret = sockaddr_set_ipport(&peeraddr, host, port);
+    if (ret != 0) {
+        return ret > 0 ? -ret : ret;
+    }
+    return sockaddr_connect(&peeraddr, nonblock);
+}
+
+int ConnectNonblock(const char* host, int port) {
+    return Connect(host, port, 1);
+}
+
+int ConnectTimeout(const char* host, int port, int ms) {
+    int connfd = Connect(host, port, 1);
+    if (connfd < 0) return connfd;
+    return ConnectFDTimeout(connfd, ms);
+}
+
+#ifdef ENABLE_UDS
+int BindUnix(const char* path, int type) {
+    sockaddr_u localaddr;
+    memset(&localaddr, 0, sizeof(localaddr));
+    sockaddr_set_path(&localaddr, path);
+    return sockaddr_bind(&localaddr, type);
 }
 
+int ListenUnix(const char* path) {
+    int sockfd = BindUnix(path, SOCK_STREAM);
+    if (sockfd < 0) return sockfd;
+    return ListenFD(sockfd);
+}
+
+int ConnectUnix(const char* path, int nonblock) {
+    sockaddr_u peeraddr;
+    memset(&peeraddr, 0, sizeof(peeraddr));
+    sockaddr_set_path(&peeraddr, path);
+    return sockaddr_connect(&peeraddr, nonblock);
+}
+
+int ConnectUnixNonblock(const char* path) {
+    return ConnectUnix(path, 1);
+}
+
+int ConnectUnixTimeout(const char* path, int ms) {
+    int connfd = ConnectUnix(path, 1);
+    if (connfd < 0) return connfd;
+    return ConnectFDTimeout(connfd, ms);
+}
+#endif
+
 int Socketpair(int family, int type, int protocol, int sv[2]) {
 #ifdef OS_UNIX
     if (family == AF_UNIX) {

+ 61 - 28
base/hsocket.h

@@ -4,6 +4,10 @@
 #include "hplatform.h"
 #include "hdef.h"
 
+#ifdef ENABLE_UDS
+    #include <sys/un.h> // import struct sockaddr_un
+#endif
+
 #ifdef _MSC_VER
 #pragma comment(lib, "ws2_32.lib")
 #endif
@@ -47,26 +51,20 @@ typedef int         SOCKET;
 #define closesocket close
 #endif
 
+//-----------------------------sockaddr_u----------------------------------------------
 typedef union {
     struct sockaddr     sa;
     struct sockaddr_in  sin;
     struct sockaddr_in6 sin6;
+#ifdef ENABLE_UDS
+    struct sockaddr_un  sun;
+#endif
 } sockaddr_u;
 
 // @param host: domain or ip
 // @retval 0:succeed
 int Resolver(const char* host, sockaddr_u* addr);
 
-static inline socklen_t sockaddrlen(sockaddr_u* addr) {
-    if (addr->sa.sa_family == AF_INET) {
-        return sizeof(struct sockaddr_in);
-    }
-    else if (addr->sa.sa_family == AF_INET6) {
-        return sizeof(struct sockaddr_in6);
-    }
-    return sizeof(sockaddr_u);
-}
-
 static inline const char* sockaddr_ip(sockaddr_u* addr, char *ip, int len) {
     if (addr->sa.sa_family == AF_INET) {
         return inet_ntop(AF_INET, &addr->sin.sin_addr, ip, len);
@@ -88,6 +86,15 @@ static inline uint16_t sockaddr_port(sockaddr_u* addr) {
     return port;
 }
 
+static inline int sockaddr_set_ip(sockaddr_u* addr, const char* host) {
+    if (!host || *host == '\0') {
+        addr->sin.sin_family = AF_INET;
+        addr->sin.sin_addr.s_addr = htonl(INADDR_ANY);
+        return 0;
+    }
+    return Resolver(host, addr);
+}
+
 static inline void sockaddr_set_port(sockaddr_u* addr, int port) {
     if (addr->sa.sa_family == AF_INET) {
         addr->sin.sin_port = ntohs(port);
@@ -97,13 +104,39 @@ static inline void sockaddr_set_port(sockaddr_u* addr, int port) {
     }
 }
 
+static inline int sockaddr_set_ipport(sockaddr_u* addr, const char* host, int port) {
+    int ret = sockaddr_set_ip(addr, host);
+    if (ret != 0) return ret;
+    sockaddr_set_port(addr, port);
+    return 0;
+}
+
 //#define INET_ADDRSTRLEN   16
 //#define INET6_ADDRSTRLEN  46
+#ifdef ENABLE_UDS
+#define SOCKADDR_STRLEN     sizeof(((struct sockaddr_un*)(NULL))->sun_path)
+static inline void sockaddr_set_path(sockaddr_u* addr, const char* path) {
+    addr->sa.sa_family = AF_UNIX;
+    strncpy(addr->sun.sun_path, path, sizeof(addr->sun.sun_path));
+}
+#else
 #define SOCKADDR_STRLEN     64 // ipv4:port | [ipv6]:port
-#define SOCKADDR_STR(addr, buf) sockaddr_str((sockaddr_u*)addr, buf, sizeof(buf))
-// NOTE: typeof(addr)=[sockaddr*, sockaddr_in*, sockaddr_in6*, sockaddr_u*]
-// char buf[SOCKADDR_STRLEN] = {0};
-// SOCKADDR_STR(addr, buf);
+#endif
+
+static inline socklen_t sockaddr_len(sockaddr_u* addr) {
+    if (addr->sa.sa_family == AF_INET) {
+        return sizeof(struct sockaddr_in);
+    }
+    else if (addr->sa.sa_family == AF_INET6) {
+        return sizeof(struct sockaddr_in6);
+    }
+#ifdef ENABLE_UDS
+    else if (addr->sa.sa_family == AF_UNIX) {
+        return sizeof(struct sockaddr_un);
+    }
+#endif
+    return sizeof(sockaddr_u);
+}
 
 static inline const char* sockaddr_str(sockaddr_u* addr, char* buf, int len) {
     char ip[SOCKADDR_STRLEN] = {0};
@@ -127,18 +160,10 @@ static inline void sockaddr_print(sockaddr_u* addr) {
     puts(buf);
 }
 
-static inline int sockaddr_assign(sockaddr_u* addr, const char* host, int port) {
-    if (host) {
-        int ret = Resolver(host, addr);
-        if (ret != 0) return ret;
-    }
-    else {
-        addr->sin.sin_family = AF_INET;
-        addr->sin.sin_addr.s_addr = htonl(INADDR_ANY);
-    }
-    sockaddr_set_port(addr, port);
-    return 0;
-}
+#define SOCKADDR_LEN(addr)      sockaddr_len((sockaddr_u*)addr)
+#define SOCKADDR_STR(addr, buf) sockaddr_str((sockaddr_u*)addr, buf, sizeof(buf))
+#define SOCKADDR_PRINT(addr)    sockaddr_print((sockaddr_u*)addr)
+//=====================================================================================
 
 // socket -> setsockopt -> bind
 // @param type: SOCK_STREAM(tcp) SOCK_DGRAM(udp)
@@ -146,10 +171,10 @@ static inline int sockaddr_assign(sockaddr_u* addr, const char* host, int port)
 int Bind(int port, const char* host DEFAULT(ANYADDR), int type DEFAULT(SOCK_STREAM));
 
 // Bind -> listen
-// @return sockfd
+// @return listenfd
 int Listen(int port, const char* host DEFAULT(ANYADDR));
 
-// @return sockfd
+// @return connfd
 // Resolver -> socket -> nonblocking -> connect
 int Connect(const char* host, int port, int nonblock DEFAULT(0));
 // Connect(host, port, 1)
@@ -158,6 +183,14 @@ int ConnectNonblock(const char* host, int port);
 #define DEFAULT_CONNECT_TIMEOUT 5000 // ms
 int ConnectTimeout(const char* host, int port, int ms DEFAULT(DEFAULT_CONNECT_TIMEOUT));
 
+#ifdef ENABLE_UDS
+int BindUnix(const char* path, int type DEFAULT(SOCK_STREAM));
+int ListenUnix(const char* path);
+int ConnectUnix(const char* path, int nonblock DEFAULT(0));
+int ConnectUnixNonblock(const char* path);
+int ConnectUnixTimeout(const char* path, int ms DEFAULT(DEFAULT_CONNECT_TIMEOUT));
+#endif
+
 // Just implement Socketpair(AF_INET, SOCK_STREAM, 0, sv);
 int Socketpair(int family, int type, int protocol, int sv[2]);
 

+ 2 - 0
config.mk

@@ -12,6 +12,8 @@ WITH_CONSUL=no
 # features
 # base/hsocket.c: replace gethostbyname with getaddrinfo
 ENABLE_IPV6=no
+# base/hsocket.h: Unix Domain Socket
+ENABLE_UDS=no
 # base/RAII.cpp: Windows MiniDumpWriteDump
 ENABLE_WINDUMP=no
 # http/http_content.h: QueryParams,MultiPart

+ 9 - 9
configure

@@ -60,7 +60,7 @@ macro=HAVE_$(echo $header | tr a-z./ A-Z__)
 write_define
 }
 
-check_funtion() {
+check_function() {
 echo -n "checking for $function... "
 rm tmp/check 2>/dev/null
 cat << END > tmp/check.c
@@ -118,14 +118,14 @@ header=fcntl.h && check_header
 header=pthread.h && check_header
 
 # Checks for functions
-function=gettid && header=unistd.h && check_funtion
-function=strlcpy && header=string.h && check_funtion
-function=strlcat && header=string.h && check_funtion
-function=clock_gettime && header=time.h && check_funtion
-function=gettimeofday && header=sys/time.h && check_funtion
-function=pthread_spin_lock && header=pthread.h && check_funtion
-function=pthread_mutex_timedlock && header=pthread.h && check_funtion
-function=sem_timedwait && header=semaphore.h && check_funtion
+function=gettid && header=unistd.h && check_function
+function=strlcpy && header=string.h && check_function
+function=strlcat && header=string.h && check_function
+function=clock_gettime && header=time.h && check_function
+function=gettimeofday && header=sys/time.h && check_function
+function=pthread_spin_lock && header=pthread.h && check_function
+function=pthread_mutex_timedlock && header=pthread.h && check_function
+function=sem_timedwait && header=semaphore.h && check_function
 
 # end confile
 cat << END >> $confile

+ 6 - 8
event/hloop.c

@@ -696,9 +696,8 @@ hio_t* create_tcp_server (hloop_t* loop, const char* host, int port, haccept_cb
 
 hio_t* create_tcp_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb) {
     sockaddr_u peeraddr;
-    socklen_t addrlen = sizeof(peeraddr);
-    memset(&peeraddr, 0, addrlen);
-    int ret = sockaddr_assign(&peeraddr, host, port);
+    memset(&peeraddr, 0, sizeof(peeraddr));
+    int ret = sockaddr_set_ipport(&peeraddr, host, port);
     if (ret != 0) {
         //printf("unknown host: %s\n", host);
         return NULL;
@@ -711,7 +710,7 @@ hio_t* create_tcp_client (hloop_t* loop, const char* host, int port, hconnect_cb
 
     hio_t* io = hio_get(loop, connfd);
     if (io == NULL) return NULL;
-    hio_set_peeraddr(io, &peeraddr.sa, sockaddrlen(&peeraddr));
+    hio_set_peeraddr(io, &peeraddr.sa, sockaddr_len(&peeraddr));
     hconnect(loop, connfd, connect_cb);
     return io;
 }
@@ -728,9 +727,8 @@ hio_t* create_udp_server(hloop_t* loop, const char* host, int port) {
 // @client: Resolver -> socket -> hio_get -> hio_set_peeraddr
 hio_t* create_udp_client(hloop_t* loop, const char* host, int port) {
     sockaddr_u peeraddr;
-    socklen_t addrlen = sizeof(peeraddr);
-    memset(&peeraddr, 0, addrlen);
-    int ret = sockaddr_assign(&peeraddr, host, port);
+    memset(&peeraddr, 0, sizeof(peeraddr));
+    int ret = sockaddr_set_ipport(&peeraddr, host, port);
     if (ret != 0) {
         //printf("unknown host: %s\n", host);
         return NULL;
@@ -744,7 +742,7 @@ hio_t* create_udp_client(hloop_t* loop, const char* host, int port) {
 
     hio_t* io = hio_get(loop, sockfd);
     if (io == NULL) return NULL;
-    hio_set_peeraddr(io, &peeraddr.sa, sockaddrlen(&peeraddr));
+    hio_set_peeraddr(io, &peeraddr.sa, sockaddr_len(&peeraddr));
     return io;
 }
 

+ 2 - 2
event/nio.c

@@ -324,7 +324,7 @@ static void connect_timeout_cb(htimer_t* timer) {
 }
 
 int hio_connect(hio_t* io) {
-    int ret = connect(io->fd, io->peeraddr, sizeof(sockaddr_u));
+    int ret = connect(io->fd, io->peeraddr, SOCKADDR_LEN(io->peeraddr));
 #ifdef OS_WIN
     if (ret < 0 && socket_errno() != WSAEWOULDBLOCK) {
 #else
@@ -370,7 +370,7 @@ try_write:
             break;
         case HIO_TYPE_UDP:
         case HIO_TYPE_IP:
-            nwrite = sendto(io->fd, buf, len, 0, io->peeraddr, sizeof(sockaddr_u));
+            nwrite = sendto(io->fd, buf, len, 0, io->peeraddr, SOCKADDR_LEN(io->peeraddr));
             break;
         default:
             nwrite = write(io->fd, buf, len);

+ 1 - 1
protocol/icmp.c

@@ -68,7 +68,7 @@ int ping(const char* host, int cnt) {
         icmp_req->icmp_cksum = 0;
         icmp_req->icmp_cksum = checksum((uint8_t*)icmp_req, sendbytes);
         start_hrtime = gethrtime_us();
-        addrlen = sockaddrlen(&peeraddr);
+        addrlen = sockaddr_len(&peeraddr);
         int nsend = sendto(sockfd, sendbuf, sendbytes, 0, &peeraddr.sa, addrlen);
         if (nsend < 0) {
             perror("sendto");

+ 1 - 0
readme_cn.md

@@ -10,6 +10,7 @@
 - cross-platform (Linux, Windows, Mac)
 - event-loop (IO, timer, idle)
 - ENABLE_IPV6
+- ENABLE_UDS (Unix Domain Socket)
 - WITH_OPENSSL
 - http client/server (include https http1/x http2 grpc)
 - http web service, indexof service, api service (support RESTful API)