From 49a22456ddda2a7cfc5c19d9ccc131125b8b690c Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Sun, 13 Jul 2008 19:58:35 +0000 Subject: [PATCH] Overhauled BNetEndpoint implementation (and BNetAddress, too): * added NetEndpointTest that exposed a couple of bugs * fixed several bugs in the implementation of BNetEndpoint, some of which kept NetPenguin from working * fixed a couple of constness issues in BNetEndpoint and BNetAddress git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26405 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/net/NetAddress.h | 14 +- headers/os/net/NetEndpoint.h | 25 +- src/kits/network/libnetapi/NetAddress.cpp | 8 +- src/kits/network/libnetapi/NetEndpoint.cpp | 280 ++++++++++------ src/kits/network/socket.cpp | 2 +- src/tests/kits/net/Jamfile | 3 + src/tests/kits/net/NetEndpointTest.cpp | 352 +++++++++++++++++++++ 7 files changed, 566 insertions(+), 118 deletions(-) create mode 100644 src/tests/kits/net/NetEndpointTest.cpp diff --git a/headers/os/net/NetAddress.h b/headers/os/net/NetAddress.h index 170c5a07e7..23e6d158bf 100644 --- a/headers/os/net/NetAddress.h +++ b/headers/os/net/NetAddress.h @@ -27,22 +27,28 @@ class BNetAddress : public BArchivable { BNetAddress(in_addr addr, int port = 0); BNetAddress(uint32 addr, int port = 0); BNetAddress(const BNetAddress& other); - BNetAddress(const char* hostname, const char* protocol, const char* service); + BNetAddress(const char* hostname, const char* protocol, + const char* service); BNetAddress& operator=(const BNetAddress&); - status_t InitCheck(); + status_t InitCheck() const; - status_t SetTo(const char* hostname, const char* protocol, const char* service); + status_t SetTo(const char* hostname, const char* protocol, + const char* service); status_t SetTo(const char* hostname = NULL, unsigned short port = 0); status_t SetTo(const struct sockaddr_in& addr); status_t SetTo(in_addr addr, int port = 0); status_t SetTo(uint32 addr = INADDR_ANY, int port = 0); - status_t GetAddr(char* hostname = NULL, unsigned short* port = NULL) const; + status_t GetAddr(char* hostname = NULL, + unsigned short* port = NULL) const; status_t GetAddr(struct sockaddr_in& addr) const; status_t GetAddr(in_addr& addr, unsigned short* port = NULL) const; + // TODO: drop this compatibility cruft method after R1 + status_t InitCheck(); + private: virtual void _ReservedBNetAddressFBCCruft1(); virtual void _ReservedBNetAddressFBCCruft2(); diff --git a/headers/os/net/NetEndpoint.h b/headers/os/net/NetEndpoint.h index d2c83f96e4..1dc3d62cad 100644 --- a/headers/os/net/NetEndpoint.h +++ b/headers/os/net/NetEndpoint.h @@ -25,18 +25,19 @@ class BNetEndpoint : public BArchivable { BNetEndpoint& operator=(const BNetEndpoint& other); - status_t InitCheck(); + status_t InitCheck() const; virtual status_t Archive(BMessage* into, bool deep = true) const; static BArchivable* Instantiate(BMessage* archive); status_t SetProtocol(int protocol); - int SetOption(int32 option, int32 level, const void* data, unsigned int dataSize); + int SetOption(int32 option, int32 level, const void* data, + unsigned int dataSize); int SetNonBlocking(bool on = true); int SetReuseAddr(bool on = true); - const BNetAddress& LocalAddr(); - const BNetAddress& RemoteAddr(); + const BNetAddress& LocalAddr() const; + const BNetAddress& RemoteAddr() const; int Socket() const; @@ -71,7 +72,14 @@ class BNetEndpoint : public BArchivable { virtual bool IsDataPending(bigtime_t timeout = 0); + // TODO: drop these compatibility cruft methods after R1 + status_t InitCheck(); + const BNetAddress& LocalAddr(); + const BNetAddress& RemoteAddr(); + private: + status_t _SetupSocket(); + virtual void _ReservedBNetEndpointFBCCruft1(); virtual void _ReservedBNetEndpointFBCCruft2(); virtual void _ReservedBNetEndpointFBCCruft3(); @@ -79,14 +87,17 @@ class BNetEndpoint : public BArchivable { virtual void _ReservedBNetEndpointFBCCruft5(); virtual void _ReservedBNetEndpointFBCCruft6(); - status_t fInit; + status_t fStatus; + int fFamily; + int fType; + int fProtocol; int fSocket; bigtime_t fTimeout; - int fLastError; BNetAddress fAddr; BNetAddress fPeer; - int32 _reserved[18]; + int32 _reserved[16]; }; + #endif // H_NETENDPOINT diff --git a/src/kits/network/libnetapi/NetAddress.cpp b/src/kits/network/libnetapi/NetAddress.cpp index 0391d79913..27ad2c5dcc 100644 --- a/src/kits/network/libnetapi/NetAddress.cpp +++ b/src/kits/network/libnetapi/NetAddress.cpp @@ -241,12 +241,18 @@ status_t BNetAddress::GetAddr( in_addr& addr, unsigned short* port ) const * Returns: * B_OK if this instance is initialized, B_ERROR if not. */ -status_t BNetAddress::InitCheck( void ) +status_t BNetAddress::InitCheck( void ) const { return ( fInit == B_OK ) ? B_OK : B_ERROR; } +status_t BNetAddress::InitCheck() +{ + return const_cast(this)->InitCheck(); +} + + /* Archive *=--------------------------------------------------------------------------=* * Purpose: diff --git a/src/kits/network/libnetapi/NetEndpoint.cpp b/src/kits/network/libnetapi/NetEndpoint.cpp index 80fe168119..b78b540673 100644 --- a/src/kits/network/libnetapi/NetEndpoint.cpp +++ b/src/kits/network/libnetapi/NetEndpoint.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007, Haiku, Inc. All Rights Reserved. + * Copyright 2002-2008, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ @@ -20,71 +20,87 @@ BNetEndpoint::BNetEndpoint(int type) : - fInit(B_NO_INIT), + fStatus(B_NO_INIT), + fFamily(AF_INET), + fType(type), + fProtocol(0), fSocket(-1), - fTimeout(B_INFINITE_TIMEOUT), - fLastError(0) + fTimeout(B_INFINITE_TIMEOUT) { - if ((fSocket = socket(AF_INET, type, 0)) < 0) - fLastError = errno; - else - fInit = B_OK; + _SetupSocket(); } BNetEndpoint::BNetEndpoint(int family, int type, int protocol) : - fInit(B_NO_INIT), + fStatus(B_NO_INIT), + fFamily(family), + fType(type), + fProtocol(protocol), fSocket(-1), - fTimeout(B_INFINITE_TIMEOUT), - fLastError(0) + fTimeout(B_INFINITE_TIMEOUT) { - if ((fSocket = socket(family, type, protocol)) < 0) - fLastError = errno; - else - fInit = B_OK; + _SetupSocket(); } BNetEndpoint::BNetEndpoint(BMessage* archive) : - fInit(B_NO_INIT), + fStatus(B_NO_INIT), + fFamily(AF_INET), + fProtocol(0), fSocket(-1), - fTimeout(B_INFINITE_TIMEOUT), - fLastError(0) + fTimeout(B_INFINITE_TIMEOUT) { - // TODO - if (! archive) + if (!archive) return; - BMessage msg; - if (archive->FindMessage("bnendp_peer", &msg) != B_OK) - return; - fPeer = BNetAddress(&msg); + in_addr addr, peer; + unsigned short addrPort = 0, peerPort = 0; + + fStatus = archive->FindInt32("_BNetEndpoint_addr_addr", + (int32 *)&addr.s_addr); + if (fStatus == B_OK) { + fStatus = archive->FindInt16("_BNetEndpoint_addr_port", + (int16 *)&addrPort); + if (fStatus == B_OK) + fStatus = fAddr.SetTo(addr, addrPort); + } + + fStatus = archive->FindInt32("_BNetEndpoint_peer_addr", + (int32 *)&peer.s_addr); + if (fStatus == B_OK) { + fStatus = archive->FindInt16("_BNetEndpoint_peer_port", + (int16 *)&peerPort); + if (fStatus == B_OK) + fStatus = fPeer.SetTo(peer, peerPort); + } - if (archive->FindMessage("bnendp_addr", &msg) != B_OK) - return; - fAddr = BNetAddress(&msg); + fStatus = archive->FindInt64("_BNetEndpoint_timeout", (int64 *)&fTimeout); + if (fStatus == B_OK) + fStatus = archive->FindInt32("_BNetEndpoint_proto", (int32 *)&fType); - fInit = B_OK; + if (fStatus == B_OK) + _SetupSocket(); } BNetEndpoint::BNetEndpoint(const BNetEndpoint& endpoint) : - fInit(endpoint.fInit), + fStatus(endpoint.fStatus), + fFamily(endpoint.fFamily), + fType(endpoint.fType), + fProtocol(endpoint.fProtocol), + fSocket(-1), fTimeout(endpoint.fTimeout), - fLastError(endpoint.fLastError), fAddr(endpoint.fAddr), fPeer(endpoint.fPeer) + { - fSocket = -1; if (endpoint.fSocket >= 0) { fSocket = dup(endpoint.fSocket); - if (fSocket < 0) { - fLastError = errno; - fInit = B_NO_INIT; - } + if (fSocket < 0) + fStatus = errno; } } @@ -92,21 +108,24 @@ BNetEndpoint::BNetEndpoint(const BNetEndpoint& endpoint) BNetEndpoint& BNetEndpoint::operator=(const BNetEndpoint& endpoint) { + if (this == &endpoint) + return *this; + Close(); - fInit = endpoint.fInit; + fStatus = endpoint.fStatus; + fFamily = endpoint.fFamily; + fType = endpoint.fType; + fProtocol = endpoint.fProtocol; fTimeout = endpoint.fTimeout; - fLastError = endpoint.fLastError; fAddr = endpoint.fAddr; fPeer = endpoint.fPeer; fSocket = -1; if (endpoint.fSocket >= 0) { fSocket = dup(endpoint.fSocket); - if (fSocket < 0) { - fLastError = errno; - fInit = B_NO_INIT; - } + if (fSocket < 0) + fStatus = errno; } return *this; @@ -115,7 +134,8 @@ BNetEndpoint::operator=(const BNetEndpoint& endpoint) BNetEndpoint::~BNetEndpoint() { - Close(); + if (fSocket >= 0) + Close(); } @@ -125,25 +145,38 @@ BNetEndpoint::~BNetEndpoint() status_t BNetEndpoint::Archive(BMessage* into, bool deep) const { - // TODO - if (into == 0) + if (!into) return B_ERROR; - if (fInit != B_OK) - return B_NO_INIT; + status_t status = BArchivable::Archive(into, deep); + if (status != B_OK) + return status; - BMessage msg; - if (fPeer.Archive(&msg) != B_OK) - return B_ERROR; - if (into->AddMessage("bnendp_peer", &msg) != B_OK) - return B_ERROR; + in_addr addr, peer; + unsigned short addrPort, peerPort; - if (fAddr.Archive(&msg) != B_OK) - return B_ERROR; - if (into->AddMessage("bnendp_addr", &msg) != B_OK) - return B_ERROR; + status = fAddr.GetAddr(addr, &addrPort); + if (status == B_OK) { + status = into->AddInt32("_BNetEndpoint_addr_addr", addr.s_addr); + if (status == B_OK) + status = into->AddInt16("_BNetEndpoint_addr_port", addrPort); + if (status != B_OK) + return status; + } + status = fPeer.GetAddr(peer, &peerPort); + if (status == B_OK) { + status = into->AddInt32("_BNetEndpoint_peer_addr", peer.s_addr); + if (status == B_OK) + status = into->AddInt16("_BNetEndpoint_peer_port", peerPort); + if (status != B_OK) + return status; + } - return B_OK; + status = into->AddInt64("_BNetEndpoint_timeout", fTimeout); + if (status == B_OK) + status = into->AddInt32("_BNetEndpoint_proto", fType); + + return status; } @@ -153,7 +186,7 @@ BNetEndpoint::Instantiate(BMessage* archive) if (!archive) return NULL; - if (!validate_instantiation(archive, "BNetAddress")) + if (!validate_instantiation(archive, "BNetEndpoint")) return NULL; BNetEndpoint* endpoint = new BNetEndpoint(archive); @@ -169,9 +202,9 @@ BNetEndpoint::Instantiate(BMessage* archive) status_t -BNetEndpoint::InitCheck() +BNetEndpoint::InitCheck() const { - return fInit; + return fSocket == -1 ? B_NO_INIT : B_OK; } @@ -183,14 +216,14 @@ BNetEndpoint::Socket() const const BNetAddress& -BNetEndpoint::LocalAddr() +BNetEndpoint::LocalAddr() const { return fAddr; } const BNetAddress& -BNetEndpoint::RemoteAddr() +BNetEndpoint::RemoteAddr() const { return fPeer; } @@ -200,12 +233,8 @@ status_t BNetEndpoint::SetProtocol(int protocol) { Close(); - if ((fSocket = socket(AF_INET, protocol, 0)) < 0) { - fLastError = errno; - return fLastError; - } - fInit = B_OK; - return fInit; + fType = protocol; // sic (protocol is SOCK_DGRAM or SOCK_STREAM) + return _SetupSocket(); } @@ -213,11 +242,11 @@ int BNetEndpoint::SetOption(int32 option, int32 level, const void* data, unsigned int length) { - if (fInit < B_OK) - return fInit; + if (fSocket < 0 && _SetupSocket() != B_OK) + return fStatus; if (setsockopt(fSocket, level, option, data, length) < 0) { - fLastError = errno; + fStatus = errno; return B_ERROR; } @@ -228,9 +257,12 @@ BNetEndpoint::SetOption(int32 option, int32 level, int BNetEndpoint::SetNonBlocking(bool enable) { + if (fSocket < 0 && _SetupSocket() != B_OK) + return fStatus; + int flags = fcntl(fSocket, F_GETFL); if (flags < 0) { - fLastError = errno; + fStatus = errno; return B_ERROR; } @@ -240,7 +272,7 @@ BNetEndpoint::SetNonBlocking(bool enable) flags &= ~O_NONBLOCK; if (fcntl(fSocket, F_SETFL, flags) < 0) { - fLastError = errno; + fStatus = errno; return B_ERROR; } @@ -251,6 +283,9 @@ BNetEndpoint::SetNonBlocking(bool enable) int BNetEndpoint::SetReuseAddr(bool enable) { + if (fSocket < 0 && _SetupSocket() != B_OK) + return fStatus; + int onoff = (int) enable; return SetOption(SO_REUSEADDR, SOL_SOCKET, &onoff, sizeof(onoff)); } @@ -266,14 +301,14 @@ BNetEndpoint::SetTimeout(bigtime_t timeout) int BNetEndpoint::Error() const { - return fLastError; + return (int)fStatus; } char* BNetEndpoint::ErrorStr() const { - return strerror(fLastError); + return strerror(fStatus); } @@ -287,15 +322,15 @@ BNetEndpoint::Close() close(fSocket); fSocket = -1; - fInit = B_NO_INIT; + fStatus = B_NO_INIT; } status_t BNetEndpoint::Bind(const BNetAddress& address) { - if (fInit < B_OK) - return fInit; + if (fSocket < 0 && _SetupSocket() != B_OK) + return fStatus; struct sockaddr_in addr; status_t status = address.GetAddr(addr); @@ -303,28 +338,18 @@ BNetEndpoint::Bind(const BNetAddress& address) return status; if (bind(fSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - fLastError = errno; + fStatus = errno; Close(); return B_ERROR; } socklen_t addrSize = sizeof(addr); if (getsockname(fSocket, (struct sockaddr *)&addr, &addrSize) < 0) { - fLastError = errno; + fStatus = errno; Close(); return B_ERROR; } - if (addr.sin_addr.s_addr == 0) { - // TODO: does this still apply? - // Grrr, buggy getsockname! - char hostname[MAXHOSTNAMELEN]; - gethostname(hostname, sizeof(hostname)); - struct hostent *host = gethostbyname(hostname); - if (host != NULL) - memcpy(&addr.sin_addr.s_addr, host->h_addr, sizeof(addr.sin_addr.s_addr)); - } - fAddr.SetTo(addr); return B_OK; } @@ -341,8 +366,8 @@ BNetEndpoint::Bind(int port) status_t BNetEndpoint::Connect(const BNetAddress& address) { - if (fInit < B_OK) - return fInit; + if (fSocket < 0 && _SetupSocket() != B_OK) + return fStatus; sockaddr_in addr; if (address.GetAddr(addr) != B_OK) @@ -350,17 +375,16 @@ BNetEndpoint::Connect(const BNetAddress& address) if (connect(fSocket, (sockaddr *) &addr, sizeof(addr)) < 0) { Close(); - fLastError = errno; + fStatus = errno; return B_ERROR; } socklen_t addrSize = sizeof(addr); if (getpeername(fSocket, (sockaddr *) &addr, &addrSize) < 0) { Close(); - fLastError = errno; + fStatus = errno; return B_ERROR; } - fPeer.SetTo(addr); return B_OK; } @@ -377,12 +401,12 @@ BNetEndpoint::Connect(const char *hostname, int port) status_t BNetEndpoint::Listen(int backlog) { - if (fInit < B_OK) - return fInit; + if (fSocket < 0 && _SetupSocket() != B_OK) + return fStatus; if (listen(fSocket, backlog) < 0) { Close(); - fLastError = errno; + fStatus = errno; return B_ERROR; } return B_OK; @@ -401,14 +425,14 @@ BNetEndpoint::Accept(int32 timeout) int socket = accept(fSocket, (struct sockaddr *) &addr, &addrSize); if (socket < 0) { Close(); - fLastError = errno; + fStatus = errno; return NULL; } BNetEndpoint* endpoint = new (std::nothrow) BNetEndpoint(*this); if (endpoint == NULL) { close(socket); - fLastError = B_NO_MEMORY; + fStatus = B_NO_MEMORY; return NULL; } @@ -417,7 +441,7 @@ BNetEndpoint::Accept(int32 timeout) if (getsockname(socket, (struct sockaddr *)&addr, &addrSize) < 0) { delete endpoint; - fLastError = errno; + fStatus = errno; return NULL; } @@ -444,7 +468,7 @@ BNetEndpoint::IsDataPending(bigtime_t timeout) } if (select(fSocket + 1, &fds, NULL, NULL, timeout > 0 ? &tv : NULL) < 0) { - fLastError = errno; + fStatus = errno; return false; } @@ -455,12 +479,15 @@ BNetEndpoint::IsDataPending(bigtime_t timeout) int32 BNetEndpoint::Receive(void* buffer, size_t length, int flags) { + if (fSocket < 0 && _SetupSocket() != B_OK) + return fStatus; + if (fTimeout >= 0 && IsDataPending(fTimeout) == false) return 0; ssize_t bytesReceived = recv(fSocket, buffer, length, flags); if (bytesReceived < 0) - fLastError = errno; + fStatus = errno; return bytesReceived; } @@ -480,6 +507,9 @@ int32 BNetEndpoint::ReceiveFrom(void* buffer, size_t length, BNetAddress& address, int flags) { + if (fSocket < 0 && _SetupSocket() != B_OK) + return fStatus; + if (fTimeout >= 0 && IsDataPending(fTimeout) == false) return 0; @@ -489,7 +519,7 @@ BNetEndpoint::ReceiveFrom(void* buffer, size_t length, length = recvfrom(fSocket, buffer, length, flags, (struct sockaddr *)&addr, &addrSize); if (length < 0) - fLastError = errno; + fStatus = errno; else address.SetTo(addr); @@ -511,9 +541,12 @@ BNetEndpoint::ReceiveFrom(BNetBuffer& buffer, size_t length, int32 BNetEndpoint::Send(const void* buffer, size_t length, int flags) { + if (fSocket < 0 && _SetupSocket() != B_OK) + return fStatus; + ssize_t bytesSent = send(fSocket, (const char *) buffer, length, flags); if (bytesSent < 0) - fLastError = errno; + fStatus = errno; return bytesSent; } @@ -530,6 +563,9 @@ int32 BNetEndpoint::SendTo(const void* buffer, size_t length, const BNetAddress& address, int flags) { + if (fSocket < 0 && _SetupSocket() != B_OK) + return fStatus; + struct sockaddr_in addr; if (address.GetAddr(addr) != B_OK) return B_ERROR; @@ -537,7 +573,7 @@ BNetEndpoint::SendTo(const void* buffer, size_t length, ssize_t bytesSent = sendto(fSocket, buffer, length, flags, (struct sockaddr *) &addr, sizeof(addr)); if (bytesSent < 0) - fLastError = errno; + fStatus = errno; return bytesSent; } @@ -554,6 +590,40 @@ BNetEndpoint::SendTo(BNetBuffer& buffer, // #pragma mark - +status_t +BNetEndpoint::_SetupSocket() +{ + if ((fSocket = socket(fFamily, fType, fProtocol)) < 0) + fStatus = errno; + else + fStatus = B_OK; + return fStatus; +} + + +// #pragma mark - + +status_t BNetEndpoint::InitCheck() +{ + return const_cast(this)->InitCheck(); +} + + +const BNetAddress& BNetEndpoint::LocalAddr() +{ + return const_cast(this)->LocalAddr(); +} + + +const BNetAddress& BNetEndpoint::RemoteAddr() +{ + return const_cast(this)->RemoteAddr(); +} + + +// #pragma mark - + + // These are virtuals, implemented for binary compatibility purpose void BNetEndpoint::_ReservedBNetEndpointFBCCruft1() {} void BNetEndpoint::_ReservedBNetEndpointFBCCruft2() {} diff --git a/src/kits/network/socket.cpp b/src/kits/network/socket.cpp index ef66045ba1..5aa32eb855 100644 --- a/src/kits/network/socket.cpp +++ b/src/kits/network/socket.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007, Haiku, Inc. All Rights Reserved. + * Copyright 2002-2008, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ diff --git a/src/tests/kits/net/Jamfile b/src/tests/kits/net/Jamfile index 54b362a521..d9c165edfd 100644 --- a/src/tests/kits/net/Jamfile +++ b/src/tests/kits/net/Jamfile @@ -17,6 +17,9 @@ SimpleTest tcp_connection_test : tcp_connection_test.cpp SimpleTest NetAddressTest : NetAddressTest.cpp : $(TARGET_NETWORK_LIBS) $(HAIKU_NETAPI_LIB) ; +SimpleTest NetEndpointTest : NetEndpointTest.cpp + : $(TARGET_NETWORK_LIBS) $(HAIKU_NETAPI_LIB) be ; + SubInclude HAIKU_TOP src tests kits net DialUpPreflet ; SubInclude HAIKU_TOP src tests kits net multicast ; SubInclude HAIKU_TOP src tests kits net netperf ; diff --git a/src/tests/kits/net/NetEndpointTest.cpp b/src/tests/kits/net/NetEndpointTest.cpp new file mode 100644 index 0000000000..2488d6040c --- /dev/null +++ b/src/tests/kits/net/NetEndpointTest.cpp @@ -0,0 +1,352 @@ +/* + * Copyright 2008, Oliver Tappe, zooey@hirschkaefer.de. + * Distributed under the terms of the MIT license. + */ + + +#include +#include + +#include +#include +#include +#include +#include +#include + + +static BNetAddress serverAddr("127.0.0.1", 1234); +static BNetAddress clientAddr("127.0.0.1", 51234); + + +static int problemCount = 0; + + +void +checkAddrsAreEqual(const BNetAddress& na1, const BNetAddress& na2, + const char* fmt) +{ + in_addr addr1, addr2; + unsigned short port1, port2; + na1.GetAddr(addr1, &port1); + na2.GetAddr(addr2, &port2); + if (addr1.s_addr == addr2.s_addr && port1 == port2) + return; + fprintf(stderr, fmt, addr1.s_addr, port1, addr2.s_addr, port2); + exit(1); +} + + +void +checkArchive(const BNetEndpoint ne, int32 protocol, + const BNetAddress& localNetAddress, const BNetAddress& remoteNetAddress) +{ + in_addr localAddr, remoteAddr; + unsigned short localPort, remotePort; + localNetAddress.GetAddr(localAddr, &localPort); + remoteNetAddress.GetAddr(remoteAddr, &remotePort); + + BMessage archive(0UL); + status_t status = ne.Archive(&archive); + if (status != B_OK) { + fprintf(stderr, "Archive() failed - %lx:%s\n", status, + strerror(status)); + problemCount++; + exit(1); + } + const char* arcClass; + if (archive.FindString("class", &arcClass) != B_OK) { + fprintf(stderr, "'class' not found in archive\n"); + problemCount++; + exit(1); + } + if (strcmp(arcClass, "BNetEndpoint") != 0) { + fprintf(stderr, "expected 'class' to be 'BNetEndpoint' - is '%s'\n", + arcClass); + problemCount++; + exit(1); + } + + if (ne.LocalAddr().InitCheck() == B_OK) { + int32 arcAddr; + if (archive.FindInt32("_BNetEndpoint_addr_addr", &arcAddr) != B_OK) { + fprintf(stderr, "'_BNetEndpoint_addr_addr' not found in archive\n"); + problemCount++; + exit(1); + } + if ((uint32)localAddr.s_addr != (uint32)arcAddr) { + fprintf(stderr, + "expected '_BNetEndpoint_addr_addr' to be %x - is %x\n", + localAddr.s_addr, (unsigned int)arcAddr); + problemCount++; + exit(1); + } + int16 arcPort; + if (archive.FindInt16("_BNetEndpoint_addr_port", &arcPort) != B_OK) { + fprintf(stderr, "'_BNetEndpoint_addr_port' not found in archive\n"); + problemCount++; + exit(1); + } + if ((uint16)localPort != (uint16)arcPort) { + fprintf(stderr, + "expected '_BNetEndpoint_addr_port' to be %d - is %d\n", + localPort, (int)arcPort); + problemCount++; + exit(1); + } + } + + if (ne.RemoteAddr().InitCheck() == B_OK) { + int32 arcAddr; + if (archive.FindInt32("_BNetEndpoint_peer_addr", &arcAddr) != B_OK) { + fprintf(stderr, "'_BNetEndpoint_peer_addr' not found in archive\n"); + problemCount++; + exit(1); + } + if ((uint32)remoteAddr.s_addr != (uint32)arcAddr) { + fprintf(stderr, + "expected '_BNetEndpoint_peer_addr' to be %x - is %x\n", + remoteAddr.s_addr, (unsigned int)arcAddr); + problemCount++; + exit(1); + } + int16 arcPort; + if (archive.FindInt16("_BNetEndpoint_peer_port", &arcPort) != B_OK) { + fprintf(stderr, "'_BNetEndpoint_peer_port' not found in archive\n"); + problemCount++; + exit(1); + } + if ((uint16)remotePort != (uint16)arcPort) { + fprintf(stderr, + "expected '_BNetEndpoint_peer_port' to be %u - is %u\n", + remotePort, (unsigned short)arcPort); + problemCount++; + exit(1); + } + } + + int64 arcTimeout; + if (archive.FindInt64("_BNetEndpoint_timeout", &arcTimeout) != B_OK) { + fprintf(stderr, "'_BNetEndpoint_timeout' not found in archive\n"); + problemCount++; + exit(1); + } + if (arcTimeout != B_INFINITE_TIMEOUT) { + fprintf(stderr, + "expected '_BNetEndpoint_timeout' to be %llu - is %llu\n", + B_INFINITE_TIMEOUT, (uint64)arcTimeout); + problemCount++; + exit(1); + } + + int32 arcProtocol; + if (archive.FindInt32("_BNetEndpoint_proto", &arcProtocol) != B_OK) { + fprintf(stderr, "'_BNetEndpoint_proto' not found in archive\n"); + problemCount++; + exit(1); + } + if (arcProtocol != protocol) { + fprintf(stderr, "expected '_BNetEndpoint_proto' to be %d - is %d\n", + (int)protocol, (int)arcProtocol); + problemCount++; + exit(1); + } + + BNetEndpoint* clone + = dynamic_cast(BNetEndpoint::Instantiate(&archive)); + if (!clone) { + fprintf(stderr, "unable to instantiate endpoint from archive\n"); + problemCount++; + exit(1); + } + delete clone; +} + +void testServer(thread_id clientThread) +{ + char buf[1]; + + // check simple UDP "connection" + BNetEndpoint server(SOCK_DGRAM); + for(int i=0; i < 2; ++i) { + status_t status = server.Bind(serverAddr); + if (status != B_OK) { + fprintf(stderr, "Bind() failed in testServer - %s\n", + strerror(status)); + problemCount++; + exit(1); + } + + checkAddrsAreEqual(server.LocalAddr(), serverAddr, + "LocalAddr() doesn't match serverAddr\n"); + + if (i == 0) + resume_thread(clientThread); + + BNetAddress remoteAddr; + status = server.ReceiveFrom(buf, 1, remoteAddr, 0); + if (status < B_OK) { + fprintf(stderr, "ReceiveFrom() failed in testServer - %s\n", + strerror(status)); + problemCount++; + exit(1); + } + + if (buf[0] != 'U') { + fprintf(stderr, "expected to receive %c but got %c\n", 'U', buf[0]); + problemCount++; + exit(1); + } + + checkAddrsAreEqual(remoteAddr, clientAddr, + "remoteAddr(%x:%d) doesn't match clientAddr(%x:%d)\n"); + + checkArchive(server, SOCK_DGRAM, serverAddr, clientAddr); + + server.Close(); + } + + // now switch to TCP and try again + server.SetProtocol(SOCK_STREAM); + status_t status = server.Bind(serverAddr); + if (status != B_OK) { + fprintf(stderr, "Bind() failed in testServer - %s\n", + strerror(status)); + problemCount++; + exit(1); + } + + checkAddrsAreEqual(server.LocalAddr(), serverAddr, + "LocalAddr() doesn't match serverAddr\n"); + + status = server.Listen(); + BNetEndpoint* acceptedConn = server.Accept(); + if (acceptedConn == NULL) { + fprintf(stderr, "Accept() failed in testServer\n"); + problemCount++; + exit(1); + } + + const BNetAddress& remoteAddr = acceptedConn->RemoteAddr(); + checkAddrsAreEqual(remoteAddr, clientAddr, + "remoteAddr(%x:%d) doesn't match clientAddr(%x:%d)\n"); + + status = acceptedConn->Receive(buf, 1); + if (status < B_OK) { + fprintf(stderr, "Receive() failed in testServer - %s\n", + strerror(status)); + problemCount++; + exit(1); + } + delete acceptedConn; + + if (buf[0] != 'T') { + fprintf(stderr, "expected to receive %c but got %c\n", 'T', buf[0]); + problemCount++; + exit(1); + } + + checkArchive(server, SOCK_STREAM, serverAddr, clientAddr); + + server.Close(); +} + + +int32 testClient(void *) +{ + BNetEndpoint client(SOCK_DGRAM); + printf("testing udp...\n"); + for(int i=0; i < 2; ++i) { + status_t status = client.Bind(clientAddr); + if (status != B_OK) { + fprintf(stderr, "Bind() failed in testClient - %s\n", + strerror(status)); + problemCount++; + exit(1); + } + + checkAddrsAreEqual(client.LocalAddr(), clientAddr, + "LocalAddr(%x:%d) doesn't match clientAddr(%x:%d)\n"); + + status = client.SendTo("U", 1, serverAddr, 0); + if (status < B_OK) { + fprintf(stderr, "SendTo() failed in testClient - %s\n", + strerror(status)); + problemCount++; + exit(1); + } + + checkArchive(client, SOCK_DGRAM, clientAddr, serverAddr); + + sleep(1); + + client.Close(); + } + + sleep(1); + + printf("testing tcp...\n"); + // now switch to TCP and try again + client.SetProtocol(SOCK_STREAM); + status_t status = client.Bind(clientAddr); + if (status != B_OK) { + fprintf(stderr, "Bind() failed in testClient - %s\n", + strerror(status)); + problemCount++; + exit(1); + } + + checkAddrsAreEqual(client.LocalAddr(), clientAddr, + "LocalAddr(%x:%d) doesn't match clientAddr(%x:%d)\n"); + + status = client.Connect(serverAddr); + if (status < B_OK) { + fprintf(stderr, "Connect() failed in testClient - %s\n", + strerror(status)); + problemCount++; + exit(1); + } + status = client.Send("T", 1); + if (status < B_OK) { + fprintf(stderr, "Send() failed in testClient - %s\n", + strerror(status)); + problemCount++; + exit(1); + } + + checkArchive(client, SOCK_STREAM, clientAddr, serverAddr); + + client.Close(); + + return B_OK; +} + + +int +main(int argc, const char* const* argv) +{ + BNetEndpoint dummy(SOCK_DGRAM); + if (sizeof(dummy) != 208) { + fprintf(stderr, "expected sizeof(netEndpoint) to be 208 - is %ld\n", + sizeof(dummy)); + exit(1); + } + dummy.Close(); + + // start thread for client + thread_id tid = spawn_thread(testClient, "client", B_NORMAL_PRIORITY, NULL); + if (tid < 0) { + fprintf(stderr, "spawn_thread() failed: %s\n", strerror(tid)); + exit(1); + } + + testServer(tid); + + status_t clientStatus; + wait_for_thread(tid, &clientStatus); + + if (!problemCount) + printf("Everything went fine.\n"); + + return 0; +}