Skip to content

Commit ef7a9c9

Browse files
committed
Implement new functions.
And do a major refactoring already.
1 parent 3021fa9 commit ef7a9c9

16 files changed

+397
-109
lines changed

mock-network.files

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,5 @@ src/mock_network/functions.cc
5151
src/mock_network/functions.h
5252
src/mock_network/socket.h
5353
src/mock_network/socket.cc
54-
src/mock_network/connect.h
55-
src/mock_network/connect.cc
54+
src/mock_network/connection.h
55+
src/mock_network/connection.cc

src/base/aliases.h

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ using Mutex = std::mutex;
2626
template <class T>
2727
using Set = std::set<T>;
2828

29+
template <class T>
30+
using SharedPtr = std::shared_ptr<T>;
31+
2932
using UniqueLock = std::unique_lock<Mutex>;
3033

3134
template <class U, class V>

src/mock_network/BUILD.gn

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
shared_library("mock_network") {
22
sources = [
3-
"connect.cc",
4-
"connect.h",
3+
"connection.cc",
4+
"connection.h",
55
"functions.cc",
66
"functions.h",
77
"mock.cc",
@@ -11,7 +11,7 @@ shared_library("mock_network") {
1111
]
1212

1313
public = [
14-
"connect.h",
14+
"connection.h",
1515
"mock.h",
1616
]
1717

src/mock_network/connect.cc

-16
This file was deleted.

src/mock_network/connect.h

-10
This file was deleted.

src/mock_network/connection.cc

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <mock_network/connection.h>
2+
3+
namespace mock_network {
4+
5+
// static
6+
void Connection::SetDuration(std::chrono::seconds duration) {
7+
duration_ = duration;
8+
}
9+
10+
// static
11+
void Connection::SetResult(int error_code) {
12+
result_ = error_code;
13+
}
14+
15+
// static
16+
std::chrono::seconds Connection::duration_(0);
17+
18+
// static
19+
int Connection::result_ = 0;
20+
21+
} // namespace mock_network

src/mock_network/connection.h

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma once
2+
3+
#include <mock_network/functions.h>
4+
5+
#include <chrono>
6+
7+
namespace mock_network {
8+
9+
class Connection {
10+
public:
11+
static void SetDuration(std::chrono::seconds duration);
12+
static void SetResult(int error_code);
13+
14+
private:
15+
friend int fake::connect(int sockfd, const struct sockaddr* addr,
16+
socklen_t addrlen);
17+
18+
static std::chrono::seconds duration_;
19+
static int result_;
20+
};
21+
22+
} // namespace mock_network

src/mock_network/functions.cc

+56-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include <mock_network/functions.h>
22

3+
#include <mock_network/connection.h>
4+
#include <mock_network/mock.h>
35
#include <mock_network/socket.h>
46

57
#include <thread>
@@ -8,20 +10,37 @@
810
#include <unistd.h>
911

1012
namespace mock_network {
13+
namespace fake {
1114

12-
extern std::chrono::seconds connection_duration;
13-
extern int connection_result;
14-
extern Map<String, void*> originals;
15+
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen) {
16+
// TODO: implement this.
17+
return -1;
18+
}
1519

16-
namespace fake {
20+
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen) {
21+
Socket socket = Socket::Get(sockfd);
22+
if (!socket.IsValid()) {
23+
// We can't detect, if the |sockfd| is a valid descriptor at a system level,
24+
// so we always indicate that it's just not a socket.
25+
errno = ENOTSOCK;
26+
return -1;
27+
}
28+
29+
if (!socket.SetState(Socket::BIND, addr, addrlen)) {
30+
// Assume |errno| is already set by |Socket::SetState()|.
31+
return -1;
32+
}
33+
34+
return 0;
35+
}
1736

1837
int close(int fd) {
1938
Socket socket = Socket::Get(fd);
2039
if (socket.IsValid()) {
2140
return socket.Close();
2241
}
2342

24-
return reinterpret_cast<int (*)(int)>(originals["close"])(fd);
43+
return Mock::CallOriginal<int>("close", fd);
2544
}
2645

2746
int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen) {
@@ -33,32 +52,52 @@ int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen) {
3352
return -1;
3453
}
3554

36-
if (!socket.SetState(Socket::CONNECTING)) {
37-
if (socket.GetState() == Socket::CONNECTING) {
38-
errno = EALREADY;
39-
} else if (socket.GetState() >= Socket::CONNECTED) {
40-
errno = EISCONN;
41-
}
42-
55+
if (!socket.SetState(Socket::CONNECTING, addr, addrlen)) {
56+
// Assume |errno| is already set by |Socket::SetState()|.
4357
return -1;
4458
}
4559

4660
if (!socket.IsNonBlocking()) {
47-
std::this_thread::sleep_for(connection_duration);
48-
// TODO: handle peer address.
49-
socket.SetState(Socket::CONNECTED);
61+
std::this_thread::sleep_for(Connection::duration_);
62+
if (!socket.SetState(Socket::CONNECTED)) {
63+
errno = EINVAL;
64+
return -1;
65+
}
5066
} else {
5167
// TODO: implement non-blocking connection, keeping in mind, that |select()|
5268
// or |epoll()| should somehow indicate this fact using pipes.
5369
// TODO: return EINPROGRESS, if the |connection_duration| is non-zero.
5470
}
5571

56-
if (connection_result == 0) {
72+
if (Connection::result_ == 0) {
5773
return 0;
5874
} else {
59-
errno = connection_result;
75+
errno = Connection::result_;
76+
return -1;
77+
}
78+
}
79+
80+
int listen(int sockfd, int backlog) {
81+
Socket socket = Socket::Get(sockfd);
82+
if (!socket.IsValid()) {
83+
// We can't detect, if the |sockfd| is a valid descriptor at a system level,
84+
// so we always indicate that it's just not a socket.
85+
errno = ENOTSOCK;
86+
return -1;
87+
}
88+
89+
if (!socket.SetState(Socket::PASSIVE)) {
90+
// Assume |errno| is already set by |Socket::SetState()|.
6091
return -1;
6192
}
93+
94+
return 0;
95+
}
96+
97+
int setsockopt(int sockfd, int level, int optname, const void* optval,
98+
socklen_t optlen) {
99+
// TODO: implement this.
100+
return 0;
62101
}
63102

64103
int socket(int domain, int type, int protocol) {

src/mock_network/functions.h

+5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@
55
namespace mock_network {
66
namespace fake {
77

8+
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
9+
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
810
int close(int fd);
911
int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
12+
int listen(int sockfd, int backlog);
13+
int setsockopt(int sockfd, int level, int optname, const void* optval,
14+
socklen_t optlen);
1015
int socket(int domain, int type, int protocol);
1116

1217
} // namespace fake

src/mock_network/mock.cc

+74-23
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010

1111
namespace mock_network {
1212

13-
// Used in the fake |close()|.
14-
Map<String, void*> originals;
15-
1613
namespace {
1714

1815
struct link_map_unloader {
@@ -45,34 +42,34 @@ LinkList GetLoadedModules() {
4542
return std::move(modules);
4643
}
4744

48-
Atomic<bool> enabled = {false};
49-
50-
#define REPLACE(func) \
51-
originals.emplace(#func, \
52-
elf_hook(handle->l_name, base, #func, \
53-
reinterpret_cast<const void*>(fake::func)))
54-
5545
const char* blacklist[] = {
56-
"ld-linux-x86-64\\.so", "libc\\.so", "libpthread\\.so",
46+
// Old libstdc++ doesn't support substring regex matching.
47+
".*ld-linux-x86-64\\.so.*", ".*libc\\.so.*", ".*libpthread\\.so.*",
5748
};
5849

50+
Map<String, void*> handles;
51+
5952
} // namespace
6053

61-
bool Enable(String* error) {
62-
bool expected = false;
63-
if (!enabled.compare_exchange_strong(expected, true)) {
54+
// static
55+
bool Mock::Enable(String* error) {
56+
UniqueLock lock(mutex_);
57+
58+
if (enabled_) {
6459
if (error) {
6560
error->assign("Mocking is already enabled");
6661
}
6762
return false;
6863
}
6964

65+
enabled_ = true;
66+
7067
LinkList modules = GetLoadedModules();
7168

72-
for (auto& handle : modules) {
69+
for (const auto& handle : modules) {
7370
bool in_blacklist = false;
7471
for (const auto* entry : blacklist) {
75-
if (std::regex_search(handle->l_name, std::regex(entry))) {
72+
if (std::regex_match(handle->l_name, std::regex(entry))) {
7673
in_blacklist = true;
7774
break;
7875
}
@@ -93,25 +90,79 @@ bool Enable(String* error) {
9390
return false;
9491
}
9592

96-
REPLACE(close);
97-
REPLACE(connect);
98-
REPLACE(socket);
93+
#define MOCK(func) \
94+
{ \
95+
void* original = elf_hook(handle->l_name, base, #func, \
96+
reinterpret_cast<const void*>(fake::func)); \
97+
if (original) { \
98+
originals_.emplace(#func, original); \
99+
} \
100+
}
101+
102+
MOCK(accept);
103+
MOCK(bind);
104+
MOCK(close);
105+
MOCK(connect);
106+
MOCK(listen);
107+
MOCK(setsockopt);
108+
MOCK(socket);
109+
110+
#undef MOCK
111+
112+
handles.emplace(handle->l_name, base);
99113
}
100114

101115
return true;
102116
}
103117

104-
bool Disable(String* error) {
105-
bool expected = true;
106-
if (!enabled.compare_exchange_strong(expected, false)) {
118+
// static
119+
bool Mock::Disable(String* error) {
120+
UniqueLock lock(mutex_);
121+
122+
if (!enabled_) {
107123
if (error) {
108124
error->assign("Mocking is not enabled");
109125
}
110126
return false;
111127
}
112128

113-
// TODO: implement this.
129+
for (const auto& handle : handles) {
130+
#define RESTORE(func) \
131+
{ \
132+
auto original = originals_.find(#func); \
133+
if (original != originals_.end()) { \
134+
elf_hook(handle.first.c_str(), handle.second, #func, original->second); \
135+
} \
136+
}
137+
138+
RESTORE(accept);
139+
RESTORE(bind);
140+
RESTORE(close);
141+
RESTORE(connect);
142+
RESTORE(listen);
143+
RESTORE(setsockopt);
144+
RESTORE(socket);
145+
146+
#undef RESTORE
147+
}
148+
149+
originals_.clear();
150+
handles.clear();
151+
152+
// NOTE: |elf_hook()| uses the |close()| internally, so we need to be able to
153+
// call the |CallOriginal()|, which asserts the |enabled_|.
154+
enabled_ = false;
155+
114156
return true;
115157
}
116158

159+
// static
160+
Mutex Mock::mutex_;
161+
162+
// static
163+
bool Mock::enabled_ = false;
164+
165+
// static
166+
Map<String, void*> Mock::originals_;
167+
117168
} // namespace mock_network

0 commit comments

Comments
 (0)