[haiku-commits] r36192 - in haiku/trunk: headers/private/net src/add-ons/kernel/network/protocols/ipv4 src/add-ons/kernel/network/protocols/l2cap src/add-ons/kernel/network/protocols/tcp src/add-ons/kernel/network/protocols/udp ...

  • From: zooey@xxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 12 Apr 2010 20:39:34 +0200 (CEST)

Author: zooey
Date: 2010-04-12 20:39:34 +0200 (Mon, 12 Apr 2010)
New Revision: 36192
Changeset: http://dev.haiku-os.org/changeset/36192/haiku
Ticket: http://dev.haiku-os.org/ticket/5716

Added:
   haiku/trunk/src/tests/kits/net/ipv46_client.cpp
   haiku/trunk/src/tests/kits/net/ipv46_server.cpp
Modified:
   haiku/trunk/headers/private/net/net_datalink.h
   haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp
   haiku/trunk/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp
   haiku/trunk/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp
   haiku/trunk/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
   haiku/trunk/src/add-ons/kernel/network/protocols/udp/udp.cpp
   haiku/trunk/src/add-ons/kernel/network/protocols/unix/UnixAddress.cpp
   haiku/trunk/src/tests/kits/net/Jamfile
Log:
Applying patch by Atis Elsts:
* fix connecting to INADDR_ANY work for tcp (effectively will
  connect to INADDR_LOOPBACK)
* add same behaviour to udp
* move some ipv4-specific code out of tcp into ipv4 address module
* bind() and connect() now reject addresses from non-matching 
  families
* myself: minor cleanup in udp.cpp with respect to 80 chars limit
Closes #5716 - many thanks!


Modified: haiku/trunk/headers/private/net/net_datalink.h
===================================================================
--- haiku/trunk/headers/private/net/net_datalink.h      2010-04-12 18:21:59 UTC 
(rev 36191)
+++ haiku/trunk/headers/private/net/net_datalink.h      2010-04-12 18:39:34 UTC 
(rev 36192)
@@ -113,6 +113,7 @@
        bool (*equal_masked_addresses)(const sockaddr *a, const sockaddr *b, 
                                        const sockaddr *mask);
        bool (*is_empty_address)(const sockaddr *address, bool checkPort);
+       bool (*is_same_family)(const sockaddr *address);
 
        int32 (*first_mask_bit)(const sockaddr *mask);
 
@@ -142,6 +143,8 @@
 
        bool (*matches_broadcast_address)(const sockaddr *address, 
                                        const sockaddr *mask, const sockaddr 
*broadcastAddr);
+
+       void (*get_loopback_address)(sockaddr *result);
 };
 
 #endif // NET_DATALINK_H

Modified: haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp      
2010-04-12 18:21:59 UTC (rev 36191)
+++ haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp      
2010-04-12 18:39:34 UTC (rev 36192)
@@ -107,7 +107,19 @@
                && (!checkPort || ((sockaddr_in *)address)->sin_port == 0);
 }
 
+/*!    Checks if the given \a address is an IPv4 address.
+       \return false if \a address is NULL, or with family different from 
AF_INET
+               true if it has AF_INET address family
+*/
+static bool
+ipv4_is_same_family(const sockaddr *address)
+{
+       if (address == NULL)
+               return false;
 
+       return address->sa_family == AF_INET;
+}
+
 /*!    Compares the IP-addresses of the two given address structures \a a and 
\a b.
        \return true if IP-addresses of \a a and \a b are equal, false if not
 */
@@ -477,7 +489,17 @@
        return B_OK;
 }
 
+static void
+ipv4_get_loopback_address(sockaddr *result)
+{
+       sockaddr_in *resultIn = (sockaddr_in *)result;
+       memset(resultIn, 0, sizeof(resultIn));
+       resultIn->sin_len = sizeof(sockaddr_in);
+       resultIn->sin_family = AF_INET;
+       resultIn->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+}
 
+
 net_address_module_info gIPv4AddressModule = {
        {
                NULL,
@@ -491,6 +513,7 @@
        ipv4_equal_addresses_and_ports,
        ipv4_equal_masked_addresses,
        ipv4_is_empty_address,
+       ipv4_is_same_family,
        ipv4_first_mask_bit,
        ipv4_check_mask,
        ipv4_print_address,
@@ -503,5 +526,6 @@
        ipv4_update_to,
        ipv4_hash_address_pair,
        ipv4_checksum_address,
-       NULL // ipv4_matches_broadcast_address,
+       NULL, // ipv4_matches_broadcast_address,
+       ipv4_get_loopback_address
 };

Modified: 
haiku/trunk/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp    
2010-04-12 18:21:59 UTC (rev 36191)
+++ haiku/trunk/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp    
2010-04-12 18:39:34 UTC (rev 36192)
@@ -100,6 +100,18 @@
                && (!checkPort || ((sockaddr_l2cap *)address)->l2cap_psm == 0) 
);
 }
 
+/*!    Checks if the given \a address is L2CAP address.
+       \return false if \a address is NULL, or with family different from 
AF_BLUETOOTH
+               true if it has AF_BLUETOOTH address family
+*/
+static bool
+l2cap_is_same_family(const sockaddr *address)
+{
+       if (address == NULL)
+               return false;
+ 
+       return address->sa_family == AF_BLUETOOTH;
+}
 
 /*!
        Compares the IP-addresses of the two given address structures \a a and 
\a b.
@@ -401,6 +413,7 @@
        l2cap_equal_addresses_and_ports,
        l2cap_equal_masked_addresses,
        l2cap_is_empty_address,
+       l2cap_is_same_family,
        l2cap_first_mask_bit,
        l2cap_check_mask,
        l2cap_print_address,
@@ -413,5 +426,6 @@
        l2cap_update_to,
        l2cap_hash_address_pair,
        l2cap_checksum_address,
-       NULL // l2cap_matches_broadcast_address,
+       NULL,   // l2cap_matches_broadcast_address,
+       NULL    // get_loopback_address
 };

Modified: 
haiku/trunk/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp    
2010-04-12 18:21:59 UTC (rev 36191)
+++ haiku/trunk/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp    
2010-04-12 18:39:34 UTC (rev 36192)
@@ -362,9 +362,9 @@
 status_t
 EndpointManager::Bind(TCPEndpoint* endpoint, const sockaddr* address)
 {
-       // TODO: check the family:
-       // if (!AddressModule()->is_understandable(address))
-       //      return EAFNOSUPPORT;
+       // check the family
+       if (!AddressModule()->is_same_family(address))
+               return EAFNOSUPPORT;
 
        WriteLocker locker(fLock);
 

Modified: haiku/trunk/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp        
2010-04-12 18:21:59 UTC (rev 36191)
+++ haiku/trunk/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp        
2010-04-12 18:39:34 UTC (rev 36192)
@@ -584,6 +584,9 @@
 {
        TRACE("Connect() on address %s", PrintAddress(address));
 
+       if (!AddressModule()->is_same_family(address))
+               return EAFNOSUPPORT;
+
        MutexLocker locker(fLock);
 
        if (gStackModule->is_restarted_syscall()) {
@@ -604,14 +607,13 @@
        } else if (fState != CLOSED)
                return EINPROGRESS;
 
-       // TODO: this is IPv4 specific, and doesn't belong here!
        // consider destination address INADDR_ANY as INADDR_LOOPBACK
-       sockaddr_in _address;
-       if (((sockaddr_in*)address)->sin_addr.s_addr == INADDR_ANY) {
-               memcpy(&_address, address, sizeof(sockaddr_in));
-               _address.sin_len = sizeof(sockaddr_in);
-               _address.sin_addr.s_addr = INADDR_LOOPBACK;
-               address = (sockaddr*)&_address;
+       sockaddr_storage _address;
+       if (AddressModule()->is_empty_address(address, false)) {
+               AddressModule()->get_loopback_address((sockaddr *)&_address);
+               // for IPv4 and IPv6 the port is at the same offset
+               ((sockaddr_in &)_address).sin_port = ((sockaddr_in 
*)address)->sin_port;
+               address = (sockaddr *)&_address;
        }
 
        status_t status = _PrepareSendPath(address);

Modified: haiku/trunk/src/add-ons/kernel/network/protocols/udp/udp.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/network/protocols/udp/udp.cpp        
2010-04-12 18:21:59 UTC (rev 36191)
+++ haiku/trunk/src/add-ons/kernel/network/protocols/udp/udp.cpp        
2010-04-12 18:39:34 UTC (rev 36192)
@@ -81,7 +81,8 @@
        status_t                                Close();
        status_t                                Free();
 
-       status_t                                SendRoutedData(net_buffer 
*buffer, net_route *route);
+       status_t                                SendRoutedData(net_buffer 
*buffer,
+                                                               net_route 
*route);
        status_t                                SendData(net_buffer *buffer);
 
        ssize_t                                 BytesAvailable();
@@ -101,8 +102,9 @@
 private:
        UdpDomainSupport                *fManager;
        bool                                    fActive;
-                                                               // an active 
UdpEndpoint is part of the endpoint
-                                                               // hash (and it 
is bound and optionally connected)
+                                                               // an active 
UdpEndpoint is part of the
+                                                               // endpoint 
hash (and it is bound and optionally
+                                                               // connected)
 
        UdpEndpoint                             *fLink;
 };
@@ -127,12 +129,13 @@
 
        size_t Hash(UdpEndpoint *endpoint) const
        {
-               return 
_Mix(endpoint->LocalAddress().HashPair(*endpoint->PeerAddress()));
+               return _Mix(endpoint->LocalAddress().HashPair(
+                       *endpoint->PeerAddress()));
        }
 
        static size_t _Mix(size_t hash)
        {
-               // move the bits into the relevant range (as defined by 
kNumHashBuckets):
+               // move the bits into the relevant range (as defined by 
kNumHashBuckets)
                return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
                        ^ (hash & 0xFFC00000UL) >> 22;
        }
@@ -287,6 +290,9 @@
 UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
        const sockaddr *address)
 {
+       if (!AddressModule()->is_same_family(address))
+               return EAFNOSUPPORT;
+
        MutexLocker _(fLock);
 
        if (endpoint->IsActive())
@@ -312,6 +318,19 @@
                // so we reset the peer address:
                endpoint->PeerAddress().SetToEmpty();
        } else {
+               if (!AddressModule()->is_same_family(address))
+                       return EAFNOSUPPORT;
+
+               // consider destination address INADDR_ANY as INADDR_LOOPBACK
+               sockaddr_storage _address;
+               if (AddressModule()->is_empty_address(address, false)) {
+                       AddressModule()->get_loopback_address((sockaddr 
*)&_address);
+                       // for IPv4 and IPv6 the port is at the same offset
+                       ((sockaddr_in&)_address).sin_port
+                               = ((sockaddr_in *)address)->sin_port;
+                       address = (sockaddr *)&_address;
+               }
+
                status_t status = endpoint->PeerAddress().SetTo(address);
                if (status < B_OK)
                        return status;
@@ -398,7 +417,8 @@
 
                if (otherEndpoint->LocalAddress().EqualPorts(address)) {
                        // port is already bound, SO_REUSEADDR or SO_REUSEPORT 
is required:
-                       if ((otherEndpoint->Socket()->options & (SO_REUSEADDR | 
SO_REUSEPORT)) == 0
+                       if ((otherEndpoint->Socket()->options
+                                       & (SO_REUSEADDR | SO_REUSEPORT)) == 0
                                || (socketOptions & (SO_REUSEADDR | 
SO_REUSEPORT)) == 0)
                                return EADDRINUSE;
 

Modified: haiku/trunk/src/add-ons/kernel/network/protocols/unix/UnixAddress.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/network/protocols/unix/UnixAddress.cpp       
2010-04-12 18:21:59 UTC (rev 36191)
+++ haiku/trunk/src/add-ons/kernel/network/protocols/unix/UnixAddress.cpp       
2010-04-12 18:39:34 UTC (rev 36192)
@@ -112,6 +112,14 @@
                && memcmp(address, &kEmptyAddress, kEmptyAddress.sun_len) == 0;
 }
 
+static bool
+unix_is_same_family(const sockaddr *address)
+{
+       if (address == NULL)
+               return false;
+ 
+       return address->sa_family == AF_UNIX;
+}
 
 static int32
 unix_first_mask_bit(const sockaddr *mask)
@@ -290,6 +298,7 @@
        unix_equal_addresses_and_ports,
        unix_equal_masked_addresses,
        unix_is_empty_address,
+       unix_is_same_family,
        unix_first_mask_bit,
        unix_check_mask,
        unix_print_address,
@@ -302,5 +311,6 @@
        unix_update_to,
        unix_hash_address_pair,
        unix_checksum_address,
-       NULL    // matches_broadcast_address
+       NULL,   // matches_broadcast_address
+       NULL    // get_loopback_address
 };

Modified: haiku/trunk/src/tests/kits/net/Jamfile
===================================================================
--- haiku/trunk/src/tests/kits/net/Jamfile      2010-04-12 18:21:59 UTC (rev 
36191)
+++ haiku/trunk/src/tests/kits/net/Jamfile      2010-04-12 18:39:34 UTC (rev 
36192)
@@ -12,6 +12,9 @@
 SimpleTest tcp_server : tcp_server.c : $(TARGET_NETWORK_LIBS) ;
 SimpleTest tcp_client : tcp_client.c : $(TARGET_NETWORK_LIBS) ;
 
+SimpleTest ipv46_server : ipv46_server.cpp : $(TARGET_NETWORK_LIBS) ;
+SimpleTest ipv46_client : ipv46_client.cpp : $(TARGET_NETWORK_LIBS) ;
+
 SimpleTest getpeername : getpeername.cpp : $(TARGET_NETWORK_LIBS) ;
 
 SimpleTest tcp_connection_test : tcp_connection_test.cpp

Added: haiku/trunk/src/tests/kits/net/ipv46_client.cpp
===================================================================
--- haiku/trunk/src/tests/kits/net/ipv46_client.cpp                             
(rev 0)
+++ haiku/trunk/src/tests/kits/net/ipv46_client.cpp     2010-04-12 18:39:34 UTC 
(rev 36192)
@@ -0,0 +1,88 @@
+#include <unistd.h>
+#include <memory.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+const unsigned short TEST_PORT = 40000;
+
+void usage() {
+       printf("client [tcp|udp] [4|6] [4|6]\n");
+       exit(1);
+}
+
+int main(int argc, char *argv[]) {
+       int socketType = SOCK_DGRAM;
+       int socketFamily1 = AF_INET;
+       int socketFamily2 = AF_INET;
+
+       if (argc > 1) {
+               if (!strcmp(argv[1], "tcp")) {
+                       socketType = SOCK_STREAM;
+               } else if (!strcmp(argv[1], "udp")) {
+                       socketType = SOCK_DGRAM;
+               } else {
+                       usage();
+               }
+       }
+       if (argc > 2) {
+               switch (atoi(argv[2])) {
+               case 4:
+                       socketFamily1 = AF_INET;
+                       break;
+               case 6:
+                       socketFamily1 = AF_INET6;
+                       break;
+               default:
+                       usage();
+               }
+       }
+       if (argc > 3) {
+               switch (atoi(argv[3])) {
+               case 4:
+                       socketFamily2 = AF_INET;
+                       break;
+               case 6:
+                       socketFamily2 = AF_INET6;
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       int fd = socket(socketFamily1, socketType, 0);
+       if (fd < 0) {
+               perror("socket");
+               return -1;
+       }
+
+       sockaddr_storage saddr;
+       memset(&saddr, 0, sizeof(saddr));
+       saddr.ss_family = socketFamily2;
+       ((sockaddr_in *) &saddr)->sin_port = htons(TEST_PORT);
+       if (connect(fd, (sockaddr *) &saddr, socketFamily2 == AF_INET ?
+                               sizeof(sockaddr_in) : sizeof(sockaddr_in6)) < 
0) {
+               perror("connect");
+               close(fd);
+               return -1;
+       }
+
+       const char *buffer = "hello world";
+       unsigned len = strlen(buffer);
+       int ret = send(fd, buffer, len, 0);
+       if (ret < len) {
+               if (ret < 0) {
+                       perror("send");
+               } else if (ret == 0) {
+                       printf("no data sent!\n");
+               } else {
+                       printf("not all data sent!\n");
+               }
+       } else {
+               printf("send(): success\n");
+       }
+       close(fd);
+       return 0;
+}

Added: haiku/trunk/src/tests/kits/net/ipv46_server.cpp
===================================================================
--- haiku/trunk/src/tests/kits/net/ipv46_server.cpp                             
(rev 0)
+++ haiku/trunk/src/tests/kits/net/ipv46_server.cpp     2010-04-12 18:39:34 UTC 
(rev 36192)
@@ -0,0 +1,126 @@
+#include <unistd.h>
+#include <memory.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+const unsigned short TEST_PORT = 40000;
+
+void usage() {
+       printf("server [tcp|udp] [4|6] [local-address]\n");
+       exit(1);
+}
+
+void recvLoop(int fd) {
+       for (;;)        {
+               char buffer[1000];
+               int ret = recv(fd, buffer, sizeof(buffer) - 1, 0);
+               if (ret < 0) {
+                       perror("recv");
+                       exit(-1);
+               }
+               if (ret == 0) {
+                       printf("received EOF!\n");
+                       break;
+               } else {
+                       buffer[ret] = 0;
+                       printf("received %d bytes: \"%s\"\n", ret, buffer);
+               }
+       }
+}
+
+int main(int argc, char *argv[]) {
+       int socketType = SOCK_DGRAM;
+       int socketFamily = AF_INET;
+       if (argc > 1) {
+               if (!strcmp(argv[1], "tcp")) {
+                       socketType = SOCK_STREAM;
+               } else if (!strcmp(argv[1], "udp")) {
+                       socketType = SOCK_DGRAM;
+               } else {
+                       usage();
+               }
+       }
+       if (argc > 2) {
+               switch (atoi(argv[2])) {
+               case 4:
+                       socketFamily = AF_INET;
+                       break;
+               case 6:
+                       socketFamily = AF_INET6;
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       sockaddr_storage localAddress;
+       memset(&localAddress, 0, sizeof(localAddress));
+       localAddress.ss_family = socketFamily;
+       ((sockaddr_in *) &localAddress)->sin_port = htons(TEST_PORT);
+
+       if (argc > 3) {
+               do {
+                       void *dstBuffer = &((sockaddr_in *) 
&localAddress)->sin_addr;
+                       if (inet_pton(AF_INET, argv[3], dstBuffer) == 1) {
+                               printf("using IPv4 local address\n");
+                               localAddress.ss_family = AF_INET;
+                               break;
+                       }
+
+                       dstBuffer = &((sockaddr_in6 *) 
&localAddress)->sin6_addr;
+                       if (inet_pton(AF_INET6, argv[3], dstBuffer) == 1) {
+                               printf("using IPv6 local address\n");
+                               localAddress.ss_family = AF_INET6;
+                               break;
+                       }
+
+                       usage();
+               } while (false);
+       }
+
+       int fd = socket(socketFamily, socketType, 0);
+       if (fd < 0) {
+               perror("socket");
+               return -1;
+       }
+
+       if (bind(fd, (sockaddr *)&localAddress, localAddress.ss_family == 
AF_INET ?
+                        sizeof(sockaddr_in) : sizeof(sockaddr_in6)) < 0) {
+               perror("bind");
+               return -1;
+       }
+
+       switch (socketType) {
+       case SOCK_DGRAM:
+               for (;;) {
+                       recvLoop(fd);
+               }
+               break;
+       case SOCK_STREAM:
+               if (listen(fd, 5) < 0) {
+                       perror("listen");
+                       return 1;
+               }
+               for (;;) {
+                       int clientfd = accept(fd, NULL, 0);
+                       if (clientfd < 0) {
+                               perror("accept");
+                               return 1;
+                       }
+                       printf("TCP server: got some client!\n");
+                       if (fork() != 0) {
+                               // parent code
+                               close(clientfd);
+                               continue;
+                       }
+                       // child code
+                       close(fd);
+                       recvLoop(clientfd);
+                       exit(0);
+               }
+               break;
+       }
+}


Other related posts: