1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include <Ice/Ice.h>
6 #include <TestHelper.h>
7 #include <Test.h>
8 
9 using namespace std;
10 using namespace Ice;
11 using namespace Test;
12 
13 class PingReplyI : public PingReply, public IceUtil::Monitor<IceUtil::Mutex>
14 {
15 public:
16 
17     virtual void
reply(const Ice::Current &)18     reply(const Ice::Current&)
19     {
20         Lock sync(*this);
21         ++_replies;
22         notify();
23     }
24 
25     void
reset()26     reset()
27     {
28          _replies = 0;
29     }
30 
31     bool
waitReply(int expectedReplies,const IceUtil::Time & timeout)32     waitReply(int expectedReplies, const IceUtil::Time& timeout)
33     {
34         Lock sync(*this);
35         IceUtil::Time end = IceUtil::Time::now() + timeout;
36         while(_replies < expectedReplies)
37         {
38             IceUtil::Time delay = end - IceUtil::Time::now();
39             if(delay > IceUtil::Time::seconds(0))
40             {
41                 timedWait(delay);
42             }
43             else
44             {
45                 break;
46             }
47         }
48         return _replies == expectedReplies;
49     }
50 
51 private:
52 
53     int _replies;
54 };
55 ICE_DEFINE_PTR(PingReplyIPtr, PingReplyI);
56 
57 void
allTests(Test::TestHelper * helper)58 allTests(Test::TestHelper* helper)
59 {
60     Ice::CommunicatorPtr communicator = helper->communicator();
61     communicator->getProperties()->setProperty("ReplyAdapter.Endpoints", "udp");
62     Ice::ObjectAdapterPtr adapter = communicator->createObjectAdapter("ReplyAdapter");
63     PingReplyIPtr replyI = ICE_MAKE_SHARED(PingReplyI);
64     PingReplyPrxPtr reply = ICE_UNCHECKED_CAST(PingReplyPrx, adapter->addWithUUID(replyI))->ice_datagram();
65     adapter->activate();
66 
67     cout << "testing udp... " << flush;
68     ObjectPrxPtr base = communicator->stringToProxy("test -d:" + helper->getTestEndpoint("udp"));
69     TestIntfPrxPtr obj = ICE_UNCHECKED_CAST(TestIntfPrx, base);
70 
71     int nRetry = 5;
72     bool ret = false;
73     while(nRetry-- > 0)
74     {
75         replyI->reset();
76         obj->ping(reply);
77         obj->ping(reply);
78         obj->ping(reply);
79         ret = replyI->waitReply(3, IceUtil::Time::seconds(2));
80         if(ret)
81         {
82             break; // Success
83         }
84 
85         // If the 3 datagrams were not received within the 2 seconds, we try again to
86         // receive 3 new datagrams using a new object. We give up after 5 retries.
87         replyI = ICE_MAKE_SHARED(PingReplyI);
88         reply = ICE_UNCHECKED_CAST(PingReplyPrx, adapter->addWithUUID(replyI))->ice_datagram();
89     }
90     test(ret);
91 
92     if(communicator->getProperties()->getPropertyAsInt("Ice.Override.Compress") == 0)
93     {
94         //
95         // Only run this test if compression is disabled, the test expect fixed message size
96         // to be sent over the wire.
97         //
98 
99         Test::ByteSeq seq;
100         try
101         {
102             seq.resize(1024);
103             while(true)
104             {
105                 seq.resize(seq.size() * 2 + 10);
106                 replyI->reset();
107                 obj->sendByteSeq(seq, reply);
108                 replyI->waitReply(1, IceUtil::Time::seconds(10));
109             }
110         }
111         catch(const DatagramLimitException&)
112         {
113             test(seq.size() > 16384);
114         }
115         obj->ice_getConnection()->close(ICE_SCOPED_ENUM(ConnectionClose, GracefullyWithWait));
116         communicator->getProperties()->setProperty("Ice.UDP.SndSize", "64000");
117         seq.resize(50000);
118         try
119         {
120             replyI->reset();
121             obj->sendByteSeq(seq, reply);
122             test(!replyI->waitReply(1, IceUtil::Time::milliSeconds(500)));
123         }
124         catch(const Ice::LocalException& ex)
125         {
126             cerr << ex << endl;
127             test(false);
128         }
129     }
130 
131     cout << "ok" << endl;
132 
133     ostringstream endpoint;
134     if(communicator->getProperties()->getProperty("Ice.IPv6") == "1")
135     {
136         endpoint << "udp -h \"ff15::1:1\" -p " << helper->getTestPort(10);
137 #if defined(__APPLE__) || defined(_WIN32)
138         endpoint << " --interface \"::1\""; // Use loopback to prevent other machines to answer. the multicast requests.
139 #endif
140     }
141     else
142     {
143         endpoint << "udp -h 239.255.1.1 -p " << helper->getTestPort(10);
144 #if defined(__APPLE__) || defined(_WIN32)
145         endpoint << " --interface 127.0.0.1"; // Use loopback to prevent other machines to answer.
146 #endif
147     }
148     base = communicator->stringToProxy("test -d:" + endpoint.str());
149     TestIntfPrxPtr objMcast = ICE_UNCHECKED_CAST(TestIntfPrx, base);
150 #if (!defined(__APPLE__) || (defined(__APPLE__) && !TARGET_OS_IPHONE))
151     cout << "testing udp multicast... " << flush;
152 
153     nRetry = 5;
154     while(nRetry-- > 0)
155     {
156         replyI->reset();
157         objMcast->ping(reply);
158         ret = replyI->waitReply(5, IceUtil::Time::seconds(2));
159         if(ret)
160         {
161             break; // Success
162         }
163         replyI = ICE_MAKE_SHARED(PingReplyI);
164         reply = ICE_UNCHECKED_CAST(PingReplyPrx, adapter->addWithUUID(replyI))->ice_datagram();
165     }
166     if(!ret)
167     {
168         cout << "failed (is a firewall enabled?)" << endl;
169     }
170     else
171     {
172         cout << "ok" << endl;
173     }
174 #endif
175 
176     cout << "testing udp bi-dir connection... " << flush;
177     obj->ice_getConnection()->setAdapter(adapter);
178     objMcast->ice_getConnection()->setAdapter(adapter);
179     nRetry = 5;
180     while(nRetry-- > 0)
181     {
182         replyI->reset();
183         obj->pingBiDir(reply->ice_getIdentity());
184         obj->pingBiDir(reply->ice_getIdentity());
185         obj->pingBiDir(reply->ice_getIdentity());
186         ret = replyI->waitReply(3, IceUtil::Time::seconds(2));
187         if(ret)
188         {
189             break; // Success
190         }
191 
192         // If the 3 datagrams were not received within the 2 seconds, we try again to
193         // receive 3 new datagrams using a new object. We give up after 5 retries.
194         replyI = ICE_MAKE_SHARED(PingReplyI);
195         reply = ICE_UNCHECKED_CAST(PingReplyPrx, adapter->addWithUUID(replyI))->ice_datagram();
196     }
197     test(ret);
198     cout << "ok" << endl;
199 
200     //
201     // Sending the replies back on the multicast UDP connection doesn't work for most
202     // platform (it works for macOS Leopard but not Snow Leopard, doesn't work on SLES,
203     // Windows...). For Windows, see UdpTransceiver constructor for the details. So
204     // we don't run this test.
205     //
206 //     cout << "testing udp bi-dir connection... " << flush;
207 //     nRetry = 5;
208 //     while(nRetry-- > 0)
209 //     {
210 //         replyI->reset();
211 //         objMcast->pingBiDir(reply->ice_getIdentity());
212 //         ret = replyI->waitReply(5, IceUtil::Time::seconds(2));
213 //         if(ret)
214 //         {
215 //             break; // Success
216 //         }
217 //         replyI = new PingReplyI;
218 //         reply = PingReplyPrx::uncheckedCast(adapter->addWithUUID(replyI))->ice_datagram();
219 //     }
220 //     if(!ret)
221 //     {
222 //         cout << "failed (is a firewall enabled?)" << endl;
223 //     }
224 //     else
225 //     {
226 //         cout << "ok" << endl;
227 //     }
228 }
229