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! git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36192 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -113,6 +113,7 @@ struct net_address_module_info {
|
|||||||
bool (*equal_masked_addresses)(const sockaddr *a, const sockaddr *b,
|
bool (*equal_masked_addresses)(const sockaddr *a, const sockaddr *b,
|
||||||
const sockaddr *mask);
|
const sockaddr *mask);
|
||||||
bool (*is_empty_address)(const sockaddr *address, bool checkPort);
|
bool (*is_empty_address)(const sockaddr *address, bool checkPort);
|
||||||
|
bool (*is_same_family)(const sockaddr *address);
|
||||||
|
|
||||||
int32 (*first_mask_bit)(const sockaddr *mask);
|
int32 (*first_mask_bit)(const sockaddr *mask);
|
||||||
|
|
||||||
@@ -142,6 +143,8 @@ struct net_address_module_info {
|
|||||||
|
|
||||||
bool (*matches_broadcast_address)(const sockaddr *address,
|
bool (*matches_broadcast_address)(const sockaddr *address,
|
||||||
const sockaddr *mask, const sockaddr *broadcastAddr);
|
const sockaddr *mask, const sockaddr *broadcastAddr);
|
||||||
|
|
||||||
|
void (*get_loopback_address)(sockaddr *result);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NET_DATALINK_H
|
#endif // NET_DATALINK_H
|
||||||
|
|||||||
@@ -107,6 +107,18 @@ ipv4_is_empty_address(const sockaddr *address, bool checkPort)
|
|||||||
&& (!checkPort || ((sockaddr_in *)address)->sin_port == 0);
|
&& (!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.
|
/*! 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
|
\return true if IP-addresses of \a a and \a b are equal, false if not
|
||||||
@@ -477,6 +489,16 @@ ipv4_checksum_address(struct Checksum *checksum, const sockaddr *address)
|
|||||||
return B_OK;
|
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 = {
|
net_address_module_info gIPv4AddressModule = {
|
||||||
{
|
{
|
||||||
@@ -491,6 +513,7 @@ net_address_module_info gIPv4AddressModule = {
|
|||||||
ipv4_equal_addresses_and_ports,
|
ipv4_equal_addresses_and_ports,
|
||||||
ipv4_equal_masked_addresses,
|
ipv4_equal_masked_addresses,
|
||||||
ipv4_is_empty_address,
|
ipv4_is_empty_address,
|
||||||
|
ipv4_is_same_family,
|
||||||
ipv4_first_mask_bit,
|
ipv4_first_mask_bit,
|
||||||
ipv4_check_mask,
|
ipv4_check_mask,
|
||||||
ipv4_print_address,
|
ipv4_print_address,
|
||||||
@@ -503,5 +526,6 @@ net_address_module_info gIPv4AddressModule = {
|
|||||||
ipv4_update_to,
|
ipv4_update_to,
|
||||||
ipv4_hash_address_pair,
|
ipv4_hash_address_pair,
|
||||||
ipv4_checksum_address,
|
ipv4_checksum_address,
|
||||||
NULL // ipv4_matches_broadcast_address,
|
NULL, // ipv4_matches_broadcast_address,
|
||||||
|
ipv4_get_loopback_address
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -100,6 +100,18 @@ l2cap_is_empty_address(const sockaddr *address, bool checkPort)
|
|||||||
&& (!checkPort || ((sockaddr_l2cap *)address)->l2cap_psm == 0) );
|
&& (!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.
|
Compares the IP-addresses of the two given address structures \a a and \a b.
|
||||||
@@ -401,6 +413,7 @@ net_address_module_info gL2cap4AddressModule = {
|
|||||||
l2cap_equal_addresses_and_ports,
|
l2cap_equal_addresses_and_ports,
|
||||||
l2cap_equal_masked_addresses,
|
l2cap_equal_masked_addresses,
|
||||||
l2cap_is_empty_address,
|
l2cap_is_empty_address,
|
||||||
|
l2cap_is_same_family,
|
||||||
l2cap_first_mask_bit,
|
l2cap_first_mask_bit,
|
||||||
l2cap_check_mask,
|
l2cap_check_mask,
|
||||||
l2cap_print_address,
|
l2cap_print_address,
|
||||||
@@ -413,5 +426,6 @@ net_address_module_info gL2cap4AddressModule = {
|
|||||||
l2cap_update_to,
|
l2cap_update_to,
|
||||||
l2cap_hash_address_pair,
|
l2cap_hash_address_pair,
|
||||||
l2cap_checksum_address,
|
l2cap_checksum_address,
|
||||||
NULL // l2cap_matches_broadcast_address,
|
NULL, // l2cap_matches_broadcast_address,
|
||||||
|
NULL // get_loopback_address
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -362,9 +362,9 @@ EndpointManager::FindConnection(sockaddr* local, sockaddr* peer)
|
|||||||
status_t
|
status_t
|
||||||
EndpointManager::Bind(TCPEndpoint* endpoint, const sockaddr* address)
|
EndpointManager::Bind(TCPEndpoint* endpoint, const sockaddr* address)
|
||||||
{
|
{
|
||||||
// TODO: check the family:
|
// check the family
|
||||||
// if (!AddressModule()->is_understandable(address))
|
if (!AddressModule()->is_same_family(address))
|
||||||
// return EAFNOSUPPORT;
|
return EAFNOSUPPORT;
|
||||||
|
|
||||||
WriteLocker locker(fLock);
|
WriteLocker locker(fLock);
|
||||||
|
|
||||||
|
|||||||
@@ -584,6 +584,9 @@ TCPEndpoint::Connect(const sockaddr* address)
|
|||||||
{
|
{
|
||||||
TRACE("Connect() on address %s", PrintAddress(address));
|
TRACE("Connect() on address %s", PrintAddress(address));
|
||||||
|
|
||||||
|
if (!AddressModule()->is_same_family(address))
|
||||||
|
return EAFNOSUPPORT;
|
||||||
|
|
||||||
MutexLocker locker(fLock);
|
MutexLocker locker(fLock);
|
||||||
|
|
||||||
if (gStackModule->is_restarted_syscall()) {
|
if (gStackModule->is_restarted_syscall()) {
|
||||||
@@ -604,14 +607,13 @@ TCPEndpoint::Connect(const sockaddr* address)
|
|||||||
} else if (fState != CLOSED)
|
} else if (fState != CLOSED)
|
||||||
return EINPROGRESS;
|
return EINPROGRESS;
|
||||||
|
|
||||||
// TODO: this is IPv4 specific, and doesn't belong here!
|
|
||||||
// consider destination address INADDR_ANY as INADDR_LOOPBACK
|
// consider destination address INADDR_ANY as INADDR_LOOPBACK
|
||||||
sockaddr_in _address;
|
sockaddr_storage _address;
|
||||||
if (((sockaddr_in*)address)->sin_addr.s_addr == INADDR_ANY) {
|
if (AddressModule()->is_empty_address(address, false)) {
|
||||||
memcpy(&_address, address, sizeof(sockaddr_in));
|
AddressModule()->get_loopback_address((sockaddr *)&_address);
|
||||||
_address.sin_len = sizeof(sockaddr_in);
|
// for IPv4 and IPv6 the port is at the same offset
|
||||||
_address.sin_addr.s_addr = INADDR_LOOPBACK;
|
((sockaddr_in &)_address).sin_port = ((sockaddr_in *)address)->sin_port;
|
||||||
address = (sockaddr*)&_address;
|
address = (sockaddr *)&_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t status = _PrepareSendPath(address);
|
status_t status = _PrepareSendPath(address);
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ public:
|
|||||||
status_t Close();
|
status_t Close();
|
||||||
status_t Free();
|
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);
|
status_t SendData(net_buffer *buffer);
|
||||||
|
|
||||||
ssize_t BytesAvailable();
|
ssize_t BytesAvailable();
|
||||||
@@ -101,8 +102,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
UdpDomainSupport *fManager;
|
UdpDomainSupport *fManager;
|
||||||
bool fActive;
|
bool fActive;
|
||||||
// an active UdpEndpoint is part of the endpoint
|
// an active UdpEndpoint is part of the
|
||||||
// hash (and it is bound and optionally connected)
|
// endpoint hash (and it is bound and optionally
|
||||||
|
// connected)
|
||||||
|
|
||||||
UdpEndpoint *fLink;
|
UdpEndpoint *fLink;
|
||||||
};
|
};
|
||||||
@@ -127,12 +129,13 @@ struct UdpHashDefinition {
|
|||||||
|
|
||||||
size_t Hash(UdpEndpoint *endpoint) const
|
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)
|
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
|
return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
|
||||||
^ (hash & 0xFFC00000UL) >> 22;
|
^ (hash & 0xFFC00000UL) >> 22;
|
||||||
}
|
}
|
||||||
@@ -287,6 +290,9 @@ status_t
|
|||||||
UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
|
UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
|
||||||
const sockaddr *address)
|
const sockaddr *address)
|
||||||
{
|
{
|
||||||
|
if (!AddressModule()->is_same_family(address))
|
||||||
|
return EAFNOSUPPORT;
|
||||||
|
|
||||||
MutexLocker _(fLock);
|
MutexLocker _(fLock);
|
||||||
|
|
||||||
if (endpoint->IsActive())
|
if (endpoint->IsActive())
|
||||||
@@ -312,6 +318,19 @@ UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint,
|
|||||||
// so we reset the peer address:
|
// so we reset the peer address:
|
||||||
endpoint->PeerAddress().SetToEmpty();
|
endpoint->PeerAddress().SetToEmpty();
|
||||||
} else {
|
} 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);
|
status_t status = endpoint->PeerAddress().SetTo(address);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
@@ -398,7 +417,8 @@ UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address)
|
|||||||
|
|
||||||
if (otherEndpoint->LocalAddress().EqualPorts(address)) {
|
if (otherEndpoint->LocalAddress().EqualPorts(address)) {
|
||||||
// port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
|
// 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)
|
|| (socketOptions & (SO_REUSEADDR | SO_REUSEPORT)) == 0)
|
||||||
return EADDRINUSE;
|
return EADDRINUSE;
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,14 @@ unix_is_empty_address(const sockaddr *address, bool checkPort)
|
|||||||
&& memcmp(address, &kEmptyAddress, kEmptyAddress.sun_len) == 0;
|
&& 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
|
static int32
|
||||||
unix_first_mask_bit(const sockaddr *mask)
|
unix_first_mask_bit(const sockaddr *mask)
|
||||||
@@ -290,6 +298,7 @@ net_address_module_info gAddressModule = {
|
|||||||
unix_equal_addresses_and_ports,
|
unix_equal_addresses_and_ports,
|
||||||
unix_equal_masked_addresses,
|
unix_equal_masked_addresses,
|
||||||
unix_is_empty_address,
|
unix_is_empty_address,
|
||||||
|
unix_is_same_family,
|
||||||
unix_first_mask_bit,
|
unix_first_mask_bit,
|
||||||
unix_check_mask,
|
unix_check_mask,
|
||||||
unix_print_address,
|
unix_print_address,
|
||||||
@@ -302,5 +311,6 @@ net_address_module_info gAddressModule = {
|
|||||||
unix_update_to,
|
unix_update_to,
|
||||||
unix_hash_address_pair,
|
unix_hash_address_pair,
|
||||||
unix_checksum_address,
|
unix_checksum_address,
|
||||||
NULL // matches_broadcast_address
|
NULL, // matches_broadcast_address
|
||||||
|
NULL // get_loopback_address
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ SimpleTest udp_server : udp_server.c : $(TARGET_NETWORK_LIBS) ;
|
|||||||
SimpleTest tcp_server : tcp_server.c : $(TARGET_NETWORK_LIBS) ;
|
SimpleTest tcp_server : tcp_server.c : $(TARGET_NETWORK_LIBS) ;
|
||||||
SimpleTest tcp_client : tcp_client.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 getpeername : getpeername.cpp : $(TARGET_NETWORK_LIBS) ;
|
||||||
|
|
||||||
SimpleTest tcp_connection_test : tcp_connection_test.cpp
|
SimpleTest tcp_connection_test : tcp_connection_test.cpp
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user