-
Notifications
You must be signed in to change notification settings - Fork 2
/
netsnoop_select.cc
321 lines (295 loc) · 11.2 KB
/
netsnoop_select.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#include <iostream>
#include <functional>
#include <thread>
#include <mutex>
#include <memory>
#include <condition_variable>
#include <cmath>
#include "netsnoop.h"
#include "net_snoop_client.h"
#include "net_snoop_server.h"
void StartClient();
void StartServer();
auto g_option = std::make_shared<Option>();
int main(int argc, char *argv[])
{
if (argc < 2)
{
std::clog << "usage: \n"
" netsnoop_select -s 0.0.0.0 4000 -vvv\n";
return 0;
}
Logger::SetGlobalLogLevel(LLERROR);
SockInit init;
strncpy(g_option->ip_remote, "127.0.0.1", sizeof(g_option->ip_remote) - 1);
strncpy(g_option->ip_local, "0.0.0.0", sizeof(g_option->ip_local) - 1);
strncpy(g_option->ip_multicast, "239.3.3.3", sizeof(g_option->ip_multicast) - 1);
g_option->port = 4000;
if (argc > 2)
{
strncpy(g_option->ip_remote, argv[2], sizeof(g_option->ip_remote) - 1);
strncpy(g_option->ip_local, argv[2], sizeof(g_option->ip_local) - 1);
}
if (argc > 3)
{
g_option->port = atoi(argv[3]);
}
if (argc > 4)
{
Logger::SetGlobalLogLevel(LogLevel(LLERROR - strlen(argv[4]) + 1));
}
if (argc > 1)
{
if (!strcmp(argv[1], "-s"))
{
StartServer();
}
if (!strcmp(argv[1], "-c"))
{
StartClient();
}
}
return 0;
}
void StartServer()
{
static int count = 0;
auto server = std::make_shared<NetSnoopServer>(g_option);
server->OnPeerConnected = [&](const Peer *peer) {
count++;
std::cout << "peer connect(" << count << "): " << peer->GetCookie() << std::endl;
};
server->OnPeerDisconnected = [&](const Peer *peer) {
count--;
std::cout << "peer disconnect(" << count << "): " << peer->GetCookie() << std::endl;
};
server->OnPeerStopped = [&](const Peer *peer, std::shared_ptr<NetStat> netstat) {
std::cout << "peer stoped: (" << peer->GetCookie() << ") " << peer->GetCommand()->GetCmd().c_str()
<< " || " << (netstat ? netstat->ToString() : "NULL") << std::endl;
};
auto server_thread = std::thread([server]() {
LOGVP("server running...");
server->Run();
});
server_thread.detach();
auto notify_thread = std::thread([] {
LOGVP("notify running...");
Udp multicast;
multicast.Initialize();
multicast.BindMulticastInterface(g_option->ip_local);
multicast.Connect("239.3.3.4", 4001);
while (true)
{
multicast.Send(g_option->ip_local, strlen(g_option->ip_local));
sleep(3);
}
});
notify_thread.detach();
std::cout << "After all clients connected, press any key to start..." << std::endl;
getchar();
std::cout << "Let's go..." << std::endl;
std::mutex mtx;
std::condition_variable cv;
// ping first
{
auto command = CommandFactory::New("ping count 20 wait 2000");
command->RegisterCallback([&](const Command *oldcommand, std::shared_ptr<NetStat> stat) {
std::cout << "command finish: " << oldcommand->GetCmd() << " || " << (stat ? stat->ToString() : "NULL") << std::endl;
cv.notify_all();
});
server->PushCommand(command);
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock);
}
std::shared_ptr<NetStat> maxstat;
std::shared_ptr<NetStat> avgstat;
std::string maxcommand;
int CMD_COUNT = 0;
int MAX_TIMES = 3;
int times = 0;
begin:
maxstat = NULL;
std::vector<std::string> cmds = {
"send unicast true speed 50 time 10000 size 1472 timeout 300 wait 2000",
"send unicast true speed 100 time 10000 size 1472 timeout 300 wait 2000",
"send unicast true speed 500 time 10000 size 1472 timeout 300 wait 5000",
"send unicast true speed 1000 time 10000 size 1472 timeout 300 wait 5000",
"send unicast true speed 2000 time 10000 size 1472 timeout 300 wait 5000",
"send unicast true count 5000 interval 0 size 1472 timeout 300 wait 5000",
"send multicast true speed 50 time 10000 size 1472 timeout 300 wait 2000",
"send multicast true speed 100 time 10000 size 1472 timeout 300 wait 2000",
"send multicast true speed 500 time 10000 size 1472 timeout 300 wait 5000",
"send multicast true speed 1000 time 10000 size 1472 timeout 300 wait 5000",
"send multicast true speed 2000 time 10000 size 1472 timeout 300 wait 5000",
"send multicast true count 100000 interval 0 size 1472 timeout 300 wait 5000",
};
CMD_COUNT = cmds.size();
for (auto i = 0; i < CMD_COUNT; i++)
{
times = 0;
avgstat = NULL;
if (i == CMD_COUNT / 2)
{
maxstat = NULL;
}
for (auto k = 0; k < MAX_TIMES; k++)
{
auto command = CommandFactory::New(cmds[i]);
command->RegisterCallback([&, i, k](const Command *oldcommand, std::shared_ptr<NetStat> stat) {
std::cout << "command value: " << oldcommand->ToString() << std::endl;
std::cout << "command finish: " << oldcommand->GetCmd() << " || " << (stat ? stat->ToString() : "NULL") << std::endl;
std::cout << "progress: " << i * MAX_TIMES + k + 1 << "/" << CMD_COUNT * MAX_TIMES << std::endl;
if (stat)
{
if (!avgstat)
{
avgstat = stat;
}
else
{
*avgstat += *stat;
}
}
times++;
if (times >= MAX_TIMES)
{
if (avgstat)
{
*avgstat /= MAX_TIMES;
if (!maxstat)
{
maxstat = avgstat;
maxcommand = oldcommand->GetCmd();
}
else if (maxstat->recv_speed < avgstat->recv_speed)
{
maxstat = avgstat;
maxcommand = oldcommand->GetCmd();
}
std::cout << "avg recv_speed: " << oldcommand->GetCmd() << " || " << (avgstat ? avgstat->ToString() : "NULL") << std::endl;
std::cout << "max recv_speed: " << maxcommand << " || " << (maxstat ? maxstat->ToString() : "NULL") << std::endl;
}
std::cout << "----------------------------" << std::endl;
}
cv.notify_all();
});
server->PushCommand(command);
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock);
}
}
// ping last
{
auto command = CommandFactory::New("ping count 20 wait 2000");
command->RegisterCallback([&](const Command *oldcommand, std::shared_ptr<NetStat> stat) {
std::cout << "command finish: " << oldcommand->GetCmd() << " || " << (stat ? stat->ToString() : "NULL") << std::endl;
cv.notify_all();
});
server->PushCommand(command);
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock);
}
std::cout << "finished." << std::endl;
}
void StartClient()
{
int result;
std::vector<std::string> ips{g_option->ip_remote};
std::vector<int> ip_try_times{0};
const int MAX_TRY_TIMES = 20;
int scale = 4;
while (true)
{
//for (auto it = ips.rbegin();it!=ips.rend();it++)
for (int i = ips.size() - 1; i >= 0; i--)
{
auto ip = ips[i];
if (ip_try_times[i] >= MAX_TRY_TIMES)
{
LOGD << "block ip: " << ip;
continue;
}
ip_try_times[i]++;
memset(g_option->ip_remote, 0, sizeof(g_option->ip_remote));
strncpy(g_option->ip_remote, ip.c_str(), sizeof(g_option->ip_remote) - 1);
NetSnoopClient client(g_option);
client.OnConnected = [&,i] {
std::clog << "connect to " << g_option->ip_remote << ":" << g_option->port << " (" << g_option->ip_multicast << ")" << std::endl;
scale = 0;
ip_try_times[i] = 0;
};
client.OnStopped = [](std::shared_ptr<Command> oldcommand, std::shared_ptr<NetStat> stat) {
std::cout << "peer finish: " << oldcommand->GetCmd() << " || " << (stat ? stat->ToString() : "NULL") << std::endl;
};
LOGD << "try connect to " << ip << " (" << ip_try_times[i] << ")";
client.Run();
LOGD << "client stop, restarting...";
LOGD << "----------------------------";
}
{
sockaddr_in server_addr;
Udp multicast;
result = multicast.Initialize();
result = multicast.Bind("0.0.0.0", 4001);
// the IGMP package will send from default route.
result = multicast.JoinMUlticastGroup("239.3.3.4");
if (result < 0)
{
LOGE << "join multicast group 239.3.3.4("
<< "0.0.0.0"
<< ") error, retry in 3 seconds..." << std::endl;
//TODO: fix this,in chromeos,it's too quick to start before if up.
sleep(3);
continue;
}
// this way will case obscure problem, when the system is not conneted to any network while has local ip.
// auto ips = multicast.GetLocalIps();
// for (auto &&ip : ips)
// {
// result = multicast.JoinMUlticastGroup("239.3.3.4",ip);
// if(result<0)
// {
// std::clog << "join multicast group 239.3.3.4("<<ip<<") error, retry in 3 seconds..." << std::endl;
// continue;
// }
// }
std::string server_ip(40, 0);
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(multicast.GetFd(), &readfds);
int wait_seconds = std::pow(2, scale);
timeval timeout{wait_seconds};
if (scale < 10)
scale++;
LOGD << "finding server...(timeout=" << wait_seconds << ")";
result = select(multicast.GetFd() + 1, &readfds, NULL, NULL, &timeout);
if (result < 0)
{
PSOCKETERROR("select error");
continue;
}
if (result == 0)
{
LOGDP("select timeout.");
continue;
}
result = multicast.RecvFrom(server_ip, &server_addr);
if (result <= 0)
continue;
server_ip.resize(result);
if (server_ip == "0.0.0.0")
{
server_ip = inet_ntoa(server_addr.sin_addr);
}
if (!std::any_of(ips.begin(), ips.end(), [&](std::string ip) { return ip == server_ip; }))
{
ips.push_back(server_ip);
LOGD << "find new server: " << server_ip << std::endl;
}
else
{
LOGD << "find old server: " << server_ip << std::endl;
}
}
}
}