1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include <iostream>
8 #include <vector>
9
10 #include "mozilla/Atomics.h"
11 #include "runnable_utils.h"
12 #include "nss.h"
13 #include "pk11pub.h"
14
15 extern "C" {
16 #include "nr_api.h"
17 #include "nr_socket.h"
18 #include "transport_addr.h"
19 #include "ice_ctx.h"
20 #include "nr_socket_multi_tcp.h"
21 }
22
23 #include "nr_socket_prsock.h"
24
25 #include "stunserver.h"
26
27 #include "nricectxhandler.h"
28 #include "nricemediastream.h"
29
30 #define GTEST_HAS_RTTI 0
31 #include "gtest/gtest.h"
32 #include "gtest_utils.h"
33
34 using namespace mozilla;
35
36 namespace {
37
38 class MultiTcpSocketTest : public MtransportTest {
39 public:
MultiTcpSocketTest()40 MultiTcpSocketTest()
41 :MtransportTest(),
42 socks(3,nullptr),
43 readable(false),
44 ice_ctx_()
45 {}
46
SetUp()47 void SetUp() {
48 MtransportTest::SetUp();
49
50 ice_ctx_ = NrIceCtxHandler::Create("stun", true);
51
52 test_utils_->sts_target()->Dispatch(
53 WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET),
54 NS_DISPATCH_SYNC);
55 test_utils_->sts_target()->Dispatch(
56 WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET6),
57 NS_DISPATCH_SYNC);
58 }
59
60
TearDown()61 void TearDown() {
62 test_utils_->sts_target()->Dispatch(
63 WrapRunnable(
64 this, &MultiTcpSocketTest::Shutdown_s),
65 NS_DISPATCH_SYNC);
66
67 MtransportTest::TearDown();
68 }
69
70 DISALLOW_COPY_ASSIGN(MultiTcpSocketTest);
71
SockReadable(NR_SOCKET s,int how,void * arg)72 static void SockReadable(NR_SOCKET s, int how, void *arg) {
73 MultiTcpSocketTest *obj=static_cast<MultiTcpSocketTest *>(arg);
74 obj->SetReadable(true);
75 }
76
Shutdown_s()77 void Shutdown_s() {
78 ice_ctx_ = nullptr;
79 for (auto& sock : socks) {
80 nr_socket_destroy(&sock);
81 }
82 }
83
GetRandomPort()84 static uint16_t GetRandomPort() {
85 uint16_t result;
86 if (PK11_GenerateRandom((unsigned char*)&result, 2) != SECSuccess) {
87 MOZ_ASSERT(false);
88 return 0;
89 }
90 return result;
91 }
92
EnsureEphemeral(uint16_t port)93 static uint16_t EnsureEphemeral(uint16_t port) {
94 // IANA ephemeral port range (49152 to 65535)
95 return port | 49152;
96 }
97
Create_s(nr_socket_tcp_type tcp_type,std::string stun_server_addr,uint16_t stun_server_port,nr_socket ** sock)98 void Create_s(nr_socket_tcp_type tcp_type, std::string stun_server_addr,
99 uint16_t stun_server_port, nr_socket **sock) {
100 nr_transport_addr local;
101 // Get start of port range for test
102 static unsigned short port_s = GetRandomPort();
103 int r;
104
105 if (!stun_server_addr.empty()) {
106 std::vector<NrIceStunServer> stun_servers;
107 UniquePtr<NrIceStunServer> server(NrIceStunServer::Create(
108 stun_server_addr, stun_server_port, kNrIceTransportTcp));
109 stun_servers.push_back(*server);
110
111 ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->ctx()->SetStunServers(stun_servers)));
112 }
113
114 r = 1;
115 for (int tries=10; tries && r; --tries) {
116 r = nr_str_port_to_transport_addr(
117 (char *)"127.0.0.1", EnsureEphemeral(port_s++), IPPROTO_TCP, &local);
118 ASSERT_EQ(0, r);
119
120 r = nr_socket_multi_tcp_create(ice_ctx_->ctx()->ctx(),
121 &local, tcp_type, 1, 2048, sock);
122 }
123
124 ASSERT_EQ(0, r);
125 printf("Creating socket on %s\n", local.as_string);
126 r = nr_socket_multi_tcp_set_readable_cb(*sock,
127 &MultiTcpSocketTest::SockReadable, this);
128 ASSERT_EQ(0, r);
129 }
130
Create(nr_socket_tcp_type tcp_type,std::string stun_server_addr="",uint16_t stun_server_port=0)131 nr_socket *Create(nr_socket_tcp_type tcp_type,
132 std::string stun_server_addr = "",
133 uint16_t stun_server_port = 0) {
134 nr_socket *sock=nullptr;
135 test_utils_->sts_target()->Dispatch(
136 WrapRunnable(
137 this, &MultiTcpSocketTest::Create_s, tcp_type,
138 stun_server_addr, stun_server_port, &sock),
139 NS_DISPATCH_SYNC);
140 return sock;
141 }
142
Listen_s(nr_socket * sock)143 void Listen_s(nr_socket *sock) {
144 nr_transport_addr addr;
145 int r=nr_socket_getaddr(sock, &addr);
146 ASSERT_EQ(0, r);
147 printf("Listening on %s\n", addr.as_string);
148 r = nr_socket_listen(sock, 5);
149 ASSERT_EQ(0, r);
150 }
151
Listen(nr_socket * sock)152 void Listen(nr_socket *sock) {
153 test_utils_->sts_target()->Dispatch(
154 WrapRunnable(
155 this, &MultiTcpSocketTest::Listen_s, sock),
156 NS_DISPATCH_SYNC);
157 }
158
Destroy_s(nr_socket * sock)159 void Destroy_s(nr_socket *sock) {
160 int r = nr_socket_destroy(&sock);
161 ASSERT_EQ(0, r);
162 }
163
Destroy(nr_socket * sock)164 void Destroy(nr_socket *sock) {
165 test_utils_->sts_target()->Dispatch(
166 WrapRunnable(
167 this, &MultiTcpSocketTest::Destroy_s, sock),
168 NS_DISPATCH_SYNC);
169 }
170
Connect_s(nr_socket * from,nr_socket * to)171 void Connect_s(nr_socket *from, nr_socket *to) {
172 nr_transport_addr addr_to;
173 nr_transport_addr addr_from;
174 int r=nr_socket_getaddr(to, &addr_to);
175 ASSERT_EQ(0, r);
176 r=nr_socket_getaddr(from, &addr_from);
177 ASSERT_EQ(0, r);
178 printf("Connecting from %s to %s\n", addr_from.as_string, addr_to.as_string);
179 r=nr_socket_connect(from, &addr_to);
180 ASSERT_EQ(0, r);
181 }
182
Connect(nr_socket * from,nr_socket * to)183 void Connect(nr_socket *from, nr_socket *to) {
184 test_utils_->sts_target()->Dispatch(
185 WrapRunnable(
186 this, &MultiTcpSocketTest::Connect_s, from, to),
187 NS_DISPATCH_SYNC);
188 }
189
ConnectSo_s(nr_socket * so1,nr_socket * so2)190 void ConnectSo_s(nr_socket *so1, nr_socket *so2) {
191 nr_transport_addr addr_so1;
192 nr_transport_addr addr_so2;
193 int r=nr_socket_getaddr(so1, &addr_so1);
194 ASSERT_EQ(0, r);
195 r=nr_socket_getaddr(so2, &addr_so2);
196 ASSERT_EQ(0, r);
197 printf("Connecting SO %s <-> %s\n", addr_so1.as_string, addr_so2.as_string);
198 r=nr_socket_connect(so1, &addr_so2);
199 ASSERT_EQ(0, r);
200 r=nr_socket_connect(so2, &addr_so1);
201 ASSERT_EQ(0, r);
202 }
203
ConnectSo(nr_socket * from,nr_socket * to)204 void ConnectSo(nr_socket *from, nr_socket *to) {
205 test_utils_->sts_target()->Dispatch(
206 WrapRunnable(
207 this, &MultiTcpSocketTest::ConnectSo_s, from, to),
208 NS_DISPATCH_SYNC);
209 }
210
SendDataToAddress_s(nr_socket * from,nr_transport_addr * to,const char * data,size_t len)211 void SendDataToAddress_s(nr_socket *from, nr_transport_addr *to, const char *data,
212 size_t len) {
213 nr_transport_addr addr_from;
214
215 int r=nr_socket_getaddr(from, &addr_from);
216 ASSERT_EQ(0, r);
217 printf("Sending %lu bytes %s -> %s\n", (unsigned long)len,
218 addr_from.as_string, to->as_string);
219 r=nr_socket_sendto(from, data, len, 0, to);
220 ASSERT_EQ(0, r);
221 }
222
SendData(nr_socket * from,nr_transport_addr * to,const char * data,size_t len)223 void SendData(nr_socket *from, nr_transport_addr *to, const char *data, size_t len) {
224 test_utils_->sts_target()->Dispatch(
225 WrapRunnable(
226 this, &MultiTcpSocketTest::SendDataToAddress_s, from, to, data,
227 len),
228 NS_DISPATCH_SYNC);
229 }
230
SendDataToSocket_s(nr_socket * from,nr_socket * to,const char * data,size_t len)231 void SendDataToSocket_s(nr_socket *from, nr_socket *to, const char *data,
232 size_t len) {
233 nr_transport_addr addr_to;
234
235 int r=nr_socket_getaddr(to, &addr_to);
236 ASSERT_EQ(0, r);
237 SendDataToAddress_s(from, &addr_to, data, len);
238 }
239
SendData(nr_socket * from,nr_socket * to,const char * data,size_t len)240 void SendData(nr_socket *from, nr_socket *to, const char *data, size_t len) {
241 test_utils_->sts_target()->Dispatch(
242 WrapRunnable(
243 this, &MultiTcpSocketTest::SendDataToSocket_s, from, to, data,
244 len),
245 NS_DISPATCH_SYNC);
246 }
247
RecvDataFromAddress_s(nr_transport_addr * expected_from,nr_socket * sent_to,const char * expected_data,size_t expected_len)248 void RecvDataFromAddress_s(nr_transport_addr *expected_from,
249 nr_socket *sent_to,
250 const char *expected_data,
251 size_t expected_len) {
252 SetReadable(false);
253 size_t buflen = expected_len ? expected_len+1 : 100;
254 char received_data[buflen];
255 nr_transport_addr addr_to;
256 nr_transport_addr retaddr;
257 size_t retlen;
258
259 int r=nr_socket_getaddr(sent_to, &addr_to);
260 ASSERT_EQ(0, r);
261 printf("Receiving %lu bytes %s <- %s\n", (unsigned long)expected_len,
262 addr_to.as_string, expected_from->as_string);
263 r=nr_socket_recvfrom(sent_to, received_data, buflen,
264 &retlen, 0, &retaddr);
265 ASSERT_EQ(0, r);
266 r=nr_transport_addr_cmp(&retaddr, expected_from,
267 NR_TRANSPORT_ADDR_CMP_MODE_ALL);
268 ASSERT_EQ(0, r);
269 // expected_len == 0 means we just expected some data
270 if (expected_len == 0) {
271 ASSERT_GT(retlen, 0U);
272 } else {
273 ASSERT_EQ(expected_len, retlen);
274 r=memcmp(expected_data, received_data, retlen);
275 ASSERT_EQ(0, r);
276 }
277 }
278
RecvData(nr_transport_addr * expected_from,nr_socket * sent_to,const char * expected_data=nullptr,size_t expected_len=0)279 void RecvData(nr_transport_addr *expected_from, nr_socket *sent_to,
280 const char *expected_data = nullptr, size_t expected_len = 0) {
281 ASSERT_TRUE_WAIT(IsReadable(), 1000);
282 test_utils_->sts_target()->Dispatch(
283 WrapRunnable(
284 this, &MultiTcpSocketTest::RecvDataFromAddress_s,
285 expected_from, sent_to, expected_data,
286 expected_len),
287 NS_DISPATCH_SYNC);
288 }
289
RecvDataFromSocket_s(nr_socket * expected_from,nr_socket * sent_to,const char * expected_data,size_t expected_len)290 void RecvDataFromSocket_s(nr_socket *expected_from, nr_socket *sent_to,
291 const char *expected_data, size_t expected_len) {
292 nr_transport_addr addr_from;
293
294 int r=nr_socket_getaddr(expected_from, &addr_from);
295 ASSERT_EQ(0, r);
296
297 RecvDataFromAddress_s(&addr_from, sent_to, expected_data, expected_len);
298 }
299
RecvData(nr_socket * expected_from,nr_socket * sent_to,const char * expected_data,size_t expected_len)300 void RecvData(nr_socket *expected_from, nr_socket *sent_to,
301 const char *expected_data, size_t expected_len) {
302 ASSERT_TRUE_WAIT(IsReadable(), 1000);
303 test_utils_->sts_target()->Dispatch(
304 WrapRunnable(
305 this, &MultiTcpSocketTest::RecvDataFromSocket_s,
306 expected_from, sent_to, expected_data, expected_len),
307 NS_DISPATCH_SYNC);
308 }
309
RecvDataFailed_s(nr_socket * sent_to,size_t expected_len,int expected_err)310 void RecvDataFailed_s(nr_socket *sent_to, size_t expected_len, int expected_err) {
311 SetReadable(false);
312 char received_data[expected_len+1];
313 nr_transport_addr addr_to;
314 nr_transport_addr retaddr;
315 size_t retlen;
316
317 int r=nr_socket_getaddr(sent_to, &addr_to);
318 ASSERT_EQ(0, r);
319 r=nr_socket_recvfrom(sent_to, received_data, expected_len+1,
320 &retlen, 0, &retaddr);
321 ASSERT_EQ(expected_err, r) << "Expecting receive failure " << expected_err
322 << " on " << addr_to.as_string;
323 }
324
RecvDataFailed(nr_socket * sent_to,size_t expected_len,int expected_err)325 void RecvDataFailed(nr_socket *sent_to, size_t expected_len,
326 int expected_err) {
327 ASSERT_TRUE_WAIT(IsReadable(), 1000);
328 test_utils_->sts_target()->Dispatch(
329 WrapRunnable(
330 this, &MultiTcpSocketTest::RecvDataFailed_s, sent_to, expected_len,
331 expected_err),
332 NS_DISPATCH_SYNC);
333 }
334
TransferData(nr_socket * from,nr_socket * to,const char * data,size_t len)335 void TransferData(nr_socket *from, nr_socket *to, const char *data,
336 size_t len) {
337 SendData(from, to, data, len);
338 RecvData(from, to, data, len);
339 }
340
341 protected:
IsReadable() const342 bool IsReadable() const {
343 return readable;
344 }
SetReadable(bool r)345 void SetReadable(bool r) {
346 readable=r;
347 }
348 std::vector<nr_socket *> socks;
349 Atomic<bool> readable;
350 RefPtr<NrIceCtxHandler> ice_ctx_;
351 };
352 }
353
TEST_F(MultiTcpSocketTest,TestListen)354 TEST_F(MultiTcpSocketTest, TestListen) {
355 socks[0] = Create(TCP_TYPE_PASSIVE);
356 Listen(socks[0]);
357 }
358
TEST_F(MultiTcpSocketTest,TestConnect)359 TEST_F(MultiTcpSocketTest, TestConnect) {
360 socks[0] = Create(TCP_TYPE_PASSIVE);
361 socks[1] = Create(TCP_TYPE_ACTIVE);
362 socks[2] = Create(TCP_TYPE_ACTIVE);
363 Listen(socks[0]);
364 Connect(socks[1], socks[0]);
365 Connect(socks[2], socks[0]);
366 }
367
TEST_F(MultiTcpSocketTest,TestTransmit)368 TEST_F(MultiTcpSocketTest, TestTransmit) {
369 const char data[] = "TestTransmit";
370 socks[0] = Create(TCP_TYPE_ACTIVE);
371 socks[1] = Create(TCP_TYPE_PASSIVE);
372 Listen(socks[1]);
373 Connect(socks[0], socks[1]);
374
375 TransferData(socks[0], socks[1], data, sizeof(data));
376 TransferData(socks[1], socks[0], data, sizeof(data));
377 }
378
TEST_F(MultiTcpSocketTest,TestClosePassive)379 TEST_F(MultiTcpSocketTest, TestClosePassive) {
380 const char data[] = "TestClosePassive";
381 socks[0] = Create(TCP_TYPE_ACTIVE);
382 socks[1] = Create(TCP_TYPE_PASSIVE);
383 Listen(socks[1]);
384 Connect(socks[0], socks[1]);
385
386 TransferData(socks[0], socks[1], data, sizeof(data));
387 TransferData(socks[1], socks[0], data, sizeof(data));
388
389 /* We have to destroy as only that calls PR_Close() */
390 std::cerr << "Destructing socket" << std::endl;
391 Destroy(socks[1]);
392
393 RecvDataFailed(socks[0], sizeof(data), R_EOD);
394
395 socks[1] = nullptr;
396 }
397
TEST_F(MultiTcpSocketTest,TestCloseActive)398 TEST_F(MultiTcpSocketTest, TestCloseActive) {
399 const char data[] = "TestCloseActive";
400 socks[0] = Create(TCP_TYPE_ACTIVE);
401 socks[1] = Create(TCP_TYPE_PASSIVE);
402 Listen(socks[1]);
403 Connect(socks[0], socks[1]);
404
405 TransferData(socks[0], socks[1], data, sizeof(data));
406 TransferData(socks[1], socks[0], data, sizeof(data));
407
408 /* We have to destroy as only that calls PR_Close() */
409 std::cerr << "Destructing socket" << std::endl;
410 Destroy(socks[0]);
411
412 RecvDataFailed(socks[1], sizeof(data), R_EOD);
413
414 socks[0] = nullptr;
415 }
416
TEST_F(MultiTcpSocketTest,TestTwoSendsBeforeReceives)417 TEST_F(MultiTcpSocketTest, TestTwoSendsBeforeReceives) {
418 const char data1[] = "TestTwoSendsBeforeReceives";
419 const char data2[] = "2nd data";
420 socks[0] = Create(TCP_TYPE_ACTIVE);
421 socks[1] = Create(TCP_TYPE_PASSIVE);
422 Listen(socks[1]);
423 Connect(socks[0], socks[1]);
424
425 SendData(socks[0], socks[1], data1, sizeof(data1));
426 SendData(socks[0], socks[1], data2, sizeof(data2));
427 RecvData(socks[0], socks[1], data1, sizeof(data1));
428 /* ICE TCP framing turns TCP effectively into datagram mode */
429 RecvData(socks[0], socks[1], data2, sizeof(data2));
430 }
431
TEST_F(MultiTcpSocketTest,TestTwoActiveBidirectionalTransmit)432 TEST_F(MultiTcpSocketTest, TestTwoActiveBidirectionalTransmit) {
433 const char data1[] = "TestTwoActiveBidirectionalTransmit";
434 const char data2[] = "ReplyToTheFirstSocket";
435 const char data3[] = "TestMessageFromTheSecondSocket";
436 const char data4[] = "ThisIsAReplyToTheSecondSocket";
437 socks[0] = Create(TCP_TYPE_PASSIVE);
438 socks[1] = Create(TCP_TYPE_ACTIVE);
439 socks[2] = Create(TCP_TYPE_ACTIVE);
440 Listen(socks[0]);
441 Connect(socks[1], socks[0]);
442 Connect(socks[2], socks[0]);
443
444 TransferData(socks[1], socks[0], data1, sizeof(data1));
445 TransferData(socks[0], socks[1], data2, sizeof(data2));
446 TransferData(socks[2], socks[0], data3, sizeof(data3));
447 TransferData(socks[0], socks[2], data4, sizeof(data4));
448 }
449
TEST_F(MultiTcpSocketTest,TestTwoPassiveBidirectionalTransmit)450 TEST_F(MultiTcpSocketTest, TestTwoPassiveBidirectionalTransmit) {
451 const char data1[] = "TestTwoPassiveBidirectionalTransmit";
452 const char data2[] = "FirstReply";
453 const char data3[] = "TestTwoPassiveBidirectionalTransmitToTheSecondSock";
454 const char data4[] = "SecondReply";
455 socks[0] = Create(TCP_TYPE_PASSIVE);
456 socks[1] = Create(TCP_TYPE_PASSIVE);
457 socks[2] = Create(TCP_TYPE_ACTIVE);
458 Listen(socks[0]);
459 Listen(socks[1]);
460 Connect(socks[2], socks[0]);
461 Connect(socks[2], socks[1]);
462
463 TransferData(socks[2], socks[0], data1, sizeof(data1));
464 TransferData(socks[0], socks[2], data2, sizeof(data2));
465 TransferData(socks[2], socks[1], data3, sizeof(data3));
466 TransferData(socks[1], socks[2], data4, sizeof(data4));
467 }
468
TEST_F(MultiTcpSocketTest,TestActivePassiveWithStunServerMockup)469 TEST_F(MultiTcpSocketTest, TestActivePassiveWithStunServerMockup) {
470 /* Fake STUN message able to pass the nr_is_stun_msg check
471 used in nr_socket_buffered_stun */
472 const char stunMessage[] = {
473 '\x00', '\x01', '\x00', '\x04', '\x21', '\x12', '\xa4', '\x42',
474 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x0c', '\x00',
475 '\x00', '\x00', '\x00', '\x00', '\x1c', '\xed', '\xca', '\xfe'
476 };
477 const char data[] = "TestActivePassiveWithStunServerMockup";
478
479 nr_transport_addr stun_srv_addr;
480 std::string stun_addr;
481 uint16_t stun_port;
482 stun_addr = TestStunTcpServer::GetInstance(AF_INET)->addr();
483 stun_port = TestStunTcpServer::GetInstance(AF_INET)->port();
484 int r = nr_str_port_to_transport_addr(stun_addr.c_str(), stun_port, IPPROTO_TCP, &stun_srv_addr);
485 ASSERT_EQ(0, r);
486
487 socks[0] = Create(TCP_TYPE_PASSIVE, stun_addr, stun_port);
488 Listen(socks[0]);
489 socks[1] = Create(TCP_TYPE_ACTIVE, stun_addr, stun_port);
490
491 /* Send a fake STUN request and expect a STUN error response */
492 SendData(socks[0], &stun_srv_addr, stunMessage, sizeof(stunMessage));
493 RecvData(&stun_srv_addr, socks[0]);
494
495 Connect(socks[1], socks[0]);
496 TransferData(socks[1], socks[0], data, sizeof(data));
497 TransferData(socks[0], socks[1], data, sizeof(data));
498 }
499
TEST_F(MultiTcpSocketTest,TestConnectTwoSo)500 TEST_F(MultiTcpSocketTest, TestConnectTwoSo) {
501 socks[0] = Create(TCP_TYPE_SO);
502 socks[1] = Create(TCP_TYPE_SO);
503 ConnectSo(socks[0], socks[1]);
504 }
505
506 // test works on localhost only with delay applied:
507 // tc qdisc add dev lo root netem delay 5ms
TEST_F(MultiTcpSocketTest,DISABLED_TestTwoSoBidirectionalTransmit)508 TEST_F(MultiTcpSocketTest, DISABLED_TestTwoSoBidirectionalTransmit) {
509 const char data[] = "TestTwoSoBidirectionalTransmit";
510 socks[0] = Create(TCP_TYPE_SO);
511 socks[1] = Create(TCP_TYPE_SO);
512 ConnectSo(socks[0], socks[1]);
513 TransferData(socks[0], socks[1], data, sizeof(data));
514 TransferData(socks[1], socks[0], data, sizeof(data));
515 }
516
TEST_F(MultiTcpSocketTest,TestBigData)517 TEST_F(MultiTcpSocketTest, TestBigData) {
518 char buf1[2048];
519 char buf2[1024];
520
521 for(unsigned i=0; i<sizeof(buf1); ++i) {
522 buf1[i]=i&0xff;
523 }
524 for(unsigned i=0; i<sizeof(buf2); ++i) {
525 buf2[i]=(i+0x80)&0xff;
526 }
527 socks[0] = Create(TCP_TYPE_ACTIVE);
528 socks[1] = Create(TCP_TYPE_PASSIVE);
529 Listen(socks[1]);
530 Connect(socks[0], socks[1]);
531
532 TransferData(socks[0], socks[1], buf1, sizeof(buf1));
533 TransferData(socks[0], socks[1], buf2, sizeof(buf2));
534 // opposite dir
535 SendData(socks[1], socks[0], buf2, sizeof(buf2));
536 SendData(socks[1], socks[0], buf1, sizeof(buf1));
537 RecvData(socks[1], socks[0], buf2, sizeof(buf2));
538 RecvData(socks[1], socks[0], buf1, sizeof(buf1));
539 }
540