Skip to content

Commit

Permalink
Add Socket::Get[Remote/Local]IpAddress and unit tests
Browse files Browse the repository at this point in the history
Differential Revision: http://reviews.llvm.org/D6917

llvm-svn: 226234
  • Loading branch information
vharrong committed Jan 16, 2015
1 parent 0a3a7cc commit 014bb7d
Show file tree
Hide file tree
Showing 10 changed files with 478 additions and 19 deletions.
16 changes: 16 additions & 0 deletions lldb/gtest/gtest.xcodeproj/project.pbxproj
Expand Up @@ -12,6 +12,10 @@
236ED33619D490B0008CA7D7 /* Makefile.rules */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Makefile.rules; sourceTree = "<group>"; };
33064C981A5C7A1A0033D415 /* UriParserTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UriParserTest.cpp; path = Utility/UriParserTest.cpp; sourceTree = "<group>"; };
33064C9D1A5C7AC90033D415 /* do-gtest.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = "do-gtest.py"; sourceTree = "<group>"; };
330E475C1A609CF600FD2884 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = Host/Makefile; sourceTree = "<group>"; };
330E475D1A609CF600FD2884 /* SocketTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SocketTest.cpp; path = Host/SocketTest.cpp; sourceTree = "<group>"; };
330E475E1A60B31F00FD2884 /* SocketTestMock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SocketTestMock.cpp; path = Host/SocketTestMock.cpp; sourceTree = "<group>"; };
330E47621A62451800FD2884 /* SocketAddressTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SocketAddressTest.cpp; path = Host/SocketAddressTest.cpp; sourceTree = "<group>"; };
338C47F41A1E67B900B46077 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = Utility/Makefile; sourceTree = "<group>"; };
338C47F51A1E67B900B46077 /* StringExtractorTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringExtractorTest.cpp; path = Utility/StringExtractorTest.cpp; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand All @@ -20,6 +24,7 @@
236ED32F19D4901D008CA7D7 /* unittest */ = {
isa = PBXGroup;
children = (
330E475B1A609CDF00FD2884 /* Host */,
338C47F31A1E677900B46077 /* Utility */,
236ED33019D4903E008CA7D7 /* Plugins */,
);
Expand Down Expand Up @@ -68,6 +73,17 @@
);
sourceTree = "<group>";
};
330E475B1A609CDF00FD2884 /* Host */ = {
isa = PBXGroup;
children = (
330E475E1A60B31F00FD2884 /* SocketTestMock.cpp */,
330E475C1A609CF600FD2884 /* Makefile */,
330E475D1A609CF600FD2884 /* SocketTest.cpp */,
330E47621A62451800FD2884 /* SocketAddressTest.cpp */,
);
name = Host;
sourceTree = "<group>";
};
338C47F31A1E677900B46077 /* Utility */ = {
isa = PBXGroup;
children = (
Expand Down
32 changes: 32 additions & 0 deletions lldb/gtest/unittest/Host/Makefile
@@ -0,0 +1,32 @@
THIS_FILE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))/

LEVEL := $(realpath $(THIS_FILE_DIR)../../make)

CFLAGS_EXTRAS := -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS
ENABLE_THREADS := YES
# the fact that we need all of these source files to compile Socket.cpp
# is a good indication that we need some refactoring
CXX_SOURCES := $(wildcard *.cpp) \
$(realpath $(LEVEL)/../../source/Core/Error.cpp) \
$(realpath $(LEVEL)/../../source/Core/RegularExpression.cpp) \
$(realpath $(LEVEL)/../../source/Core/Stream.cpp) \
$(realpath $(LEVEL)/../../source/Core/StreamString.cpp) \
$(realpath $(LEVEL)/../../source/Host/common/Socket.cpp) \
$(realpath $(LEVEL)/../../source/Host/common/SocketAddress.cpp) \
$(realpath $(LEVEL)/../../source/Host/common/StringConvert.cpp) \
$(realpath $(LEVEL)/../../source/Host/common/TimeValue.cpp)

OS := $(shell uname -s)
ifeq ($(OS),Windows)
CXX_SOURCES := $(CXX_SOURCES) \
$(LEVEL)/../../source/Host/windows/Condition.cpp \
$(LEVEL)/../../source/Host/windows/Mutex.cpp
else
CXX_SOURCES := $(CXX_SOURCES) \
$(LEVEL)/../../source/Host/common/Condition.cpp \
$(LEVEL)/../../source/Host/common/Mutex.cpp
endif

MAKE_DSYM := NO

include $(LEVEL)/Makefile.rules
77 changes: 77 additions & 0 deletions lldb/gtest/unittest/Host/SocketAddressTest.cpp
@@ -0,0 +1,77 @@
//===-- SocketAddressTest.cpp -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//


#include "gtest/gtest.h"

#include "lldb/Host/SocketAddress.h"

namespace
{
class SocketAddressTest: public ::testing::Test
{
};
}

using namespace lldb_private;

TEST_F (SocketAddressTest, Set)
{
SocketAddress sa;
ASSERT_TRUE (sa.SetToLocalhost (AF_INET, 1138));
ASSERT_STREQ ("127.0.0.1", sa.GetIPAddress ().c_str ());
ASSERT_EQ (1138, sa.GetPort ());

ASSERT_TRUE (sa.SetToAnyAddress (AF_INET, 0));
ASSERT_STREQ ("0.0.0.0", sa.GetIPAddress ().c_str ());
ASSERT_EQ (0, sa.GetPort ());

ASSERT_TRUE (sa.SetToLocalhost (AF_INET6, 1139));
#ifdef _WIN32
ASSERT_STREQ ("0:0:0:0:0:0:0:1", sa.GetIPAddress ().c_str ());
#else
ASSERT_STREQ ("::1", sa.GetIPAddress ().c_str ());
#endif
ASSERT_EQ (1139, sa.GetPort ());
}

#ifdef _WIN32

// we need to test our inet_ntop implementation for Windows XP
const char* inet_ntop (int af, const void * src,
char * dst, socklen_t size);

TEST_F (SocketAddressTest, inet_ntop)
{
const uint8_t address4[4] = {255, 0, 1, 100};
const uint8_t address6[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 255, 0};

char buffer[INET6_ADDRSTRLEN];
memset (buffer, 'x', sizeof (buffer));
EXPECT_STREQ ("1:203:405:607:809:a0b:c0d:ff00", inet_ntop (AF_INET6, address6, buffer, sizeof (buffer)));
memset (buffer, 'x', sizeof (buffer));
EXPECT_STREQ ("1:203:405:607:809:a0b:c0d:ff00", inet_ntop (AF_INET6, address6, buffer, 31));
memset (buffer, 'x', sizeof (buffer));
EXPECT_STREQ (nullptr, inet_ntop (AF_INET6, address6, buffer, 0));
memset (buffer, 'x', sizeof (buffer));
EXPECT_STREQ (nullptr, inet_ntop (AF_INET6, address6, buffer, 30));

memset (buffer, 'x', sizeof (buffer));
EXPECT_STREQ ("255.0.1.100", inet_ntop (AF_INET, address4, buffer, sizeof (buffer)));
memset (buffer, 'x', sizeof (buffer));
EXPECT_STREQ ("255.0.1.100", inet_ntop (AF_INET, address4, buffer, 12));
memset (buffer, 'x', sizeof (buffer));
EXPECT_STREQ (nullptr, inet_ntop (AF_INET, address4, buffer, 0));
memset (buffer, 'x', sizeof (buffer));
EXPECT_STREQ (nullptr, inet_ntop (AF_INET, address4, buffer, 11));
}

#endif


132 changes: 132 additions & 0 deletions lldb/gtest/unittest/Host/SocketTest.cpp
@@ -0,0 +1,132 @@
//===-- SocketTest.cpp ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include <thread>

#include "gtest/gtest.h"

#include "lldb/Host/Socket.h"

class SocketTest: public ::testing::Test
{
};

using namespace lldb_private;

void AcceptThread (Socket* listen_socket,
const char* listen_remote_address,
bool child_processes_inherit,
Socket** accept_socket,
Error* error)
{
*error = listen_socket->BlockingAccept (listen_remote_address, child_processes_inherit, *accept_socket);
}

void CreateConnectedSockets (std::unique_ptr<Socket>* a_up, std::unique_ptr<Socket>* b_up)
{
Predicate<uint16_t> port_predicate;
// Used when binding to port zero to wait for the thread
// that creates the socket, binds and listens to resolve
// the port number.

port_predicate.SetValue (0, eBroadcastNever);

bool child_processes_inherit = false;
Socket *socket = nullptr;
const char* listen_remote_address = "localhost:0";
Error error = Socket::TcpListen (listen_remote_address, child_processes_inherit, socket, &port_predicate);
std::unique_ptr<Socket> listen_socket_up (socket);
socket = nullptr;
EXPECT_FALSE (error.Fail ());
EXPECT_NE (nullptr, listen_socket_up.get ());
EXPECT_TRUE (listen_socket_up->IsValid ());

Error accept_error;
Socket* accept_socket;
std::thread accept_thread (AcceptThread,
listen_socket_up.get (),
listen_remote_address,
child_processes_inherit,
&accept_socket,
&accept_error);

char connect_remote_address[64];
snprintf (connect_remote_address, sizeof (connect_remote_address), "localhost:%u", port_predicate.GetValue ());
error = Socket::TcpConnect (connect_remote_address, child_processes_inherit, socket);
a_up->reset (socket);
socket = nullptr;
EXPECT_TRUE (error.Success ());
EXPECT_NE (nullptr, a_up->get ());
EXPECT_TRUE ((*a_up)->IsValid ());

accept_thread.join ();
b_up->reset (accept_socket);
EXPECT_TRUE (accept_error.Success ());
EXPECT_NE (nullptr, b_up->get ());
EXPECT_TRUE ((*b_up)->IsValid ());

listen_socket_up.reset ();
}

TEST_F (SocketTest, DecodeHostAndPort)
{
std::string host_str;
std::string port_str;
int32_t port;
Error error;
EXPECT_TRUE (Socket::DecodeHostAndPort ("localhost:1138", host_str, port_str, port, &error));
EXPECT_STREQ ("localhost", host_str.c_str ());
EXPECT_STREQ ("1138", port_str.c_str ());
EXPECT_EQ (1138, port);
EXPECT_TRUE (error.Success ());

EXPECT_FALSE (Socket::DecodeHostAndPort ("google.com:65536", host_str, port_str, port, &error));
EXPECT_TRUE (error.Fail ());
EXPECT_STREQ ("invalid host:port specification: 'google.com:65536'", error.AsCString ());

EXPECT_FALSE (Socket::DecodeHostAndPort ("google.com:-1138", host_str, port_str, port, &error));
EXPECT_TRUE (error.Fail ());
EXPECT_STREQ ("invalid host:port specification: 'google.com:-1138'", error.AsCString ());

EXPECT_TRUE (Socket::DecodeHostAndPort ("12345", host_str, port_str, port, &error));
EXPECT_STREQ ("", host_str.c_str ());
EXPECT_STREQ ("12345", port_str.c_str ());
EXPECT_EQ (12345, port);
EXPECT_TRUE (error.Success ());

EXPECT_TRUE (Socket::DecodeHostAndPort ("*:0", host_str, port_str, port, &error));
EXPECT_STREQ ("*", host_str.c_str ());
EXPECT_STREQ ("0", port_str.c_str ());
EXPECT_EQ (0, port);
EXPECT_TRUE (error.Success ());

}

TEST_F (SocketTest, Listen0ConnectAccept)
{
std::unique_ptr<Socket> socket_a_up;
std::unique_ptr<Socket> socket_b_up;
CreateConnectedSockets (&socket_a_up, &socket_b_up);
}

TEST_F (SocketTest, GetAddress)
{
std::unique_ptr<Socket> socket_a_up;
std::unique_ptr<Socket> socket_b_up;
CreateConnectedSockets (&socket_a_up, &socket_b_up);

EXPECT_EQ (socket_a_up->GetLocalPortNumber (), socket_b_up->GetRemotePortNumber ());
EXPECT_EQ (socket_b_up->GetLocalPortNumber (), socket_a_up->GetRemotePortNumber ());
EXPECT_NE (socket_a_up->GetLocalPortNumber (), socket_b_up->GetLocalPortNumber ());
EXPECT_STREQ ("127.0.0.1", socket_a_up->GetRemoteIPAddress ().c_str ());
EXPECT_STREQ ("127.0.0.1", socket_b_up->GetRemoteIPAddress ().c_str ());
}



64 changes: 64 additions & 0 deletions lldb/gtest/unittest/Host/SocketTestMock.cpp
@@ -0,0 +1,64 @@
//===-- SocketTestMock.cpp --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// This file provides a few necessary functions to link SocketTest.cpp
// Bringing in the real implementations results in a cascade of dependencies
// that pull in all of lldb.

#include "lldb/Core/Log.h"

#ifdef _WIN32
#include <windows.h>
#endif

using namespace lldb_private;

void
lldb_private::Log::Error (char const*, ...)
{
}

void
lldb_private::Log::Printf (char const*, ...)
{
}

Log*
lldb_private::GetLogIfAnyCategoriesSet (unsigned int)
{
return nullptr;
}

#include "lldb/Host/FileSystem.h"

#ifdef _WIN32

Error
FileSystem::Unlink(const char *path)
{
Error error;
BOOL result = ::DeleteFile(path);
if (!result)
error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
return error;
}

#else

Error
FileSystem::Unlink (const char *path)
{
Error error;
if (::unlink (path) == -1)
error.SetErrorToErrno ();
return error;
}

#endif

31 changes: 22 additions & 9 deletions lldb/include/lldb/Host/Socket.h
Expand Up @@ -70,30 +70,43 @@ class Socket : public IOObject
int GetOption (int level, int option_name, int &option_value);
int SetOption (int level, int option_name, int option_value);

static uint16_t GetPortNumber(const NativeSocket& socket);
uint16_t GetPortNumber () const;
// returns port number or 0 if error
static uint16_t GetLocalPortNumber (const NativeSocket& socket);

// returns port number or 0 if error
uint16_t GetLocalPortNumber () const;

// returns ip address string or empty string if error
std::string GetLocalIPAddress () const;

// must be connected
// returns port number or 0 if error
uint16_t GetRemotePortNumber () const;

// must be connected
// returns ip address string or empty string if error
std::string GetRemoteIPAddress () const;

NativeSocket GetNativeSocket () const { return m_socket; }
SocketProtocol GetSocketProtocol() const { return m_protocol; }
SocketProtocol GetSocketProtocol () const { return m_protocol; }

virtual Error Read (void *buf, size_t &num_bytes);
virtual Error Write (const void *buf, size_t &num_bytes);

virtual Error PreDisconnect();
virtual Error Close();
virtual Error PreDisconnect ();
virtual Error Close ();

virtual bool IsValid() const { return m_socket != kInvalidSocketValue; }
virtual WaitableHandle GetWaitableHandle();
virtual bool IsValid () const { return m_socket != kInvalidSocketValue; }
virtual WaitableHandle GetWaitableHandle ();

protected:
static bool
DecodeHostAndPort (llvm::StringRef host_and_port,
std::string &host_str,
std::string &port_str,
int32_t& port,
Error *error_ptr);


protected:
SocketProtocol m_protocol;
NativeSocket m_socket;
SocketAddress m_udp_send_sockaddr; // Send address used for UDP connections.
Expand Down

0 comments on commit 014bb7d

Please sign in to comment.