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