Просмотр исходного кода

Remove seqsocket socket type. Unix socket of type SOCK_SEQPACKET are broken (Linux) because they do not support the MSG_EOR flag.
Instead use SOCK_DGRAM unix sockets for IPC, which are (hopefully) reliable and preserve message boundaries across send()/recv().
Also some minor refactoring in BSocket.

ambrop7 15 лет назад
Родитель
Сommit
3ffeaefbba
5 измененных файлов с 81 добавлено и 198 удалено
  1. 9 2
      flow/CMakeLists.txt
  2. 1 1
      ipc/BIPC.c
  3. 1 1
      ipc/BIPCServer.c
  4. 60 152
      system/BSocket.c
  5. 10 42
      system/BSocket.h

+ 9 - 2
flow/CMakeLists.txt

@@ -1,3 +1,11 @@
+set(FLOW_ADDITIONAL_SOURCES)
+if (NOT WIN32)
+    list(APPEND FLOW_ADDITIONAL_SOURCES
+        SeqPacketSocketSink.c
+        SeqPacketSocketSource.c
+    )
+endif ()
+
 add_library(flow
     PacketPassFairQueue.c
     PacketPassPriorityQueue.c
@@ -27,7 +35,6 @@ add_library(flow
     DataProtoKeepaliveSource.c
     PacketProtoFlow.c
     SinglePacketSender.c
-    SeqPacketSocketSink.c
-    SeqPacketSocketSource.c
+    ${FLOW_ADDITIONAL_SOURCES}
 )
 target_link_libraries(flow system security)

+ 1 - 1
ipc/BIPC.c

@@ -55,7 +55,7 @@ int BIPC_InitConnect (BIPC *o, const char *path, int send_mtu, int recv_mtu, BIP
     DEAD_INIT(o->dead);
     
     // init socket
-    if (BSocket_Init(&o->sock, reactor, BADDR_TYPE_UNIX, BSOCKET_TYPE_SEQPACKET) < 0) {
+    if (BSocket_Init(&o->sock, reactor, BADDR_TYPE_UNIX, BSOCKET_TYPE_DGRAM) < 0) {
         DEBUG("BSocket_Init failed");
         goto fail0;
     }

+ 1 - 1
ipc/BIPCServer.c

@@ -40,7 +40,7 @@ int BIPCServer_Init (BIPCServer *o, const char *path, BIPCServer_handler handler
     DEAD_INIT(o->dead);
     
     // init socket
-    if (BSocket_Init(&o->sock, reactor, BADDR_TYPE_UNIX, BSOCKET_TYPE_SEQPACKET) < 0) {
+    if (BSocket_Init(&o->sock, reactor, BADDR_TYPE_UNIX, BSOCKET_TYPE_DGRAM) < 0) {
         DEBUG("BSocket_Init failed");
         goto fail0;
     }

+ 60 - 152
system/BSocket.c

@@ -20,10 +20,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifdef BADVPN_USE_WINAPI
-#include <winsock2.h>
-#include <misc/mswsock.h>
-#else
+#ifndef BADVPN_USE_WINAPI
 #define _GNU_SOURCE
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -454,27 +451,47 @@ static int limit_recv (BSocket *bs)
     return 0;
 }
 
-static void setup_pktinfo (BSocket *bs)
+static int setup_pktinfo (int socket, int type, int domain)
 {
-    int have_pktinfo = 0;
-    if (bs->type == BSOCKET_TYPE_DGRAM) {
-        int need = 1;
-        switch (bs->domain) {
+    if (type == BSOCKET_TYPE_DGRAM) {
+        switch (domain) {
             case BADDR_TYPE_IPV4:
-                have_pktinfo = (set_pktinfo(bs->socket) == 0);
+                if (set_pktinfo(socket) == 0) {
+                    return 0;
+                }
                 break;
             case BADDR_TYPE_IPV6:
-                have_pktinfo = (set_pktinfo6(bs->socket) == 0);
+                if (set_pktinfo6(socket) == 0) {
+                    return 0;
+                }
                 break;
-            default:
-                need = 0;
-        }
-        if (need && !have_pktinfo) {
-            DEBUG("WARNING: no pktinfo");
         }
     }
     
-    bs->have_pktinfo = have_pktinfo;
+    return 1;
+}
+
+static int setup_winsock_exts (int socket, BSocket *bs)
+{
+    #ifdef BADVPN_USE_WINAPI
+    
+    DWORD out_bytes;
+    
+    // obtain WSASendMsg
+    GUID guid_send = WSAID_WSASENDMSG;
+    if (WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid_send, sizeof(guid_send), &bs->WSASendMsg, sizeof(bs->WSASendMsg), &out_bytes, NULL, NULL) != 0) {
+        return 0;
+    }
+    
+    // obtain WSARecvMsg
+    GUID guid_recv = WSAID_WSARECVMSG;
+    if (WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid_recv, sizeof(guid_recv), &bs->WSARecvMsg, sizeof(bs->WSARecvMsg), &out_bytes, NULL, NULL) != 0) {
+        return 0;
+    }
+    
+    #endif
+    
+    return 1;
 }
 
 int BSocket_GlobalInit (void)
@@ -534,9 +551,6 @@ int BSocket_Init (BSocket *bs, BReactor *bsys, int domain, int type)
         case BSOCKET_TYPE_DGRAM:
             sys_type = SOCK_DGRAM;
             break;
-        case BSOCKET_TYPE_SEQPACKET:
-            sys_type = SOCK_SEQPACKET;
-            break;
         default:
             ASSERT(0)
             return -1;
@@ -555,13 +569,23 @@ int BSocket_Init (BSocket *bs, BReactor *bsys, int domain, int type)
         goto fail1;
     }
     
-    // initialize variables
+    // set pktinfo if needed
+    if (!setup_pktinfo(fd, type, domain)) {
+        DEBUG("setup_pktinfo failed");
+        goto fail1;
+    }
+    
+    // setup winsock exts
+    if (!setup_winsock_exts(fd, bs)) {
+        DEBUG("setup_winsock_exts failed");
+        goto fail1;
+    }
+    
     DEAD_INIT(bs->dead);
     bs->bsys = bsys;
     bs->type = type;
     bs->domain = domain;
     bs->socket = fd;
-    setup_pktinfo(bs);
     bs->error = BSOCKET_ERROR_NONE;
     init_handlers(bs);
     bs->waitEvents = 0;
@@ -874,12 +898,23 @@ int BSocket_Accept (BSocket *bs, BSocket *newsock, BAddr *addr)
             goto fail0;
         }
         
+        // set pktinfo if needed
+        if (!setup_pktinfo(fd, bs->type, bs->domain)) {
+            DEBUG("setup_pktinfo failed");
+            goto fail0;
+        }
+        
+        // setup winsock exts
+        if (!setup_winsock_exts(fd, newsock)) {
+            DEBUG("setup_winsock_exts failed");
+            goto fail0;
+        }
+        
         DEAD_INIT(newsock->dead);
         newsock->bsys = bs->bsys;
         newsock->type = bs->type;
         newsock->domain = bs->domain;
         newsock->socket = fd;
-        setup_pktinfo(newsock);
         newsock->error = BSOCKET_ERROR_NONE;
         init_handlers(newsock);
         newsock->waitEvents = 0;
@@ -985,92 +1020,6 @@ int BSocket_Recv (BSocket *bs, uint8_t *data, int len)
     return bytes;
 }
 
-int BSocket_SendTo (BSocket *bs, uint8_t *data, int len, BAddr *addr)
-{
-    ASSERT(len >= 0)
-    ASSERT(addr)
-    ASSERT(!BAddr_IsInvalid(addr))
-    
-    struct sys_addr remote_sysaddr;
-    addr_socket_to_sys(&remote_sysaddr, addr);
-    
-    #ifdef BADVPN_USE_WINAPI
-    int flags = 0;
-    #else
-    int flags = MSG_NOSIGNAL;
-    #endif
-    
-    int bytes = sendto(bs->socket, data, len, flags, &remote_sysaddr.addr.generic, remote_sysaddr.len);
-    if (bytes < 0) {
-        int error;
-        #ifdef BADVPN_USE_WINAPI
-        switch ((error = WSAGetLastError())) {
-            case WSAEWOULDBLOCK:
-                bs->error = BSOCKET_ERROR_LATER;
-                return -1;
-        }
-        #else
-        switch ((error = errno)) {
-            case EAGAIN:
-            #if EAGAIN != EWOULDBLOCK
-            case EWOULDBLOCK:
-            #endif
-                bs->error = BSOCKET_ERROR_LATER;
-                return -1;
-        }
-        #endif
-        
-        bs->error = translate_error(error);
-        return -1;
-    }
-
-    bs->error = BSOCKET_ERROR_NONE;
-    return bytes;
-}
-
-int BSocket_RecvFrom (BSocket *bs, uint8_t *data, int len, BAddr *addr)
-{
-    ASSERT(len >= 0)
-    ASSERT(addr)
-    
-    if (limit_recv(bs)) {
-        bs->error = BSOCKET_ERROR_LATER;
-        return -1;
-    }
-    
-    struct sys_addr remote_sysaddr;
-    remote_sysaddr.len = sizeof(remote_sysaddr.addr);
-    
-    int bytes = recvfrom(bs->socket, data, len, 0, &remote_sysaddr.addr.generic, &remote_sysaddr.len);
-    if (bytes < 0) {
-        int error;
-        #ifdef BADVPN_USE_WINAPI
-        switch ((error = WSAGetLastError())) {
-            case WSAEWOULDBLOCK:
-                bs->error = BSOCKET_ERROR_LATER;
-                return -1;
-        }
-        #else
-        switch ((error = errno)) {
-            case EAGAIN:
-            #if EAGAIN != EWOULDBLOCK
-            case EWOULDBLOCK:
-            #endif
-                bs->error = BSOCKET_ERROR_LATER;
-                return -1;
-        }
-        #endif
-        
-        bs->error = translate_error(error);
-        return -1;
-    }
-    
-    addr_sys_to_socket(addr, &remote_sysaddr);
-    
-    bs->error = BSOCKET_ERROR_NONE;
-    return bytes;
-}
-
 int BSocket_SendToFrom (BSocket *bs, uint8_t *data, int len, BAddr *addr, BIPAddr *local_addr)
 {
     ASSERT(len >= 0)
@@ -1078,22 +1027,6 @@ int BSocket_SendToFrom (BSocket *bs, uint8_t *data, int len, BAddr *addr, BIPAdd
     ASSERT(!BAddr_IsInvalid(addr))
     ASSERT(local_addr)
     
-    if (!bs->have_pktinfo) {
-        return BSocket_SendTo(bs, data, len, addr);
-    }
-    
-    #ifdef BADVPN_USE_WINAPI
-    
-    // obtain WSASendMsg
-    GUID guid = WSAID_WSASENDMSG;
-    LPFN_WSASENDMSG WSASendMsg;
-    DWORD out_bytes;
-    if (WSAIoctl(bs->socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &WSASendMsg, sizeof(WSASendMsg), &out_bytes, NULL, NULL) != 0) {
-        return BSocket_SendTo(bs, data, len, addr);
-    }
-    
-    #endif
-    
     struct sys_addr remote_sysaddr;
     addr_socket_to_sys(&remote_sysaddr, addr);
     
@@ -1149,7 +1082,7 @@ int BSocket_SendToFrom (BSocket *bs, uint8_t *data, int len, BAddr *addr, BIPAdd
     msg.Control.len = sum;
     
     DWORD bytes;
-    if (WSASendMsg(bs->socket, &msg, 0, &bytes, NULL, NULL) != 0) {
+    if (bs->WSASendMsg(bs->socket, &msg, 0, &bytes, NULL, NULL) != 0) {
         int error;
         switch ((error = WSAGetLastError())) {
             case WSAEWOULDBLOCK:
@@ -1234,37 +1167,12 @@ int BSocket_SendToFrom (BSocket *bs, uint8_t *data, int len, BAddr *addr, BIPAdd
     return bytes;
 }
 
-static int recvfromto_fallback (BSocket *bs, uint8_t *data, int len, BAddr *addr, BIPAddr *local_addr)
-{
-    int res = BSocket_RecvFrom(bs, data, len, addr);
-    if (res >= 0) {
-        BIPAddr_InitInvalid(local_addr);
-    }
-    return res;
-}
-
 int BSocket_RecvFromTo (BSocket *bs, uint8_t *data, int len, BAddr *addr, BIPAddr *local_addr)
 {
     ASSERT(len >= 0)
     ASSERT(addr)
     ASSERT(local_addr)
     
-    if (!bs->have_pktinfo) {
-        return recvfromto_fallback(bs, data, len, addr, local_addr);
-    }
-    
-    #ifdef BADVPN_USE_WINAPI
-    
-    // obtain WSARecvMsg
-    GUID guid = WSAID_WSARECVMSG;
-    LPFN_WSARECVMSG WSARecvMsg;
-    DWORD out_bytes;
-    if (WSAIoctl(bs->socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &WSARecvMsg, sizeof(WSARecvMsg), &out_bytes, NULL, NULL) != 0) {
-        return recvfromto_fallback(bs, data, len, addr, local_addr);
-    }
-    
-    #endif
-    
     if (limit_recv(bs)) {
         bs->error = BSOCKET_ERROR_LATER;
         return -1;
@@ -1294,7 +1202,7 @@ int BSocket_RecvFromTo (BSocket *bs, uint8_t *data, int len, BAddr *addr, BIPAdd
     msg.Control.len = sizeof(cdata);
     
     DWORD bytes;
-    if (WSARecvMsg(bs->socket, &msg, &bytes, NULL, NULL) != 0) {
+    if (bs->WSARecvMsg(bs->socket, &msg, &bytes, NULL, NULL) != 0) {
         int error;
         switch ((error = WSAGetLastError())) {
             case WSAEWOULDBLOCK:

+ 10 - 42
system/BSocket.h

@@ -28,6 +28,11 @@
 #ifndef BADVPN_SYSTEM_BSOCKET_H
 #define BADVPN_SYSTEM_BSOCKET_H
 
+#ifdef BADVPN_USE_WINAPI
+#include <winsock2.h>
+#include <misc/mswsock.h>
+#endif
+
 #include <misc/dead.h>
 #include <misc/debug.h>
 #include <system/BAddr.h>
@@ -51,7 +56,6 @@
 // socket types
 #define BSOCKET_TYPE_STREAM 1
 #define BSOCKET_TYPE_DGRAM 2
-#define BSOCKET_TYPE_SEQPACKET 3
 
 // socket events
 #define BSOCKET_READ 1
@@ -84,7 +88,6 @@ typedef struct BSocket_t {
     int type;
     int domain;
     int socket;
-    int have_pktinfo;
     int error;
     BSocket_handler global_handler;
     void *global_handler_user;
@@ -99,6 +102,8 @@ typedef struct BSocket_t {
     #ifdef BADVPN_USE_WINAPI
     WSAEVENT event;
     BHandle bhandle;
+    LPFN_WSASENDMSG WSASendMsg;
+    LPFN_WSARECVMSG WSARecvMsg;
     #else
     BFileDescriptor fd;
     #endif
@@ -119,8 +124,7 @@ int BSocket_GlobalInit (void) WARN_UNUSED;
  * @param bsys {@link BReactor} to operate in
  * @param domain domain (same as address type). Must be one of BADDR_TYPE_IPV4, BADDR_TYPE_IPV6
  *               and BADDR_TYPE_UNIX (non-Windows only).
- * @param type socket type. Must be one of BSOCKET_TYPE_STREAM, BSOCKET_TYPE_DGRAM and
- *             BSOCKET_TYPE_SEQPACKET.
+ * @param type socket type. Must be one of BSOCKET_TYPE_STREAM and BSOCKET_TYPE_DGRAM.
  * @return 0 for success,
  *         -1 for failure
  */
@@ -304,7 +308,7 @@ int BSocket_Listen (BSocket *bs, int backlog) WARN_UNUSED;
 int BSocket_Accept (BSocket *bs, BSocket *newsock, BAddr *addr) WARN_UNUSED;
 
 /**
- * Sends data on a socket.
+ * Sends data on a stream socket.
  *
  * @param bs the object
  * @param data buffer to read data from
@@ -320,7 +324,7 @@ int BSocket_Accept (BSocket *bs, BSocket *newsock, BAddr *addr) WARN_UNUSED;
 int BSocket_Send (BSocket *bs, uint8_t *data, int len) WARN_UNUSED;
 
 /**
- * Receives data on a socket.
+ * Receives data on a stream socket.
  *
  * @param bs the object
  * @param data buffer to write data to
@@ -336,42 +340,6 @@ int BSocket_Send (BSocket *bs, uint8_t *data, int len) WARN_UNUSED;
  */
 int BSocket_Recv (BSocket *bs, uint8_t *data, int len) WARN_UNUSED;
 
-/**
- * Sends a datagram on a datagram socket to the specified address.
- *
- * @param bs the object
- * @param data buffer to read data from
- * @param len amount of data. Must be >=0.
- * @param addr remote address. Must be valid.
- * @return non-negative value for amount of data sent,
- *         -1 for failure, where the error code can be:
- *             - BSOCKET_ERROR_LATER no data can be sent at the moment
- *             - BSOCKET_ERROR_CONNECTION_REFUSED the remote host refused to allow the network connection.
- *                   For UDP sockets, this means the remote sent an ICMP Port Unreachable packet.
- *             - BSOCKET_ERROR_CONNECTION_RESET connection was reset by the remote peer
- *             - BSOCKET_ERROR_UNKNOWN unhandled error
- */
-int BSocket_SendTo (BSocket *bs, uint8_t *data, int len, BAddr *addr) WARN_UNUSED;
-
-/**
- * Receives a datagram on a datagram socket and returns the sender address.
- *
- * @param bs the object
- * @param data buffer to write data to
- * @param len maximum amount of data to read. Must be >=0.
- * @param addr the sender address will be stored here on success. Must not be NULL.
- *             The returned address may be an invalid address.
- * @return - non-negative value for amount of data read; on stream sockets the value 0
- *           means that the peer has shutdown the connection gracefully
- *         - -1 for failure, where the error code can be:
- *             - BSOCKET_ERROR_LATER no data can be read at the moment
- *             - BSOCKET_ERROR_CONNECTION_REFUSED a remote host refused to allow the network connection.
- *                   For UDP sockets, this means the remote sent an ICMP Port Unreachable packet.
- *             - BSOCKET_ERROR_CONNECTION_RESET connection was reset by the remote peer
- *             - BSOCKET_ERROR_UNKNOWN unhandled error
- */
-int BSocket_RecvFrom (BSocket *bs, uint8_t *data, int len, BAddr *addr) WARN_UNUSED;
-
 /**
  * Sends a datagram on a datagram socket to the specified address
  * from the specified local source address.